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