diff options
Diffstat (limited to 'venv/lib/python3.11/site-packages/litestar/contrib/mako.py')
-rw-r--r-- | venv/lib/python3.11/site-packages/litestar/contrib/mako.py | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/venv/lib/python3.11/site-packages/litestar/contrib/mako.py b/venv/lib/python3.11/site-packages/litestar/contrib/mako.py new file mode 100644 index 0000000..9cb4c47 --- /dev/null +++ b/venv/lib/python3.11/site-packages/litestar/contrib/mako.py @@ -0,0 +1,146 @@ +from __future__ import annotations + +from functools import partial +from typing import TYPE_CHECKING, Any, Mapping, TypeVar + +from typing_extensions import ParamSpec + +from litestar.exceptions import ImproperlyConfiguredException, MissingDependencyException, TemplateNotFoundException +from litestar.template.base import ( + TemplateCallableType, + TemplateEngineProtocol, + TemplateProtocol, + csrf_token, + url_for, + url_for_static_asset, +) + +try: + from mako.exceptions import TemplateLookupException as MakoTemplateNotFound # type: ignore[import-untyped] + from mako.lookup import TemplateLookup # type: ignore[import-untyped] + from mako.template import Template as _MakoTemplate # type: ignore[import-untyped] +except ImportError as e: + raise MissingDependencyException("mako") from e + +if TYPE_CHECKING: + from pathlib import Path + +__all__ = ("MakoTemplate", "MakoTemplateEngine") + +P = ParamSpec("P") +T = TypeVar("T") + + +class MakoTemplate(TemplateProtocol): + """Mako template, implementing ``TemplateProtocol``""" + + def __init__(self, template: _MakoTemplate, template_callables: list[tuple[str, TemplateCallableType]]) -> None: + """Initialize a template. + + Args: + template: Base ``MakoTemplate`` used by the underlying mako-engine + template_callables: List of callables passed to the template + """ + super().__init__() + self.template = template + self.template_callables = template_callables + + def render(self, *args: Any, **kwargs: Any) -> str: + """Render a template. + + Args: + args: Positional arguments passed to the engines ``render`` function + kwargs: Keyword arguments passed to the engines ``render`` function + + Returns: + Rendered template as a string + """ + for callable_key, template_callable in self.template_callables: + kwargs_copy = {**kwargs} + kwargs[callable_key] = partial(template_callable, kwargs_copy) + + return str(self.template.render(*args, **kwargs)) + + +class MakoTemplateEngine(TemplateEngineProtocol[MakoTemplate, Mapping[str, Any]]): + """Mako-based TemplateEngine.""" + + def __init__(self, directory: Path | list[Path] | None = None, engine_instance: Any | None = None) -> None: + """Initialize template engine. + + Args: + directory: Direct path or list of directory paths from which to serve templates. + engine_instance: A mako TemplateLookup instance. + """ + super().__init__(directory, engine_instance) + if directory and engine_instance: + raise ImproperlyConfiguredException("You must provide either a directory or a mako TemplateLookup.") + if directory: + self.engine = TemplateLookup( + directories=directory if isinstance(directory, (list, tuple)) else [directory], default_filters=["h"] + ) + elif engine_instance: + self.engine = engine_instance + + self._template_callables: list[tuple[str, TemplateCallableType]] = [] + self.register_template_callable(key="url_for_static_asset", template_callable=url_for_static_asset) + self.register_template_callable(key="csrf_token", template_callable=csrf_token) + self.register_template_callable(key="url_for", template_callable=url_for) + + def get_template(self, template_name: str) -> MakoTemplate: + """Retrieve a template by matching its name (dotted path) with files in the directory or directories provided. + + Args: + template_name: A dotted path + + Returns: + MakoTemplate instance + + Raises: + TemplateNotFoundException: if no template is found. + """ + try: + return MakoTemplate( + template=self.engine.get_template(template_name), template_callables=self._template_callables + ) + except MakoTemplateNotFound as exc: + raise TemplateNotFoundException(template_name=template_name) from exc + + def register_template_callable( + self, key: str, template_callable: TemplateCallableType[Mapping[str, Any], P, T] + ) -> None: + """Register a callable on the template engine. + + Args: + key: The callable key, i.e. the value to use inside the template to call the callable. + template_callable: A callable to register. + + Returns: + None + """ + self._template_callables.append((key, template_callable)) + + def render_string(self, template_string: str, context: Mapping[str, Any]) -> str: # pyright: ignore + """Render a template from a string with the given context. + + Args: + template_string: The template string to render. + context: A dictionary of variables to pass to the template. + + Returns: + The rendered template as a string. + """ + template = _MakoTemplate(template_string) # noqa: S702 + return template.render(**context) # type: ignore[no-any-return] + + @classmethod + def from_template_lookup(cls, template_lookup: TemplateLookup) -> MakoTemplateEngine: + """Create a template engine from an existing mako TemplateLookup instance. + + Args: + template_lookup: A mako TemplateLookup instance. + + Returns: + MakoTemplateEngine instance + """ + return cls(directory=None, engine_instance=template_lookup) |