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. All built-in loaders are safe (FileSystemLoader reads files atomically, DictLoader uses immutable dict lookup, ChoiceLoader and PrefixLoader delegate to their child loaders, PackageLoader reads via importlib, FunctionLoader delegates to the user-provided callable).

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]
List all templates in search paths.
def list_templates(self) -> list[str]
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