Coverage for /Users/davegaeddert/Developer/dropseed/plain/plain/plain/templates/jinja/environments.py: 96%
26 statements
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-23 11:16 -0600
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-23 11:16 -0600
1import functools
2from pathlib import Path
4from jinja2 import Environment, StrictUndefined
5from jinja2.loaders import FileSystemLoader
7from plain.packages import packages
8from plain.runtime import settings
10from .filters import default_filters
11from .globals import default_globals
14def finalize_callable_error(obj):
15 """Prevent direct rendering of a callable (likely just forgotten ()) by raising a TypeError"""
16 if callable(obj):
17 raise TypeError(f"{obj} is callable, did you forget parentheses?")
19 # TODO find a way to prevent <object representation> from being rendered
20 # if obj.__class__.__str__ is object.__str__:
21 # raise TypeError(f"{obj} does not have a __str__ method")
23 return obj
26def get_template_dirs():
27 jinja_templates = Path(__file__).parent / "templates"
28 app_templates = settings.path.parent / "templates"
29 return (jinja_templates, app_templates) + _get_app_template_dirs()
32@functools.lru_cache
33def _get_app_template_dirs():
34 """
35 Return an iterable of paths of directories to load app templates from.
37 dirname is the name of the subdirectory containing templates inside
38 installed applications.
39 """
40 dirname = "templates"
41 template_dirs = [
42 Path(package_config.path) / dirname
43 for package_config in packages.get_package_configs()
44 if package_config.path and (Path(package_config.path) / dirname).is_dir()
45 ]
46 # Immutable return value because it will be cached and shared by callers.
47 return tuple(template_dirs)
50class DefaultEnvironment(Environment):
51 def __init__(self):
52 super().__init__(
53 loader=FileSystemLoader(get_template_dirs()),
54 autoescape=True,
55 auto_reload=settings.DEBUG,
56 undefined=StrictUndefined,
57 finalize=finalize_callable_error,
58 extensions=["jinja2.ext.loopcontrols", "jinja2.ext.debug"],
59 )
61 # Load the top-level defaults
62 self.globals.update(default_globals)
63 self.filters.update(default_filters)