Module

environment.loaders

Template loaders for Kida environment.

Loaders provide template source to the Environment. They implement get_source(name) returning (source, filename).

Built-in Loaders:

  • FileSystemLoader: Load from filesystem directories
  • DictLoader: Load from in-memory dictionary (testing/embedded)
  • ChoiceLoader: Try multiple loaders in order (theme fallback)
  • PrefixLoader: Namespace templates by prefix (plugin architectures)
  • PackageLoader: Load from installed Python packages (importlib.resources)
  • FunctionLoader: Wrap a callable as a loader (quick one-offs)

Custom Loaders:

Implement the Loader protocol:

```python
class DatabaseLoader:
    def get_source(self, name: str) -> tuple[str, str | None]:
        row = db.query("SELECT source FROM templates WHERE name = ?", name)
        if not row:
            raise TemplateNotFoundError(f"Template '{name}' not found")
        return row.source, f"db://{name}"

    def list_templates(self) -> list[str]:
        return [r.name for r in db.query("SELECT name FROM templates")]
```

Thread-Safety: Loaders should be thread-safe for concurrentget_source()calls. Built-in loaders are safe for concurrent reads when their configured sources remain stable. Do not mutate aDictLoader/PrefixLoadermapping or loader list while it is shared.ChoiceLoader and PrefixLoaderinherit their child loaders' guarantees, andFunctionLoaderinherits its callable's guarantee. Filesystem/package updates are outside the loader synchronization contract.

Classes

FileSystemLoader 5 ▼
Load templates from filesystem directories. Searches one or more directories for templates by name…

Load templates from filesystem directories.

Searches one or more directories for templates by name. The first matching file is returned. Supports arbitrary directory structures and file nesting.

Methods: get_source(name): Return (source, filename) for template list_templates(): Return sorted list of all template names

Search Order: Directories are searched in order. First match wins: python loader = FileSystemLoader(["themes/custom/", "themes/default/"]) # Looks in themes/custom/ first, then themes/default/

Attributes

Name Type Description
_paths —

List of Path objects to search

_encoding —

File encoding (default: utf-8)

Methods

get_source 1 tuple[str, str] ▼
Load template source from filesystem.
def get_source(self, name: str) -> tuple[str, str]
Parameters
Name Type Description
name —
Returns
tuple[str, str]
list_templates 0 list[str] ▼
Recursively list supported templates as sorted relative POSIX paths. Includes …
def list_templates(self) -> list[str]

Recursively list supported templates as sorted relative POSIX paths.

Includes .html, .xml, and .kida files, deduplicated across search paths.

Returns
list[str]
Internal Methods 1 ▼
__init__ 2 ▼
def __init__(self, paths: str | Path | list[str | Path], encoding: str = 'utf-8')
Parameters
Name Type Description
paths —
encoding — Default:'utf-8'
DictLoader 4 ▼
Load templates from an in-memory dictionary. Maps template names to source strings. Useful for tes…

Load templates from an in-memory dictionary.

Maps template names to source strings. Useful for testing, embedded templates, or dynamically generated templates.

Methods: get_source(name): Return (source, None) for template list_templates(): Return sorted list of template names

Testing:

>>> loader = DictLoader({"test.html": "{{ x * 2 }}"})
    >>> env = Environment(loader=loader)
    >>> assert env.render("test.html", x=21) == "42"

Attributes

Name Type Description
_mapping —

Dict mapping template name → source string

Methods

get_source 1 tuple[str, None] ▼
def get_source(self, name: str) -> tuple[str, None]
Parameters
Name Type Description
name —
Returns
tuple[str, None]
list_templates 0 list[str] ▼
def list_templates(self) -> list[str]
Returns
list[str]
Internal Methods 1 ▼
__init__ 1 ▼
def __init__(self, mapping: dict[str, str])
Parameters
Name Type Description
mapping —
ChoiceLoader 3 ▼
Try multiple loaders in order, returning the first match. Useful for theme fallback patterns where…

Try multiple loaders in order, returning the first match.

Useful for theme fallback patterns where a custom theme overrides a subset of templates and the default theme provides the rest.

Search Order: Loaders are tried in order. First successfulget_source()wins: python loader = ChoiceLoader([ FileSystemLoader("themes/custom/"), FileSystemLoader("themes/default/"), ]) # Looks in custom/ first, then default/

Methods

get_source 1 tuple[str, str | None] ▼
Try each loader in order, return first match.
def get_source(self, name: str) -> tuple[str, str | None]
Parameters
Name Type Description
name —
Returns
tuple[str, str | None]
list_templates 0 list[str] ▼
Merge template lists from all loaders (deduplicated, sorted).
def list_templates(self) -> list[str]
Returns
list[str]
Internal Methods 1 ▼
__init__ 1 ▼
def __init__(self, loaders: list[FileSystemLoader | DictLoader | ChoiceLoader | PrefixLoader | PackageLoader | FunctionLoader])
Parameters
Name Type Description
loaders —
PrefixLoader 3 ▼
Namespace templates by prefix, delegating to per-prefix loaders. Template names are split on a del…

Namespace templates by prefix, delegating to per-prefix loaders.

Template names are split on a delimiter (default/) and the first segment is used to select the appropriate loader. This enables plugin and theme architectures where different template sources are isolated by namespace.

Methods

get_source 1 tuple[str, str | None] ▼
Split name on delimiter, look up prefix, delegate to loader.
def get_source(self, name: str) -> tuple[str, str | None]
Parameters
Name Type Description
name —
Returns
tuple[str, str | None]
list_templates 0 list[str] ▼
List all templates across all prefixes, with prefix prepended.
def list_templates(self) -> list[str]
Returns
list[str]
Internal Methods 1 ▼
__init__ 2 ▼
def __init__(self, mapping: dict[str, FileSystemLoader | DictLoader | ChoiceLoader | PrefixLoader | PackageLoader | FunctionLoader], delimiter: str = '/')
Parameters
Name Type Description
mapping —
delimiter — Default:'/'
PackageLoader 5 ▼
Load templates from an installed Python package. Uses ``importlib.resources`` to locate template f…

Load templates from an installed Python package.

Usesimportlib.resourcesto locate template files inside a package's directory tree. This enables pip-installable packages to ship templates that are loadable without knowing the installation path.

Use Cases:

  • Framework default templates (admin panels, error pages)
  • Distributable themes (pip install my-theme)
  • Plugin/extension templates namespaced by package

Methods

get_source 1 tuple[str, str | None] ▼
Load template source from package resources.
def get_source(self, name: str) -> tuple[str, str | None]
Parameters
Name Type Description
name —
Returns
tuple[str, str | None]
list_templates 0 list[str] ▼
List all templates in the package directory.
def list_templates(self) -> list[str]
Returns
list[str]
Internal Methods 3 ▼
__init__ 3 ▼
def __init__(self, package_name: str, package_path: str = 'templates', encoding: str = 'utf-8')
Parameters
Name Type Description
package_name —
package_path — Default:'templates'
encoding — Default:'utf-8'
_get_root 0 importlib.resources.abc.… ▼
Get the traversable root for the template directory.
def _get_root(self) -> importlib.resources.abc.Traversable
Returns
importlib.resources.abc.Traversable
_walk 2 list[str] ▼
Recursively walk a traversable, collecting file paths.
def _walk(self, traversable: importlib.resources.abc.Traversable, prefix: str) -> list[str]
Parameters
Name Type Description
traversable —
prefix —
Returns
list[str]
FunctionLoader 3 ▼
Wrap a callable as a template loader. The simplest way to create a custom loader. Pass a function …

Wrap a callable as a template loader.

The simplest way to create a custom loader. Pass a function that takes a template name and returns the source (orNoneif not found).

The function can return either:

  • str: Template source (filename will be "<function>").
  • tuple[str, str | None]: (source, filename)for custom
    filenames in error messages.
    
  • None: Template not found (raises TemplateNotFoundError).

Use with tuple return for better error messages:

>>> def load(name):
    ...     source = my_cms.get_template(name)
    ...     if source:
    ...         return source, f"cms://{name}"
    ...     return None
    >>> env = Environment(loader=FunctionLoader(load))

Methods

get_source 1 tuple[str, str | None] ▼
Call the load function and normalize the result.
def get_source(self, name: str) -> tuple[str, str | None]
Parameters
Name Type Description
name —
Returns
tuple[str, str | None]
list_templates 0 list[str] ▼
FunctionLoader cannot enumerate templates.
def list_templates(self) -> list[str]
Returns
list[str]
Internal Methods 1 ▼
__init__ 1 ▼
def __init__(self, load_func: Callable[[str], str | tuple[str, str | None] | None])
Parameters
Name Type Description
load_func —