# core

URL: /kida/api/environment/core/
Section: environment
Description: Core Environment class for Kida template system.

The Environment is the central hub for template configuration, compilation,
and caching. It manages loaders, filters, tests, and global variables.

Thread-Safety:
- Immutable configuration after construction
- Copy-on-write for filters/tests/globals (no locking)
- LRU caches use RLock; _template_hashes, _analysis_cache, _structure_manifest_cache
  are protected by _cache_lock for concurrent get_template/get_template_structure
- Safe for concurrent get_template(), render(), and get_template_structure() calls

Example:
    >>> from kida import Environment, FileSystemLoader
    >>> env = Environment(
    ...     loader=FileSystemLoader("templates/"),
    ...     autoescape=True,
    ... )
    >>> env.get_template("page.html").render(page=page)

---

> For a complete page index, fetch /kida/llms.txt.

Open LLM text
(/kida/api/environment/core/index.txt)

Share with AI

Ask Claude
(https://claude.ai/new?q=Please%20help%20me%20understand%20this%20documentation%3A%20%2Fkida%2Fapi%2Fenvironment%2Fcore%2Findex.txt)

Ask ChatGPT
(https://chatgpt.com/?q=Please%20help%20me%20understand%20this%20documentation%3A%20%2Fkida%2Fapi%2Fenvironment%2Fcore%2Findex.txt)

Ask Gemini
(https://gemini.google.com/app?q=Please%20help%20me%20understand%20this%20documentation%3A%20%2Fkida%2Fapi%2Fenvironment%2Fcore%2Findex.txt)

Ask Copilot
(https://copilot.microsoft.com/?q=Please%20help%20me%20understand%20this%20documentation%3A%20%2Fkida%2Fapi%2Fenvironment%2Fcore%2Findex.txt)

Module

#
`environment.core`

Core Environment class for Kida template system.

The Environment is the central hub for template configuration, compilation,
and caching. It manages loaders, filters, tests, and global variables.

Thread-Safety:

- Immutable configuration after construction

- Copy-on-write for filters/tests/globals (no locking)

- LRU caches use RLock; _template_hashes, _analysis_cache, _structure_manifest_cache
are protected by _cache_lock for concurrent get_template/get_template_structure

- Safe for concurrent get_template(), render(), and get_template_structure() calls

Example:

```
>>> from kida import Environment, FileSystemLoader
>>> env = Environment(
...     loader=FileSystemLoader("templates/"),
...     autoescape=True,
... )
>>> env.get_template("page.html").render(page=page)
```

1Class7Functions

## Classes

`Environment`

84

▼

Central configuration and template management hub.

The Environment holds all template engine setti…

Central configuration and template management hub.

The Environment holds all template engine settings and provides the primary
API for loading and rendering templates. It manages three key concerns:

- Template Loading: Via configurable loaders (filesystem, dict, etc.)

- Compilation Settings: Autoescape, strict undefined handling

- Runtime Context: Filters, tests, and global variables

Strict Mode:
Undefined variables raise`UndefinedError`instead of returning empty
string. Catches typos and missing context variables at render time.

```
    >>> env = Environment()
    >>> env.from_string("{{ typo_var }}").render()
UndefinedError: Undefined variable 'typo_var' in <template>:1

    >>> env.from_string("{{ optional | default('N/A') }}").render()
    'N/A'
```

Caching:

Three cache layers for optimal performance:

-

Bytecode cache (disk): Persistent compiled bytecode via marshal.

```
Auto-enabled for FileSystemLoader in `__pycache__/kida/`.
```

```
Current cold-start gain is modest (~7-8% median in
```

```
`benchmarks/benchmark_cold_start.py`); most startup time is import
```

```
cost, so lazy imports or pre-compilation are required for larger
```

```
improvements.
```

-

Template cache (memory): Compiled Template objects (keyed by name)

-

Fragment cache (memory):`{% cache key %}`block outputs

>> env.cache_info()

```
{'template': {'size': 5, 'max_size': 400, 'hits': 100, 'misses': 5},
     'fragment': {'size': 12, 'max_size': 1000, 'hits': 50, 'misses': 12},
     'bytecode': {'file_count': 10, 'total_bytes': 45000}}
```

#### Attributes

Name
Type
Description

`loader`

`Loader | None`

Template source provider (FileSystemLoader, DictLoader, etc.)

`autoescape`

`bool | str | Callable[[str | None], bool]`

HTML auto-escaping. True, False, callable(name) → bool, or a string: "terminal" (enable, ANSI-aware mode), "true" (enable), or "false" (disable). Any other string raises ValueError.

`auto_reload`

`bool`

Check template modification times (default: True)

`strict_none`

`bool`

Fail early on None comparisons during sorting (default: False)

`strict_undefined`

`bool`

—

`jinja2_compat_warnings`

`bool`

—

`preserve_ast`

`bool`

—

`cache_size`

`int`

Maximum compiled templates to cache (default: 400)

`fragment_cache_size`

`int`

Maximum`{% cache %}`fragment entries (default: 1000)

`fragment_ttl`

`float`

Fragment cache TTL in seconds (default: 300.0)

`bytecode_cache`

`BytecodeCache | bool | None`

Persistent bytecode cache configuration: - None (default): Auto-enabled for FileSystemLoader - False: Explicitly disabled - BytecodeCache instance: Custom cache directory

`template_aliases`

`dict[str, str] | None`

—

`static_context`

`dict[str, Any] | None`

—

`_bytecode_cache`

`BytecodeCache | None`

—

`block_start`

`str`

—

`block_end`

`str`

—

`variable_start`

`str`

—

`variable_end`

`str`

—

`comment_start`

`str`

—

`comment_end`

`str`

—

`trim_blocks`

`bool`

—

`lstrip_blocks`

`bool`

—

`max_extends_depth`

`int`

—

`max_include_depth`

`int`

—

`validate_calls`

`bool`

—

`enable_profiling`

`bool`

—

`enable_capture`

`bool`

—

`fstring_coalescing`

`bool`

—

`pure_filters`

`set[str]`

—

`inline_components`

`bool`

—

`optimize_translations`

`bool`

—

`enable_htmx_helpers`

`bool`

—

`extensions`

`list[type]`

—

`terminal_color`

`str | None`

—

`terminal_width`

`int | None`

—

`terminal_unicode`

`bool | None`

—

`ambiguous_width`

`int | None`

—

`globals`

`dict[str, Any]`

Variables available in all templates (includes Python builtins) Thread-Safety: All operations are safe for concurrent use: - Configuration is immutable after`__post_init__` - `add_filter()`, `add_test()`, `add_global()` use copy-on-write - `get_template()` uses lock-free LRU cache with atomic operations - `render()`uses only local state (StringBuilder pattern)

`_filters`

`dict[str, Callable[..., Any]]`

—

`_tests`

`dict[str, Callable[..., bool]]`

—

`_cache`

`LRUCache[str, Template]`

—

`_fragment_cache`

`LRUCache[str, str]`

—

`_template_hashes`

`dict[str, str]`

—

`_template_mtimes`

`dict[str, int]`

—

`_analysis_cache`

`dict[str, TemplateMetadata]`

—

`_structure_manifest_cache`

`dict[str, TemplateStructureManifest]`

—

`_cache_lock`

`threading.RLock`

—

`_terminal_caps`

`TerminalCaps | None`

—

`_extension_instances`

`list[Any]`

—

`_extension_tags`

`dict[str, Any]`

—

`_extension_compilers`

`dict[str, Any]`

—

`_extension_end_keywords`

`frozenset[str]`

—

`_filtered_globals`

`dict[str, Any] | None`

—

`_filtered_globals_source`

`dict[str, Any] | None`

—

#### Methods

`filters`

0

`FilterRegistry`

▼

Get filters as dict-like registry.

property

`def filters(self) -> FilterRegistry`

##### Returns

`FilterRegistry`

`tests`

0

`FilterRegistry`

▼

Get tests as dict-like registry.

property

`def tests(self) -> FilterRegistry`

##### Returns

`FilterRegistry`

`install_translations`

1

▼

Install a gettext translations object.

The object must have gettext() and nget…

`def install_translations(self, translations: Any) -> None`

Install a gettext translations object.

The object must have gettext() and ngettext() methods
(standard library gettext.GNUTranslations interface).

##### Parameters

Name
Type
Description

`translations`
`—`

`install_gettext_callables`

2

▼

Install gettext/ngettext functions directly.

These are registered as template …

`def install_gettext_callables(self, gettext: Any, ngettext: Any) -> None`

Install gettext/ngettext functions directly.

These are registered as template globals`_` and `_n`, and
stored as`_gettext`/`_ngettext`for compiler namespace access.

##### Parameters

Name
Type
Description

`gettext`
`—`

`ngettext`
`—`

`add_filter`

2

▼

Add a filter (copy-on-write).

`def add_filter(self, name: str, func: Callable[..., Any]) -> None`

##### Parameters

Name
Type
Description

`name`
`—`

Filter name (used in templates as {{ x | name }})

`func`
`—`

Filter function If func was decorated with :func:`kida.pure`, the filter is automatically registered as pure, enabling compile-time evaluation when all inputs are statically known.

`add_test`

2

▼

Add a test (copy-on-write).

`def add_test(self, name: str, func: Callable[..., Any]) -> None`

##### Parameters

Name
Type
Description

`name`
`—`

Test name (used in templates as {% if x is name %})

`func`
`—`

Test function returning bool

`add_global`

2

▼

Add a global variable (copy-on-write).

`def add_global(self, name: str, value: Any) -> None`

##### Parameters

Name
Type
Description

`name`
`—`

Global name (used in templates as {{ name }})

`value`
`—`

Any value (variable, function, etc.)

`get_filtered_globals`

0

`dict[str, Any]`

▼

Return globals dict with UNDEFINED values removed (cached).

The result is cach…

`def get_filtered_globals(self) -> dict[str, Any]`

Return globals dict with UNDEFINED values removed (cached).

The result is cached, but the cache is automatically refreshed if
the public`globals`mapping has been mutated or replaced since the
last computation.

##### Returns

`dict[str, Any]`

`update_filters`

1

▼

Add multiple filters at once (copy-on-write).

`def update_filters(self, filters: dict[str, Callable[..., Any]]) -> None`

##### Parameters

Name
Type
Description

`filters`
`—`

Dict mapping filter names to functions

`update_tests`

1

▼

Add multiple tests at once (copy-on-write).

`def update_tests(self, tests: dict[str, Callable[..., Any]]) -> None`

##### Parameters

Name
Type
Description

`tests`
`—`

Dict mapping test names to functions

`get_template`

2

`Template`

▼

Load and cache a template by name.

`def get_template(self, name: str, *, caller: str | None = None) -> Template`

##### Parameters

Name
Type
Description

`name`
`—`

Template identifier (e.g.,`"index.html"`). May start with `./` or `../` for resolution relative to the calling template — see `caller`.

`caller`
`—`

Logical name of the template issuing the request. Required when`name` is a relative path. Supplied automatically by `{% include %}`, `{% extends %}`, `{% embed %}`, and `{% from ... import ... %}`at render time.

Default:`None`

##### Returns

`Template`

Compiled Template object

`from_string`

3

`Template`

▼

Compile a template from a string.

`def from_string(self, source: str, name: str | None = None, *, static_context: dict[str, Any] | None = None) -> Template`

##### Parameters

Name
Type
Description

`source`
`—`

Template source code

`name`
`—`

Template name for error messages and bytecode caching. When a`bytecode_cache`is configured, providing a name enables persistent caching of the compiled template. Without a name, the template is compiled fresh each time.

Default:`None`

`static_context`
`—`

Values known at compile time. Expressions that depend only on these values are evaluated during compilation and replaced with constants in the bytecode. This enables near-`str.format()`speed for static regions.

Default:`None`

##### Returns

`Template`

Compiled Template object

`clear_template_cache`

1

▼

Clear template cache (optional, for external invalidation).

Useful when an ext…

`def clear_template_cache(self, names: list[str] | None = None) -> None`

Clear template cache (optional, for external invalidation).

Useful when an external system (e.g., Bengal) detects template changes
and wants to force cache invalidation without waiting for hash check.

##### Parameters

Name
Type
Description

`names`
`—`

Specific template names to clear, or None to clear all

Default:`None`

`get_template_structure`

1

`TemplateStructureManifes…`

▼

Return lightweight manifest with extends/blocks/dependencies.

`def get_template_structure(self, name: str) -> TemplateStructureManifest | None`

##### Parameters

Name
Type
Description

`name`
`—`

##### Returns

`TemplateStructureManifest | None`

`render`

3

`str`

▼

Render a template by name with context.

Convenience method combining get_templ…

`def render(self, template_name: str, *args: Any, **kwargs: Any) -> str`

Render a template by name with context.

Convenience method combining get_template() and render().

##### Parameters

Name
Type
Description

`template_name`
`—`

Template identifier (e.g., "index.html") *args: Single dict of context variables (optional) **kwargs: Context variables as keyword arguments

`*args`
`—`

`**kwargs`
`—`

##### Returns

`str`

Rendered template as string

`render_string`

3

`str`

▼

Compile and render a template string.

Convenience method combining from_string…

`def render_string(self, source: str, *args: Any, **kwargs: Any) -> str`

Compile and render a template string.

Convenience method combining from_string() and render().

##### Parameters

Name
Type
Description

`source`
`—`

Template source code *args: Single dict of context variables (optional) **kwargs: Context variables as keyword arguments

`*args`
`—`

`**kwargs`
`—`

##### Returns

`str`

Rendered template as string

`filter`

1

`Callable[[Callable[..., …`

▼

Decorator to register a filter function.

`def filter(self, name: str | None = None) -> Callable[[Callable[..., Any]], Callable[..., Any]]`

##### Parameters

Name
Type
Description

`name`
`—`

Filter name (defaults to function name)

Default:`None`

##### Returns

`Callable[[Callable[..., Any]], Callable[..., Any]]`

Decorator function

`test`

1

`Callable[[Callable[..., …`

▼

Decorator to register a test function.

`def test(self, name: str | None = None) -> Callable[[Callable[..., Any]], Callable[..., Any]]`

##### Parameters

Name
Type
Description

`name`
`—`

Test name (defaults to function name)

Default:`None`

##### Returns

`Callable[[Callable[..., Any]], Callable[..., Any]]`

Decorator function

`select_autoescape`

1

`bool`

▼

Determine if autoescape should be enabled for a template.

For ``.kida`` files …

`def select_autoescape(self, name: str | None) -> bool`

Determine if autoescape should be enabled for a template.

For`.kida`files the inner extension drives the decision: e.g.
`page.html.kida` → `.html` → escape, `README.md.kida` → `.md`
→ no escape. A bare`.kida`file (no inner extension) is treated as
plain text (no escaping).

##### Parameters

Name
Type
Description

`name`
`—`

Template name (may be None for string templates)

##### Returns

`bool`

True if autoescape should be enabled

`clear_cache`

1

▼

Clear all cached templates and fragments.

Call this to release memory when tem…

`def clear_cache(self, include_bytecode: bool = False) -> None`

Clear all cached templates and fragments.

Call this to release memory when templates are no longer needed,
or when template files have been modified and need reloading.

##### Parameters

Name
Type
Description

`include_bytecode`
`—`

Also clear persistent bytecode cache (default: False)

Default:`False`

`clear_fragment_cache`

0

▼

Clear only the fragment cache (keep template cache).

`def clear_fragment_cache(self) -> None`

`clear_bytecode_cache`

0

`int`

▼

Clear persistent bytecode cache.

`def clear_bytecode_cache(self) -> int`

##### Returns

`int`

Number of cache files removed.

`cache_info`

0

`dict[str, Any]`

▼

Return cache statistics.

Returns cache statistics for template and fragment ca…

`def cache_info(self) -> dict[str, Any]`

Return cache statistics.

Returns cache statistics for template and fragment caches.

##### Returns

`dict[str, Any]`

Dict with cache statistics including hit/miss rates.

Internal Methods
7

▼

`__post_init__`

0

▼

Initialize derived configuration.

`def __post_init__(self) -> None`

`_init_extensions`

0

▼

Initialize registered extensions.

`def _init_extensions(self) -> None`

`_collect_imported_def_metadata`

2

`dict[str, Any]`

▼

Return visible imported component definitions for static validation.

Only lite…

`def _collect_imported_def_metadata(self, ast: TemplateNode, current_name: str | None) -> dict[str, Any]`

Return visible imported component definitions for static validation.

Only literal`{% from "template" import name [as alias] %}`imports
are resolved. Dynamic imports and templates that fail to load are
skipped so validation remains conservative.

##### Parameters

Name
Type
Description

`ast`
`—`

`current_name`
`—`

##### Returns

`dict[str, Any]`

`_resolve_bytecode_cache`

0

`BytecodeCache | None`

▼

Resolve bytecode cache from configuration.

Auto-detection logic:
- If byte…

`def _resolve_bytecode_cache(self) -> BytecodeCache | None`

Resolve bytecode cache from configuration.

Auto-detection logic:

- If bytecode_cache is False: disabled

- If bytecode_cache is BytecodeCache: use it

- If bytecode_cache is None and loader is FileSystemLoader:

```
auto-create cache in first search path's __pycache__/kida/
```

##### Returns

`BytecodeCache | None`

Resolved BytecodeCache or None if disabled/unavailable.

`_resolve_alias`

1

`str`

▼

Substitute ``@alias/path`` with the configured alias root.

Raises TemplateNotF…

`def _resolve_alias(self, name: str) -> str`

Substitute`@alias/path`with the configured alias root.

Raises TemplateNotFoundError when the alias is unknown or when no
aliases are configured on this Environment.

##### Parameters

Name
Type
Description

`name`
`—`

##### Returns

`str`

`_compile`

4

`Template`

▼

Compile template source to Template object.

Uses bytecode cache when configure…

`def _compile(self, source: str, name: str | None, filename: str | None, *, static_context: dict[str, Any] | None = None) -> Template`

Compile template source to Template object.

Uses bytecode cache when configured for fast cold-start.
Preserves AST for introspection when self.preserve_ast=True (default).

When`static_context`is provided, runs a partial evaluation pass
before compilation to replace static expressions with constants.

##### Parameters

Name
Type
Description

`source`
`—`

`name`
`—`

`filename`
`—`

`static_context`
`—`

Default:`None`

##### Returns

`Template`

`_is_template_stale`

1

`bool`

▼

Check if a cached template is stale (source changed).

Uses a two-tier check: m…

`def _is_template_stale(self, name: str) -> bool`

Check if a cached template is stale (source changed).

Uses a two-tier check: mtime first (cheap stat call), then hash
comparison only if mtime changed. This avoids reading and hashing
the entire source on every get_template() call when auto_reload=True.

##### Parameters

Name
Type
Description

`name`
`—`

Template identifier

##### Returns

`bool`

True if template source changed, False if unchanged

## Functions

`_identity_gettext`

1

`str`

▼

Default gettext: return message unchanged.

`def _identity_gettext(message: str) -> str`

##### Parameters

Name
Type
Description

`message`
`str`

##### Returns

`str`

`_identity_ngettext`

3

`str`

▼

Default ngettext: select form by count.

`def _identity_ngettext(singular: str, plural: str, n: int) -> str`

##### Parameters

Name
Type
Description

`singular`
`str`

`plural`
`str`

`n`
`int`

##### Returns

`str`

`_consume_global`

2

`Any`

▼

Template global: read a value from the nearest {% provide %} ancestor.

`def _consume_global(key: str, default: Any = None) -> Any`

##### Parameters

Name
Type
Description

`key`
`str`

`default`
`Any`

Default:`None`

##### Returns

`Any`

`_format_call_validation_parts`

1

`list[str]`

▼

Format the individual problems in a component call validation result.

`def _format_call_validation_parts(issue: Any) -> list[str]`

##### Parameters

Name
Type
Description

`issue`
`Any`

##### Returns

`list[str]`

`_component_call_warning`

2

`Any`

▼

Build a structured warning for a component call validation issue.

`def _component_call_warning(issue: Any, template_name: str | None) -> Any`

##### Parameters

Name
Type
Description

`issue`
`Any`

`template_name`
`str | None`

##### Returns

`Any`

`_iter_nodes`

1

`Any`

▼

Yield AST nodes depth-first without depending on a visitor class.

`def _iter_nodes(root: Any) -> Any`

##### Parameters

Name
Type
Description

`root`
`Any`

##### Returns

`Any`

`_hash_static_context`

1

`str | None`

▼

Hash static context deterministically for bytecode cache keys.

`def _hash_static_context(static_context: dict[str, Any] | None) -> str | None`

##### Parameters

Name
Type
Description

`static_context`
`dict[str, Any] | None`

##### Returns

`str | None`
