Plain is headed towards 1.0! Subscribe for development updates →

 1from importlib import import_module
 2
 3from plain.packages import packages_registry
 4from plain.runtime import settings
 5from plain.utils.functional import LazyObject
 6from plain.utils.module_loading import import_string
 7
 8from .environments import DefaultEnvironment, get_template_dirs
 9
10
11class JinjaEnvironment(LazyObject):
12    def __init__(self, *args, **kwargs):
13        self.__dict__["_imported_modules"] = set()
14        super().__init__(*args, **kwargs)
15
16    def _setup(self):
17        environment_setting = settings.TEMPLATES_JINJA_ENVIRONMENT
18
19        if isinstance(environment_setting, str):
20            env = import_string(environment_setting)()
21        else:
22            env = environment_setting()
23
24        # We have to set _wrapped before we trigger the autoloading of "register" commands
25        self._wrapped = env
26
27        for package_config in packages_registry.get_package_configs():
28            # Allow this to fail in case there are import errors inside of their file
29            import_name = f"{package_config.name}.templates"
30            if import_name in self._imported_modules:
31                continue
32            try:
33                import_module(import_name)
34                self._imported_modules.add(import_name)
35            except ModuleNotFoundError:
36                pass
37
38        # Allow this to fail in case there are import errors inside of their file
39        import_name = "app.templates"
40        if import_name not in self._imported_modules:
41            try:
42                import_module(import_name)
43                self._imported_modules.add(import_name)
44            except ModuleNotFoundError:
45                pass
46
47
48environment = JinjaEnvironment()
49
50
51def register_template_extension(extension_class):
52    environment.add_extension(extension_class)
53    return extension_class
54
55
56def register_template_global(value, name=None):
57    """
58    Adds a global to the Jinja environment.
59
60    Can be used as a decorator on a function:
61
62            @register_template_global
63            def my_global():
64                return "Hello, world!"
65
66    Or as a function:
67
68            register_template_global("Hello, world!", name="my_global")
69    """
70    if callable(value):
71        environment.globals[name or value.__name__] = value
72    elif name:
73        environment.globals[name] = value
74    else:
75        raise ValueError("name must be provided if value is not callable")
76
77    return value
78
79
80def register_template_filter(func, name=None):
81    """Adds a filter to the Jinja environment."""
82    environment.filters[name or func.__name__] = func
83    return func
84
85
86__all__ = [
87    "environment",
88    "DefaultEnvironment",
89    "get_template_dirs",
90    "register_template_extension",
91    "register_template_filter",
92    "register_template_global",
93]