1from __future__ import annotations
2
3from collections.abc import Callable
4from typing import Any
5
6from plain.packages import packages_registry
7from plain.runtime import settings
8from plain.utils.functional import LazyObject
9from plain.utils.module_loading import import_string
10
11from .environments import DefaultEnvironment, get_template_dirs
12
13
14class JinjaEnvironment(LazyObject):
15 def _setup(self) -> None:
16 environment_setting = settings.TEMPLATES_JINJA_ENVIRONMENT
17
18 if isinstance(environment_setting, str):
19 env = import_string(environment_setting)()
20 else:
21 env = environment_setting()
22
23 # We have to set _wrapped before we trigger the autoloading of "register" commands
24 self._wrapped = env
25
26 # Autoload template helpers using the registry method
27 packages_registry.autodiscover_modules("templates", include_app=True)
28
29
30environment = JinjaEnvironment()
31
32
33def register_template_extension(extension_class: type) -> type:
34 environment.add_extension(extension_class)
35 return extension_class
36
37
38def register_template_global(value: Any, name: str | None = None) -> Any:
39 """
40 Adds a global to the Jinja environment.
41
42 Can be used as a decorator on a function:
43
44 @register_template_global
45 def my_global():
46 return "Hello, world!"
47
48 Or as a function:
49
50 register_template_global("Hello, world!", name="my_global")
51 """
52 if callable(value):
53 environment.globals[name or value.__name__] = value
54 elif name:
55 environment.globals[name] = value
56 else:
57 raise ValueError("name must be provided if value is not callable")
58
59 return value
60
61
62def register_template_filter(
63 func: Callable[..., Any], name: str | None = None
64) -> Callable[..., Any]:
65 """Adds a filter to the Jinja environment."""
66 filter_name = name if name is not None else func.__name__ # type: ignore[attr-defined]
67 environment.filters[filter_name] = func
68 return func
69
70
71__all__ = [
72 "environment",
73 "DefaultEnvironment",
74 "get_template_dirs",
75 "register_template_extension",
76 "register_template_filter",
77 "register_template_global",
78]