1e31aef6aSopenharmony_ci"""Classes for managing templates and their runtime and compile time 2e31aef6aSopenharmony_cioptions. 3e31aef6aSopenharmony_ci""" 4e31aef6aSopenharmony_ciimport os 5e31aef6aSopenharmony_ciimport typing 6e31aef6aSopenharmony_ciimport typing as t 7e31aef6aSopenharmony_ciimport weakref 8e31aef6aSopenharmony_cifrom collections import ChainMap 9e31aef6aSopenharmony_cifrom functools import lru_cache 10e31aef6aSopenharmony_cifrom functools import partial 11e31aef6aSopenharmony_cifrom functools import reduce 12e31aef6aSopenharmony_cifrom types import CodeType 13e31aef6aSopenharmony_ci 14e31aef6aSopenharmony_cifrom markupsafe import Markup 15e31aef6aSopenharmony_ci 16e31aef6aSopenharmony_cifrom . import nodes 17e31aef6aSopenharmony_cifrom .compiler import CodeGenerator 18e31aef6aSopenharmony_cifrom .compiler import generate 19e31aef6aSopenharmony_cifrom .defaults import BLOCK_END_STRING 20e31aef6aSopenharmony_cifrom .defaults import BLOCK_START_STRING 21e31aef6aSopenharmony_cifrom .defaults import COMMENT_END_STRING 22e31aef6aSopenharmony_cifrom .defaults import COMMENT_START_STRING 23e31aef6aSopenharmony_cifrom .defaults import DEFAULT_FILTERS 24e31aef6aSopenharmony_cifrom .defaults import DEFAULT_NAMESPACE 25e31aef6aSopenharmony_cifrom .defaults import DEFAULT_POLICIES 26e31aef6aSopenharmony_cifrom .defaults import DEFAULT_TESTS 27e31aef6aSopenharmony_cifrom .defaults import KEEP_TRAILING_NEWLINE 28e31aef6aSopenharmony_cifrom .defaults import LINE_COMMENT_PREFIX 29e31aef6aSopenharmony_cifrom .defaults import LINE_STATEMENT_PREFIX 30e31aef6aSopenharmony_cifrom .defaults import LSTRIP_BLOCKS 31e31aef6aSopenharmony_cifrom .defaults import NEWLINE_SEQUENCE 32e31aef6aSopenharmony_cifrom .defaults import TRIM_BLOCKS 33e31aef6aSopenharmony_cifrom .defaults import VARIABLE_END_STRING 34e31aef6aSopenharmony_cifrom .defaults import VARIABLE_START_STRING 35e31aef6aSopenharmony_cifrom .exceptions import TemplateNotFound 36e31aef6aSopenharmony_cifrom .exceptions import TemplateRuntimeError 37e31aef6aSopenharmony_cifrom .exceptions import TemplatesNotFound 38e31aef6aSopenharmony_cifrom .exceptions import TemplateSyntaxError 39e31aef6aSopenharmony_cifrom .exceptions import UndefinedError 40e31aef6aSopenharmony_cifrom .lexer import get_lexer 41e31aef6aSopenharmony_cifrom .lexer import Lexer 42e31aef6aSopenharmony_cifrom .lexer import TokenStream 43e31aef6aSopenharmony_cifrom .nodes import EvalContext 44e31aef6aSopenharmony_cifrom .parser import Parser 45e31aef6aSopenharmony_cifrom .runtime import Context 46e31aef6aSopenharmony_cifrom .runtime import new_context 47e31aef6aSopenharmony_cifrom .runtime import Undefined 48e31aef6aSopenharmony_cifrom .utils import _PassArg 49e31aef6aSopenharmony_cifrom .utils import concat 50e31aef6aSopenharmony_cifrom .utils import consume 51e31aef6aSopenharmony_cifrom .utils import import_string 52e31aef6aSopenharmony_cifrom .utils import internalcode 53e31aef6aSopenharmony_cifrom .utils import LRUCache 54e31aef6aSopenharmony_cifrom .utils import missing 55e31aef6aSopenharmony_ci 56e31aef6aSopenharmony_ciif t.TYPE_CHECKING: 57e31aef6aSopenharmony_ci import typing_extensions as te 58e31aef6aSopenharmony_ci from .bccache import BytecodeCache 59e31aef6aSopenharmony_ci from .ext import Extension 60e31aef6aSopenharmony_ci from .loaders import BaseLoader 61e31aef6aSopenharmony_ci 62e31aef6aSopenharmony_ci_env_bound = t.TypeVar("_env_bound", bound="Environment") 63e31aef6aSopenharmony_ci 64e31aef6aSopenharmony_ci 65e31aef6aSopenharmony_ci# for direct template usage we have up to ten living environments 66e31aef6aSopenharmony_ci@lru_cache(maxsize=10) 67e31aef6aSopenharmony_cidef get_spontaneous_environment(cls: t.Type[_env_bound], *args: t.Any) -> _env_bound: 68e31aef6aSopenharmony_ci """Return a new spontaneous environment. A spontaneous environment 69e31aef6aSopenharmony_ci is used for templates created directly rather than through an 70e31aef6aSopenharmony_ci existing environment. 71e31aef6aSopenharmony_ci 72e31aef6aSopenharmony_ci :param cls: Environment class to create. 73e31aef6aSopenharmony_ci :param args: Positional arguments passed to environment. 74e31aef6aSopenharmony_ci """ 75e31aef6aSopenharmony_ci env = cls(*args) 76e31aef6aSopenharmony_ci env.shared = True 77e31aef6aSopenharmony_ci return env 78e31aef6aSopenharmony_ci 79e31aef6aSopenharmony_ci 80e31aef6aSopenharmony_cidef create_cache( 81e31aef6aSopenharmony_ci size: int, 82e31aef6aSopenharmony_ci) -> t.Optional[t.MutableMapping[t.Tuple[weakref.ref, str], "Template"]]: 83e31aef6aSopenharmony_ci """Return the cache class for the given size.""" 84e31aef6aSopenharmony_ci if size == 0: 85e31aef6aSopenharmony_ci return None 86e31aef6aSopenharmony_ci 87e31aef6aSopenharmony_ci if size < 0: 88e31aef6aSopenharmony_ci return {} 89e31aef6aSopenharmony_ci 90e31aef6aSopenharmony_ci return LRUCache(size) # type: ignore 91e31aef6aSopenharmony_ci 92e31aef6aSopenharmony_ci 93e31aef6aSopenharmony_cidef copy_cache( 94e31aef6aSopenharmony_ci cache: t.Optional[t.MutableMapping], 95e31aef6aSopenharmony_ci) -> t.Optional[t.MutableMapping[t.Tuple[weakref.ref, str], "Template"]]: 96e31aef6aSopenharmony_ci """Create an empty copy of the given cache.""" 97e31aef6aSopenharmony_ci if cache is None: 98e31aef6aSopenharmony_ci return None 99e31aef6aSopenharmony_ci 100e31aef6aSopenharmony_ci if type(cache) is dict: 101e31aef6aSopenharmony_ci return {} 102e31aef6aSopenharmony_ci 103e31aef6aSopenharmony_ci return LRUCache(cache.capacity) # type: ignore 104e31aef6aSopenharmony_ci 105e31aef6aSopenharmony_ci 106e31aef6aSopenharmony_cidef load_extensions( 107e31aef6aSopenharmony_ci environment: "Environment", 108e31aef6aSopenharmony_ci extensions: t.Sequence[t.Union[str, t.Type["Extension"]]], 109e31aef6aSopenharmony_ci) -> t.Dict[str, "Extension"]: 110e31aef6aSopenharmony_ci """Load the extensions from the list and bind it to the environment. 111e31aef6aSopenharmony_ci Returns a dict of instantiated extensions. 112e31aef6aSopenharmony_ci """ 113e31aef6aSopenharmony_ci result = {} 114e31aef6aSopenharmony_ci 115e31aef6aSopenharmony_ci for extension in extensions: 116e31aef6aSopenharmony_ci if isinstance(extension, str): 117e31aef6aSopenharmony_ci extension = t.cast(t.Type["Extension"], import_string(extension)) 118e31aef6aSopenharmony_ci 119e31aef6aSopenharmony_ci result[extension.identifier] = extension(environment) 120e31aef6aSopenharmony_ci 121e31aef6aSopenharmony_ci return result 122e31aef6aSopenharmony_ci 123e31aef6aSopenharmony_ci 124e31aef6aSopenharmony_cidef _environment_config_check(environment: "Environment") -> "Environment": 125e31aef6aSopenharmony_ci """Perform a sanity check on the environment.""" 126e31aef6aSopenharmony_ci assert issubclass( 127e31aef6aSopenharmony_ci environment.undefined, Undefined 128e31aef6aSopenharmony_ci ), "'undefined' must be a subclass of 'jinja2.Undefined'." 129e31aef6aSopenharmony_ci assert ( 130e31aef6aSopenharmony_ci environment.block_start_string 131e31aef6aSopenharmony_ci != environment.variable_start_string 132e31aef6aSopenharmony_ci != environment.comment_start_string 133e31aef6aSopenharmony_ci ), "block, variable and comment start strings must be different." 134e31aef6aSopenharmony_ci assert environment.newline_sequence in { 135e31aef6aSopenharmony_ci "\r", 136e31aef6aSopenharmony_ci "\r\n", 137e31aef6aSopenharmony_ci "\n", 138e31aef6aSopenharmony_ci }, "'newline_sequence' must be one of '\\n', '\\r\\n', or '\\r'." 139e31aef6aSopenharmony_ci return environment 140e31aef6aSopenharmony_ci 141e31aef6aSopenharmony_ci 142e31aef6aSopenharmony_ciclass Environment: 143e31aef6aSopenharmony_ci r"""The core component of Jinja is the `Environment`. It contains 144e31aef6aSopenharmony_ci important shared variables like configuration, filters, tests, 145e31aef6aSopenharmony_ci globals and others. Instances of this class may be modified if 146e31aef6aSopenharmony_ci they are not shared and if no template was loaded so far. 147e31aef6aSopenharmony_ci Modifications on environments after the first template was loaded 148e31aef6aSopenharmony_ci will lead to surprising effects and undefined behavior. 149e31aef6aSopenharmony_ci 150e31aef6aSopenharmony_ci Here are the possible initialization parameters: 151e31aef6aSopenharmony_ci 152e31aef6aSopenharmony_ci `block_start_string` 153e31aef6aSopenharmony_ci The string marking the beginning of a block. Defaults to ``'{%'``. 154e31aef6aSopenharmony_ci 155e31aef6aSopenharmony_ci `block_end_string` 156e31aef6aSopenharmony_ci The string marking the end of a block. Defaults to ``'%}'``. 157e31aef6aSopenharmony_ci 158e31aef6aSopenharmony_ci `variable_start_string` 159e31aef6aSopenharmony_ci The string marking the beginning of a print statement. 160e31aef6aSopenharmony_ci Defaults to ``'{{'``. 161e31aef6aSopenharmony_ci 162e31aef6aSopenharmony_ci `variable_end_string` 163e31aef6aSopenharmony_ci The string marking the end of a print statement. Defaults to 164e31aef6aSopenharmony_ci ``'}}'``. 165e31aef6aSopenharmony_ci 166e31aef6aSopenharmony_ci `comment_start_string` 167e31aef6aSopenharmony_ci The string marking the beginning of a comment. Defaults to ``'{#'``. 168e31aef6aSopenharmony_ci 169e31aef6aSopenharmony_ci `comment_end_string` 170e31aef6aSopenharmony_ci The string marking the end of a comment. Defaults to ``'#}'``. 171e31aef6aSopenharmony_ci 172e31aef6aSopenharmony_ci `line_statement_prefix` 173e31aef6aSopenharmony_ci If given and a string, this will be used as prefix for line based 174e31aef6aSopenharmony_ci statements. See also :ref:`line-statements`. 175e31aef6aSopenharmony_ci 176e31aef6aSopenharmony_ci `line_comment_prefix` 177e31aef6aSopenharmony_ci If given and a string, this will be used as prefix for line based 178e31aef6aSopenharmony_ci comments. See also :ref:`line-statements`. 179e31aef6aSopenharmony_ci 180e31aef6aSopenharmony_ci .. versionadded:: 2.2 181e31aef6aSopenharmony_ci 182e31aef6aSopenharmony_ci `trim_blocks` 183e31aef6aSopenharmony_ci If this is set to ``True`` the first newline after a block is 184e31aef6aSopenharmony_ci removed (block, not variable tag!). Defaults to `False`. 185e31aef6aSopenharmony_ci 186e31aef6aSopenharmony_ci `lstrip_blocks` 187e31aef6aSopenharmony_ci If this is set to ``True`` leading spaces and tabs are stripped 188e31aef6aSopenharmony_ci from the start of a line to a block. Defaults to `False`. 189e31aef6aSopenharmony_ci 190e31aef6aSopenharmony_ci `newline_sequence` 191e31aef6aSopenharmony_ci The sequence that starts a newline. Must be one of ``'\r'``, 192e31aef6aSopenharmony_ci ``'\n'`` or ``'\r\n'``. The default is ``'\n'`` which is a 193e31aef6aSopenharmony_ci useful default for Linux and OS X systems as well as web 194e31aef6aSopenharmony_ci applications. 195e31aef6aSopenharmony_ci 196e31aef6aSopenharmony_ci `keep_trailing_newline` 197e31aef6aSopenharmony_ci Preserve the trailing newline when rendering templates. 198e31aef6aSopenharmony_ci The default is ``False``, which causes a single newline, 199e31aef6aSopenharmony_ci if present, to be stripped from the end of the template. 200e31aef6aSopenharmony_ci 201e31aef6aSopenharmony_ci .. versionadded:: 2.7 202e31aef6aSopenharmony_ci 203e31aef6aSopenharmony_ci `extensions` 204e31aef6aSopenharmony_ci List of Jinja extensions to use. This can either be import paths 205e31aef6aSopenharmony_ci as strings or extension classes. For more information have a 206e31aef6aSopenharmony_ci look at :ref:`the extensions documentation <jinja-extensions>`. 207e31aef6aSopenharmony_ci 208e31aef6aSopenharmony_ci `optimized` 209e31aef6aSopenharmony_ci should the optimizer be enabled? Default is ``True``. 210e31aef6aSopenharmony_ci 211e31aef6aSopenharmony_ci `undefined` 212e31aef6aSopenharmony_ci :class:`Undefined` or a subclass of it that is used to represent 213e31aef6aSopenharmony_ci undefined values in the template. 214e31aef6aSopenharmony_ci 215e31aef6aSopenharmony_ci `finalize` 216e31aef6aSopenharmony_ci A callable that can be used to process the result of a variable 217e31aef6aSopenharmony_ci expression before it is output. For example one can convert 218e31aef6aSopenharmony_ci ``None`` implicitly into an empty string here. 219e31aef6aSopenharmony_ci 220e31aef6aSopenharmony_ci `autoescape` 221e31aef6aSopenharmony_ci If set to ``True`` the XML/HTML autoescaping feature is enabled by 222e31aef6aSopenharmony_ci default. For more details about autoescaping see 223e31aef6aSopenharmony_ci :class:`~markupsafe.Markup`. As of Jinja 2.4 this can also 224e31aef6aSopenharmony_ci be a callable that is passed the template name and has to 225e31aef6aSopenharmony_ci return ``True`` or ``False`` depending on autoescape should be 226e31aef6aSopenharmony_ci enabled by default. 227e31aef6aSopenharmony_ci 228e31aef6aSopenharmony_ci .. versionchanged:: 2.4 229e31aef6aSopenharmony_ci `autoescape` can now be a function 230e31aef6aSopenharmony_ci 231e31aef6aSopenharmony_ci `loader` 232e31aef6aSopenharmony_ci The template loader for this environment. 233e31aef6aSopenharmony_ci 234e31aef6aSopenharmony_ci `cache_size` 235e31aef6aSopenharmony_ci The size of the cache. Per default this is ``400`` which means 236e31aef6aSopenharmony_ci that if more than 400 templates are loaded the loader will clean 237e31aef6aSopenharmony_ci out the least recently used template. If the cache size is set to 238e31aef6aSopenharmony_ci ``0`` templates are recompiled all the time, if the cache size is 239e31aef6aSopenharmony_ci ``-1`` the cache will not be cleaned. 240e31aef6aSopenharmony_ci 241e31aef6aSopenharmony_ci .. versionchanged:: 2.8 242e31aef6aSopenharmony_ci The cache size was increased to 400 from a low 50. 243e31aef6aSopenharmony_ci 244e31aef6aSopenharmony_ci `auto_reload` 245e31aef6aSopenharmony_ci Some loaders load templates from locations where the template 246e31aef6aSopenharmony_ci sources may change (ie: file system or database). If 247e31aef6aSopenharmony_ci ``auto_reload`` is set to ``True`` (default) every time a template is 248e31aef6aSopenharmony_ci requested the loader checks if the source changed and if yes, it 249e31aef6aSopenharmony_ci will reload the template. For higher performance it's possible to 250e31aef6aSopenharmony_ci disable that. 251e31aef6aSopenharmony_ci 252e31aef6aSopenharmony_ci `bytecode_cache` 253e31aef6aSopenharmony_ci If set to a bytecode cache object, this object will provide a 254e31aef6aSopenharmony_ci cache for the internal Jinja bytecode so that templates don't 255e31aef6aSopenharmony_ci have to be parsed if they were not changed. 256e31aef6aSopenharmony_ci 257e31aef6aSopenharmony_ci See :ref:`bytecode-cache` for more information. 258e31aef6aSopenharmony_ci 259e31aef6aSopenharmony_ci `enable_async` 260e31aef6aSopenharmony_ci If set to true this enables async template execution which 261e31aef6aSopenharmony_ci allows using async functions and generators. 262e31aef6aSopenharmony_ci """ 263e31aef6aSopenharmony_ci 264e31aef6aSopenharmony_ci #: if this environment is sandboxed. Modifying this variable won't make 265e31aef6aSopenharmony_ci #: the environment sandboxed though. For a real sandboxed environment 266e31aef6aSopenharmony_ci #: have a look at jinja2.sandbox. This flag alone controls the code 267e31aef6aSopenharmony_ci #: generation by the compiler. 268e31aef6aSopenharmony_ci sandboxed = False 269e31aef6aSopenharmony_ci 270e31aef6aSopenharmony_ci #: True if the environment is just an overlay 271e31aef6aSopenharmony_ci overlayed = False 272e31aef6aSopenharmony_ci 273e31aef6aSopenharmony_ci #: the environment this environment is linked to if it is an overlay 274e31aef6aSopenharmony_ci linked_to: t.Optional["Environment"] = None 275e31aef6aSopenharmony_ci 276e31aef6aSopenharmony_ci #: shared environments have this set to `True`. A shared environment 277e31aef6aSopenharmony_ci #: must not be modified 278e31aef6aSopenharmony_ci shared = False 279e31aef6aSopenharmony_ci 280e31aef6aSopenharmony_ci #: the class that is used for code generation. See 281e31aef6aSopenharmony_ci #: :class:`~jinja2.compiler.CodeGenerator` for more information. 282e31aef6aSopenharmony_ci code_generator_class: t.Type["CodeGenerator"] = CodeGenerator 283e31aef6aSopenharmony_ci 284e31aef6aSopenharmony_ci concat = "".join 285e31aef6aSopenharmony_ci 286e31aef6aSopenharmony_ci #: the context class that is used for templates. See 287e31aef6aSopenharmony_ci #: :class:`~jinja2.runtime.Context` for more information. 288e31aef6aSopenharmony_ci context_class: t.Type[Context] = Context 289e31aef6aSopenharmony_ci 290e31aef6aSopenharmony_ci template_class: t.Type["Template"] 291e31aef6aSopenharmony_ci 292e31aef6aSopenharmony_ci def __init__( 293e31aef6aSopenharmony_ci self, 294e31aef6aSopenharmony_ci block_start_string: str = BLOCK_START_STRING, 295e31aef6aSopenharmony_ci block_end_string: str = BLOCK_END_STRING, 296e31aef6aSopenharmony_ci variable_start_string: str = VARIABLE_START_STRING, 297e31aef6aSopenharmony_ci variable_end_string: str = VARIABLE_END_STRING, 298e31aef6aSopenharmony_ci comment_start_string: str = COMMENT_START_STRING, 299e31aef6aSopenharmony_ci comment_end_string: str = COMMENT_END_STRING, 300e31aef6aSopenharmony_ci line_statement_prefix: t.Optional[str] = LINE_STATEMENT_PREFIX, 301e31aef6aSopenharmony_ci line_comment_prefix: t.Optional[str] = LINE_COMMENT_PREFIX, 302e31aef6aSopenharmony_ci trim_blocks: bool = TRIM_BLOCKS, 303e31aef6aSopenharmony_ci lstrip_blocks: bool = LSTRIP_BLOCKS, 304e31aef6aSopenharmony_ci newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = NEWLINE_SEQUENCE, 305e31aef6aSopenharmony_ci keep_trailing_newline: bool = KEEP_TRAILING_NEWLINE, 306e31aef6aSopenharmony_ci extensions: t.Sequence[t.Union[str, t.Type["Extension"]]] = (), 307e31aef6aSopenharmony_ci optimized: bool = True, 308e31aef6aSopenharmony_ci undefined: t.Type[Undefined] = Undefined, 309e31aef6aSopenharmony_ci finalize: t.Optional[t.Callable[..., t.Any]] = None, 310e31aef6aSopenharmony_ci autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = False, 311e31aef6aSopenharmony_ci loader: t.Optional["BaseLoader"] = None, 312e31aef6aSopenharmony_ci cache_size: int = 400, 313e31aef6aSopenharmony_ci auto_reload: bool = True, 314e31aef6aSopenharmony_ci bytecode_cache: t.Optional["BytecodeCache"] = None, 315e31aef6aSopenharmony_ci enable_async: bool = False, 316e31aef6aSopenharmony_ci ): 317e31aef6aSopenharmony_ci # !!Important notice!! 318e31aef6aSopenharmony_ci # The constructor accepts quite a few arguments that should be 319e31aef6aSopenharmony_ci # passed by keyword rather than position. However it's important to 320e31aef6aSopenharmony_ci # not change the order of arguments because it's used at least 321e31aef6aSopenharmony_ci # internally in those cases: 322e31aef6aSopenharmony_ci # - spontaneous environments (i18n extension and Template) 323e31aef6aSopenharmony_ci # - unittests 324e31aef6aSopenharmony_ci # If parameter changes are required only add parameters at the end 325e31aef6aSopenharmony_ci # and don't change the arguments (or the defaults!) of the arguments 326e31aef6aSopenharmony_ci # existing already. 327e31aef6aSopenharmony_ci 328e31aef6aSopenharmony_ci # lexer / parser information 329e31aef6aSopenharmony_ci self.block_start_string = block_start_string 330e31aef6aSopenharmony_ci self.block_end_string = block_end_string 331e31aef6aSopenharmony_ci self.variable_start_string = variable_start_string 332e31aef6aSopenharmony_ci self.variable_end_string = variable_end_string 333e31aef6aSopenharmony_ci self.comment_start_string = comment_start_string 334e31aef6aSopenharmony_ci self.comment_end_string = comment_end_string 335e31aef6aSopenharmony_ci self.line_statement_prefix = line_statement_prefix 336e31aef6aSopenharmony_ci self.line_comment_prefix = line_comment_prefix 337e31aef6aSopenharmony_ci self.trim_blocks = trim_blocks 338e31aef6aSopenharmony_ci self.lstrip_blocks = lstrip_blocks 339e31aef6aSopenharmony_ci self.newline_sequence = newline_sequence 340e31aef6aSopenharmony_ci self.keep_trailing_newline = keep_trailing_newline 341e31aef6aSopenharmony_ci 342e31aef6aSopenharmony_ci # runtime information 343e31aef6aSopenharmony_ci self.undefined: t.Type[Undefined] = undefined 344e31aef6aSopenharmony_ci self.optimized = optimized 345e31aef6aSopenharmony_ci self.finalize = finalize 346e31aef6aSopenharmony_ci self.autoescape = autoescape 347e31aef6aSopenharmony_ci 348e31aef6aSopenharmony_ci # defaults 349e31aef6aSopenharmony_ci self.filters = DEFAULT_FILTERS.copy() 350e31aef6aSopenharmony_ci self.tests = DEFAULT_TESTS.copy() 351e31aef6aSopenharmony_ci self.globals = DEFAULT_NAMESPACE.copy() 352e31aef6aSopenharmony_ci 353e31aef6aSopenharmony_ci # set the loader provided 354e31aef6aSopenharmony_ci self.loader = loader 355e31aef6aSopenharmony_ci self.cache = create_cache(cache_size) 356e31aef6aSopenharmony_ci self.bytecode_cache = bytecode_cache 357e31aef6aSopenharmony_ci self.auto_reload = auto_reload 358e31aef6aSopenharmony_ci 359e31aef6aSopenharmony_ci # configurable policies 360e31aef6aSopenharmony_ci self.policies = DEFAULT_POLICIES.copy() 361e31aef6aSopenharmony_ci 362e31aef6aSopenharmony_ci # load extensions 363e31aef6aSopenharmony_ci self.extensions = load_extensions(self, extensions) 364e31aef6aSopenharmony_ci 365e31aef6aSopenharmony_ci self.is_async = enable_async 366e31aef6aSopenharmony_ci _environment_config_check(self) 367e31aef6aSopenharmony_ci 368e31aef6aSopenharmony_ci def add_extension(self, extension: t.Union[str, t.Type["Extension"]]) -> None: 369e31aef6aSopenharmony_ci """Adds an extension after the environment was created. 370e31aef6aSopenharmony_ci 371e31aef6aSopenharmony_ci .. versionadded:: 2.5 372e31aef6aSopenharmony_ci """ 373e31aef6aSopenharmony_ci self.extensions.update(load_extensions(self, [extension])) 374e31aef6aSopenharmony_ci 375e31aef6aSopenharmony_ci def extend(self, **attributes: t.Any) -> None: 376e31aef6aSopenharmony_ci """Add the items to the instance of the environment if they do not exist 377e31aef6aSopenharmony_ci yet. This is used by :ref:`extensions <writing-extensions>` to register 378e31aef6aSopenharmony_ci callbacks and configuration values without breaking inheritance. 379e31aef6aSopenharmony_ci """ 380e31aef6aSopenharmony_ci for key, value in attributes.items(): 381e31aef6aSopenharmony_ci if not hasattr(self, key): 382e31aef6aSopenharmony_ci setattr(self, key, value) 383e31aef6aSopenharmony_ci 384e31aef6aSopenharmony_ci def overlay( 385e31aef6aSopenharmony_ci self, 386e31aef6aSopenharmony_ci block_start_string: str = missing, 387e31aef6aSopenharmony_ci block_end_string: str = missing, 388e31aef6aSopenharmony_ci variable_start_string: str = missing, 389e31aef6aSopenharmony_ci variable_end_string: str = missing, 390e31aef6aSopenharmony_ci comment_start_string: str = missing, 391e31aef6aSopenharmony_ci comment_end_string: str = missing, 392e31aef6aSopenharmony_ci line_statement_prefix: t.Optional[str] = missing, 393e31aef6aSopenharmony_ci line_comment_prefix: t.Optional[str] = missing, 394e31aef6aSopenharmony_ci trim_blocks: bool = missing, 395e31aef6aSopenharmony_ci lstrip_blocks: bool = missing, 396e31aef6aSopenharmony_ci newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = missing, 397e31aef6aSopenharmony_ci keep_trailing_newline: bool = missing, 398e31aef6aSopenharmony_ci extensions: t.Sequence[t.Union[str, t.Type["Extension"]]] = missing, 399e31aef6aSopenharmony_ci optimized: bool = missing, 400e31aef6aSopenharmony_ci undefined: t.Type[Undefined] = missing, 401e31aef6aSopenharmony_ci finalize: t.Optional[t.Callable[..., t.Any]] = missing, 402e31aef6aSopenharmony_ci autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = missing, 403e31aef6aSopenharmony_ci loader: t.Optional["BaseLoader"] = missing, 404e31aef6aSopenharmony_ci cache_size: int = missing, 405e31aef6aSopenharmony_ci auto_reload: bool = missing, 406e31aef6aSopenharmony_ci bytecode_cache: t.Optional["BytecodeCache"] = missing, 407e31aef6aSopenharmony_ci enable_async: bool = False, 408e31aef6aSopenharmony_ci ) -> "Environment": 409e31aef6aSopenharmony_ci """Create a new overlay environment that shares all the data with the 410e31aef6aSopenharmony_ci current environment except for cache and the overridden attributes. 411e31aef6aSopenharmony_ci Extensions cannot be removed for an overlayed environment. An overlayed 412e31aef6aSopenharmony_ci environment automatically gets all the extensions of the environment it 413e31aef6aSopenharmony_ci is linked to plus optional extra extensions. 414e31aef6aSopenharmony_ci 415e31aef6aSopenharmony_ci Creating overlays should happen after the initial environment was set 416e31aef6aSopenharmony_ci up completely. Not all attributes are truly linked, some are just 417e31aef6aSopenharmony_ci copied over so modifications on the original environment may not shine 418e31aef6aSopenharmony_ci through. 419e31aef6aSopenharmony_ci 420e31aef6aSopenharmony_ci .. versionchanged:: 3.1.2 421e31aef6aSopenharmony_ci Added the ``newline_sequence``,, ``keep_trailing_newline``, 422e31aef6aSopenharmony_ci and ``enable_async`` parameters to match ``__init__``. 423e31aef6aSopenharmony_ci """ 424e31aef6aSopenharmony_ci args = dict(locals()) 425e31aef6aSopenharmony_ci del args["self"], args["cache_size"], args["extensions"], args["enable_async"] 426e31aef6aSopenharmony_ci 427e31aef6aSopenharmony_ci rv = object.__new__(self.__class__) 428e31aef6aSopenharmony_ci rv.__dict__.update(self.__dict__) 429e31aef6aSopenharmony_ci rv.overlayed = True 430e31aef6aSopenharmony_ci rv.linked_to = self 431e31aef6aSopenharmony_ci 432e31aef6aSopenharmony_ci for key, value in args.items(): 433e31aef6aSopenharmony_ci if value is not missing: 434e31aef6aSopenharmony_ci setattr(rv, key, value) 435e31aef6aSopenharmony_ci 436e31aef6aSopenharmony_ci if cache_size is not missing: 437e31aef6aSopenharmony_ci rv.cache = create_cache(cache_size) 438e31aef6aSopenharmony_ci else: 439e31aef6aSopenharmony_ci rv.cache = copy_cache(self.cache) 440e31aef6aSopenharmony_ci 441e31aef6aSopenharmony_ci rv.extensions = {} 442e31aef6aSopenharmony_ci for key, value in self.extensions.items(): 443e31aef6aSopenharmony_ci rv.extensions[key] = value.bind(rv) 444e31aef6aSopenharmony_ci if extensions is not missing: 445e31aef6aSopenharmony_ci rv.extensions.update(load_extensions(rv, extensions)) 446e31aef6aSopenharmony_ci 447e31aef6aSopenharmony_ci if enable_async is not missing: 448e31aef6aSopenharmony_ci rv.is_async = enable_async 449e31aef6aSopenharmony_ci 450e31aef6aSopenharmony_ci return _environment_config_check(rv) 451e31aef6aSopenharmony_ci 452e31aef6aSopenharmony_ci @property 453e31aef6aSopenharmony_ci def lexer(self) -> Lexer: 454e31aef6aSopenharmony_ci """The lexer for this environment.""" 455e31aef6aSopenharmony_ci return get_lexer(self) 456e31aef6aSopenharmony_ci 457e31aef6aSopenharmony_ci def iter_extensions(self) -> t.Iterator["Extension"]: 458e31aef6aSopenharmony_ci """Iterates over the extensions by priority.""" 459e31aef6aSopenharmony_ci return iter(sorted(self.extensions.values(), key=lambda x: x.priority)) 460e31aef6aSopenharmony_ci 461e31aef6aSopenharmony_ci def getitem( 462e31aef6aSopenharmony_ci self, obj: t.Any, argument: t.Union[str, t.Any] 463e31aef6aSopenharmony_ci ) -> t.Union[t.Any, Undefined]: 464e31aef6aSopenharmony_ci """Get an item or attribute of an object but prefer the item.""" 465e31aef6aSopenharmony_ci try: 466e31aef6aSopenharmony_ci return obj[argument] 467e31aef6aSopenharmony_ci except (AttributeError, TypeError, LookupError): 468e31aef6aSopenharmony_ci if isinstance(argument, str): 469e31aef6aSopenharmony_ci try: 470e31aef6aSopenharmony_ci attr = str(argument) 471e31aef6aSopenharmony_ci except Exception: 472e31aef6aSopenharmony_ci pass 473e31aef6aSopenharmony_ci else: 474e31aef6aSopenharmony_ci try: 475e31aef6aSopenharmony_ci return getattr(obj, attr) 476e31aef6aSopenharmony_ci except AttributeError: 477e31aef6aSopenharmony_ci pass 478e31aef6aSopenharmony_ci return self.undefined(obj=obj, name=argument) 479e31aef6aSopenharmony_ci 480e31aef6aSopenharmony_ci def getattr(self, obj: t.Any, attribute: str) -> t.Any: 481e31aef6aSopenharmony_ci """Get an item or attribute of an object but prefer the attribute. 482e31aef6aSopenharmony_ci Unlike :meth:`getitem` the attribute *must* be a string. 483e31aef6aSopenharmony_ci """ 484e31aef6aSopenharmony_ci try: 485e31aef6aSopenharmony_ci return getattr(obj, attribute) 486e31aef6aSopenharmony_ci except AttributeError: 487e31aef6aSopenharmony_ci pass 488e31aef6aSopenharmony_ci try: 489e31aef6aSopenharmony_ci return obj[attribute] 490e31aef6aSopenharmony_ci except (TypeError, LookupError, AttributeError): 491e31aef6aSopenharmony_ci return self.undefined(obj=obj, name=attribute) 492e31aef6aSopenharmony_ci 493e31aef6aSopenharmony_ci def _filter_test_common( 494e31aef6aSopenharmony_ci self, 495e31aef6aSopenharmony_ci name: t.Union[str, Undefined], 496e31aef6aSopenharmony_ci value: t.Any, 497e31aef6aSopenharmony_ci args: t.Optional[t.Sequence[t.Any]], 498e31aef6aSopenharmony_ci kwargs: t.Optional[t.Mapping[str, t.Any]], 499e31aef6aSopenharmony_ci context: t.Optional[Context], 500e31aef6aSopenharmony_ci eval_ctx: t.Optional[EvalContext], 501e31aef6aSopenharmony_ci is_filter: bool, 502e31aef6aSopenharmony_ci ) -> t.Any: 503e31aef6aSopenharmony_ci if is_filter: 504e31aef6aSopenharmony_ci env_map = self.filters 505e31aef6aSopenharmony_ci type_name = "filter" 506e31aef6aSopenharmony_ci else: 507e31aef6aSopenharmony_ci env_map = self.tests 508e31aef6aSopenharmony_ci type_name = "test" 509e31aef6aSopenharmony_ci 510e31aef6aSopenharmony_ci func = env_map.get(name) # type: ignore 511e31aef6aSopenharmony_ci 512e31aef6aSopenharmony_ci if func is None: 513e31aef6aSopenharmony_ci msg = f"No {type_name} named {name!r}." 514e31aef6aSopenharmony_ci 515e31aef6aSopenharmony_ci if isinstance(name, Undefined): 516e31aef6aSopenharmony_ci try: 517e31aef6aSopenharmony_ci name._fail_with_undefined_error() 518e31aef6aSopenharmony_ci except Exception as e: 519e31aef6aSopenharmony_ci msg = f"{msg} ({e}; did you forget to quote the callable name?)" 520e31aef6aSopenharmony_ci 521e31aef6aSopenharmony_ci raise TemplateRuntimeError(msg) 522e31aef6aSopenharmony_ci 523e31aef6aSopenharmony_ci args = [value, *(args if args is not None else ())] 524e31aef6aSopenharmony_ci kwargs = kwargs if kwargs is not None else {} 525e31aef6aSopenharmony_ci pass_arg = _PassArg.from_obj(func) 526e31aef6aSopenharmony_ci 527e31aef6aSopenharmony_ci if pass_arg is _PassArg.context: 528e31aef6aSopenharmony_ci if context is None: 529e31aef6aSopenharmony_ci raise TemplateRuntimeError( 530e31aef6aSopenharmony_ci f"Attempted to invoke a context {type_name} without context." 531e31aef6aSopenharmony_ci ) 532e31aef6aSopenharmony_ci 533e31aef6aSopenharmony_ci args.insert(0, context) 534e31aef6aSopenharmony_ci elif pass_arg is _PassArg.eval_context: 535e31aef6aSopenharmony_ci if eval_ctx is None: 536e31aef6aSopenharmony_ci if context is not None: 537e31aef6aSopenharmony_ci eval_ctx = context.eval_ctx 538e31aef6aSopenharmony_ci else: 539e31aef6aSopenharmony_ci eval_ctx = EvalContext(self) 540e31aef6aSopenharmony_ci 541e31aef6aSopenharmony_ci args.insert(0, eval_ctx) 542e31aef6aSopenharmony_ci elif pass_arg is _PassArg.environment: 543e31aef6aSopenharmony_ci args.insert(0, self) 544e31aef6aSopenharmony_ci 545e31aef6aSopenharmony_ci return func(*args, **kwargs) 546e31aef6aSopenharmony_ci 547e31aef6aSopenharmony_ci def call_filter( 548e31aef6aSopenharmony_ci self, 549e31aef6aSopenharmony_ci name: str, 550e31aef6aSopenharmony_ci value: t.Any, 551e31aef6aSopenharmony_ci args: t.Optional[t.Sequence[t.Any]] = None, 552e31aef6aSopenharmony_ci kwargs: t.Optional[t.Mapping[str, t.Any]] = None, 553e31aef6aSopenharmony_ci context: t.Optional[Context] = None, 554e31aef6aSopenharmony_ci eval_ctx: t.Optional[EvalContext] = None, 555e31aef6aSopenharmony_ci ) -> t.Any: 556e31aef6aSopenharmony_ci """Invoke a filter on a value the same way the compiler does. 557e31aef6aSopenharmony_ci 558e31aef6aSopenharmony_ci This might return a coroutine if the filter is running from an 559e31aef6aSopenharmony_ci environment in async mode and the filter supports async 560e31aef6aSopenharmony_ci execution. It's your responsibility to await this if needed. 561e31aef6aSopenharmony_ci 562e31aef6aSopenharmony_ci .. versionadded:: 2.7 563e31aef6aSopenharmony_ci """ 564e31aef6aSopenharmony_ci return self._filter_test_common( 565e31aef6aSopenharmony_ci name, value, args, kwargs, context, eval_ctx, True 566e31aef6aSopenharmony_ci ) 567e31aef6aSopenharmony_ci 568e31aef6aSopenharmony_ci def call_test( 569e31aef6aSopenharmony_ci self, 570e31aef6aSopenharmony_ci name: str, 571e31aef6aSopenharmony_ci value: t.Any, 572e31aef6aSopenharmony_ci args: t.Optional[t.Sequence[t.Any]] = None, 573e31aef6aSopenharmony_ci kwargs: t.Optional[t.Mapping[str, t.Any]] = None, 574e31aef6aSopenharmony_ci context: t.Optional[Context] = None, 575e31aef6aSopenharmony_ci eval_ctx: t.Optional[EvalContext] = None, 576e31aef6aSopenharmony_ci ) -> t.Any: 577e31aef6aSopenharmony_ci """Invoke a test on a value the same way the compiler does. 578e31aef6aSopenharmony_ci 579e31aef6aSopenharmony_ci This might return a coroutine if the test is running from an 580e31aef6aSopenharmony_ci environment in async mode and the test supports async execution. 581e31aef6aSopenharmony_ci It's your responsibility to await this if needed. 582e31aef6aSopenharmony_ci 583e31aef6aSopenharmony_ci .. versionchanged:: 3.0 584e31aef6aSopenharmony_ci Tests support ``@pass_context``, etc. decorators. Added 585e31aef6aSopenharmony_ci the ``context`` and ``eval_ctx`` parameters. 586e31aef6aSopenharmony_ci 587e31aef6aSopenharmony_ci .. versionadded:: 2.7 588e31aef6aSopenharmony_ci """ 589e31aef6aSopenharmony_ci return self._filter_test_common( 590e31aef6aSopenharmony_ci name, value, args, kwargs, context, eval_ctx, False 591e31aef6aSopenharmony_ci ) 592e31aef6aSopenharmony_ci 593e31aef6aSopenharmony_ci @internalcode 594e31aef6aSopenharmony_ci def parse( 595e31aef6aSopenharmony_ci self, 596e31aef6aSopenharmony_ci source: str, 597e31aef6aSopenharmony_ci name: t.Optional[str] = None, 598e31aef6aSopenharmony_ci filename: t.Optional[str] = None, 599e31aef6aSopenharmony_ci ) -> nodes.Template: 600e31aef6aSopenharmony_ci """Parse the sourcecode and return the abstract syntax tree. This 601e31aef6aSopenharmony_ci tree of nodes is used by the compiler to convert the template into 602e31aef6aSopenharmony_ci executable source- or bytecode. This is useful for debugging or to 603e31aef6aSopenharmony_ci extract information from templates. 604e31aef6aSopenharmony_ci 605e31aef6aSopenharmony_ci If you are :ref:`developing Jinja extensions <writing-extensions>` 606e31aef6aSopenharmony_ci this gives you a good overview of the node tree generated. 607e31aef6aSopenharmony_ci """ 608e31aef6aSopenharmony_ci try: 609e31aef6aSopenharmony_ci return self._parse(source, name, filename) 610e31aef6aSopenharmony_ci except TemplateSyntaxError: 611e31aef6aSopenharmony_ci self.handle_exception(source=source) 612e31aef6aSopenharmony_ci 613e31aef6aSopenharmony_ci def _parse( 614e31aef6aSopenharmony_ci self, source: str, name: t.Optional[str], filename: t.Optional[str] 615e31aef6aSopenharmony_ci ) -> nodes.Template: 616e31aef6aSopenharmony_ci """Internal parsing function used by `parse` and `compile`.""" 617e31aef6aSopenharmony_ci return Parser(self, source, name, filename).parse() 618e31aef6aSopenharmony_ci 619e31aef6aSopenharmony_ci def lex( 620e31aef6aSopenharmony_ci self, 621e31aef6aSopenharmony_ci source: str, 622e31aef6aSopenharmony_ci name: t.Optional[str] = None, 623e31aef6aSopenharmony_ci filename: t.Optional[str] = None, 624e31aef6aSopenharmony_ci ) -> t.Iterator[t.Tuple[int, str, str]]: 625e31aef6aSopenharmony_ci """Lex the given sourcecode and return a generator that yields 626e31aef6aSopenharmony_ci tokens as tuples in the form ``(lineno, token_type, value)``. 627e31aef6aSopenharmony_ci This can be useful for :ref:`extension development <writing-extensions>` 628e31aef6aSopenharmony_ci and debugging templates. 629e31aef6aSopenharmony_ci 630e31aef6aSopenharmony_ci This does not perform preprocessing. If you want the preprocessing 631e31aef6aSopenharmony_ci of the extensions to be applied you have to filter source through 632e31aef6aSopenharmony_ci the :meth:`preprocess` method. 633e31aef6aSopenharmony_ci """ 634e31aef6aSopenharmony_ci source = str(source) 635e31aef6aSopenharmony_ci try: 636e31aef6aSopenharmony_ci return self.lexer.tokeniter(source, name, filename) 637e31aef6aSopenharmony_ci except TemplateSyntaxError: 638e31aef6aSopenharmony_ci self.handle_exception(source=source) 639e31aef6aSopenharmony_ci 640e31aef6aSopenharmony_ci def preprocess( 641e31aef6aSopenharmony_ci self, 642e31aef6aSopenharmony_ci source: str, 643e31aef6aSopenharmony_ci name: t.Optional[str] = None, 644e31aef6aSopenharmony_ci filename: t.Optional[str] = None, 645e31aef6aSopenharmony_ci ) -> str: 646e31aef6aSopenharmony_ci """Preprocesses the source with all extensions. This is automatically 647e31aef6aSopenharmony_ci called for all parsing and compiling methods but *not* for :meth:`lex` 648e31aef6aSopenharmony_ci because there you usually only want the actual source tokenized. 649e31aef6aSopenharmony_ci """ 650e31aef6aSopenharmony_ci return reduce( 651e31aef6aSopenharmony_ci lambda s, e: e.preprocess(s, name, filename), 652e31aef6aSopenharmony_ci self.iter_extensions(), 653e31aef6aSopenharmony_ci str(source), 654e31aef6aSopenharmony_ci ) 655e31aef6aSopenharmony_ci 656e31aef6aSopenharmony_ci def _tokenize( 657e31aef6aSopenharmony_ci self, 658e31aef6aSopenharmony_ci source: str, 659e31aef6aSopenharmony_ci name: t.Optional[str], 660e31aef6aSopenharmony_ci filename: t.Optional[str] = None, 661e31aef6aSopenharmony_ci state: t.Optional[str] = None, 662e31aef6aSopenharmony_ci ) -> TokenStream: 663e31aef6aSopenharmony_ci """Called by the parser to do the preprocessing and filtering 664e31aef6aSopenharmony_ci for all the extensions. Returns a :class:`~jinja2.lexer.TokenStream`. 665e31aef6aSopenharmony_ci """ 666e31aef6aSopenharmony_ci source = self.preprocess(source, name, filename) 667e31aef6aSopenharmony_ci stream = self.lexer.tokenize(source, name, filename, state) 668e31aef6aSopenharmony_ci 669e31aef6aSopenharmony_ci for ext in self.iter_extensions(): 670e31aef6aSopenharmony_ci stream = ext.filter_stream(stream) # type: ignore 671e31aef6aSopenharmony_ci 672e31aef6aSopenharmony_ci if not isinstance(stream, TokenStream): 673e31aef6aSopenharmony_ci stream = TokenStream(stream, name, filename) # type: ignore 674e31aef6aSopenharmony_ci 675e31aef6aSopenharmony_ci return stream 676e31aef6aSopenharmony_ci 677e31aef6aSopenharmony_ci def _generate( 678e31aef6aSopenharmony_ci self, 679e31aef6aSopenharmony_ci source: nodes.Template, 680e31aef6aSopenharmony_ci name: t.Optional[str], 681e31aef6aSopenharmony_ci filename: t.Optional[str], 682e31aef6aSopenharmony_ci defer_init: bool = False, 683e31aef6aSopenharmony_ci ) -> str: 684e31aef6aSopenharmony_ci """Internal hook that can be overridden to hook a different generate 685e31aef6aSopenharmony_ci method in. 686e31aef6aSopenharmony_ci 687e31aef6aSopenharmony_ci .. versionadded:: 2.5 688e31aef6aSopenharmony_ci """ 689e31aef6aSopenharmony_ci return generate( # type: ignore 690e31aef6aSopenharmony_ci source, 691e31aef6aSopenharmony_ci self, 692e31aef6aSopenharmony_ci name, 693e31aef6aSopenharmony_ci filename, 694e31aef6aSopenharmony_ci defer_init=defer_init, 695e31aef6aSopenharmony_ci optimized=self.optimized, 696e31aef6aSopenharmony_ci ) 697e31aef6aSopenharmony_ci 698e31aef6aSopenharmony_ci def _compile(self, source: str, filename: str) -> CodeType: 699e31aef6aSopenharmony_ci """Internal hook that can be overridden to hook a different compile 700e31aef6aSopenharmony_ci method in. 701e31aef6aSopenharmony_ci 702e31aef6aSopenharmony_ci .. versionadded:: 2.5 703e31aef6aSopenharmony_ci """ 704e31aef6aSopenharmony_ci return compile(source, filename, "exec") 705e31aef6aSopenharmony_ci 706e31aef6aSopenharmony_ci @typing.overload 707e31aef6aSopenharmony_ci def compile( # type: ignore 708e31aef6aSopenharmony_ci self, 709e31aef6aSopenharmony_ci source: t.Union[str, nodes.Template], 710e31aef6aSopenharmony_ci name: t.Optional[str] = None, 711e31aef6aSopenharmony_ci filename: t.Optional[str] = None, 712e31aef6aSopenharmony_ci raw: "te.Literal[False]" = False, 713e31aef6aSopenharmony_ci defer_init: bool = False, 714e31aef6aSopenharmony_ci ) -> CodeType: 715e31aef6aSopenharmony_ci ... 716e31aef6aSopenharmony_ci 717e31aef6aSopenharmony_ci @typing.overload 718e31aef6aSopenharmony_ci def compile( 719e31aef6aSopenharmony_ci self, 720e31aef6aSopenharmony_ci source: t.Union[str, nodes.Template], 721e31aef6aSopenharmony_ci name: t.Optional[str] = None, 722e31aef6aSopenharmony_ci filename: t.Optional[str] = None, 723e31aef6aSopenharmony_ci raw: "te.Literal[True]" = ..., 724e31aef6aSopenharmony_ci defer_init: bool = False, 725e31aef6aSopenharmony_ci ) -> str: 726e31aef6aSopenharmony_ci ... 727e31aef6aSopenharmony_ci 728e31aef6aSopenharmony_ci @internalcode 729e31aef6aSopenharmony_ci def compile( 730e31aef6aSopenharmony_ci self, 731e31aef6aSopenharmony_ci source: t.Union[str, nodes.Template], 732e31aef6aSopenharmony_ci name: t.Optional[str] = None, 733e31aef6aSopenharmony_ci filename: t.Optional[str] = None, 734e31aef6aSopenharmony_ci raw: bool = False, 735e31aef6aSopenharmony_ci defer_init: bool = False, 736e31aef6aSopenharmony_ci ) -> t.Union[str, CodeType]: 737e31aef6aSopenharmony_ci """Compile a node or template source code. The `name` parameter is 738e31aef6aSopenharmony_ci the load name of the template after it was joined using 739e31aef6aSopenharmony_ci :meth:`join_path` if necessary, not the filename on the file system. 740e31aef6aSopenharmony_ci the `filename` parameter is the estimated filename of the template on 741e31aef6aSopenharmony_ci the file system. If the template came from a database or memory this 742e31aef6aSopenharmony_ci can be omitted. 743e31aef6aSopenharmony_ci 744e31aef6aSopenharmony_ci The return value of this method is a python code object. If the `raw` 745e31aef6aSopenharmony_ci parameter is `True` the return value will be a string with python 746e31aef6aSopenharmony_ci code equivalent to the bytecode returned otherwise. This method is 747e31aef6aSopenharmony_ci mainly used internally. 748e31aef6aSopenharmony_ci 749e31aef6aSopenharmony_ci `defer_init` is use internally to aid the module code generator. This 750e31aef6aSopenharmony_ci causes the generated code to be able to import without the global 751e31aef6aSopenharmony_ci environment variable to be set. 752e31aef6aSopenharmony_ci 753e31aef6aSopenharmony_ci .. versionadded:: 2.4 754e31aef6aSopenharmony_ci `defer_init` parameter added. 755e31aef6aSopenharmony_ci """ 756e31aef6aSopenharmony_ci source_hint = None 757e31aef6aSopenharmony_ci try: 758e31aef6aSopenharmony_ci if isinstance(source, str): 759e31aef6aSopenharmony_ci source_hint = source 760e31aef6aSopenharmony_ci source = self._parse(source, name, filename) 761e31aef6aSopenharmony_ci source = self._generate(source, name, filename, defer_init=defer_init) 762e31aef6aSopenharmony_ci if raw: 763e31aef6aSopenharmony_ci return source 764e31aef6aSopenharmony_ci if filename is None: 765e31aef6aSopenharmony_ci filename = "<template>" 766e31aef6aSopenharmony_ci return self._compile(source, filename) 767e31aef6aSopenharmony_ci except TemplateSyntaxError: 768e31aef6aSopenharmony_ci self.handle_exception(source=source_hint) 769e31aef6aSopenharmony_ci 770e31aef6aSopenharmony_ci def compile_expression( 771e31aef6aSopenharmony_ci self, source: str, undefined_to_none: bool = True 772e31aef6aSopenharmony_ci ) -> "TemplateExpression": 773e31aef6aSopenharmony_ci """A handy helper method that returns a callable that accepts keyword 774e31aef6aSopenharmony_ci arguments that appear as variables in the expression. If called it 775e31aef6aSopenharmony_ci returns the result of the expression. 776e31aef6aSopenharmony_ci 777e31aef6aSopenharmony_ci This is useful if applications want to use the same rules as Jinja 778e31aef6aSopenharmony_ci in template "configuration files" or similar situations. 779e31aef6aSopenharmony_ci 780e31aef6aSopenharmony_ci Example usage: 781e31aef6aSopenharmony_ci 782e31aef6aSopenharmony_ci >>> env = Environment() 783e31aef6aSopenharmony_ci >>> expr = env.compile_expression('foo == 42') 784e31aef6aSopenharmony_ci >>> expr(foo=23) 785e31aef6aSopenharmony_ci False 786e31aef6aSopenharmony_ci >>> expr(foo=42) 787e31aef6aSopenharmony_ci True 788e31aef6aSopenharmony_ci 789e31aef6aSopenharmony_ci Per default the return value is converted to `None` if the 790e31aef6aSopenharmony_ci expression returns an undefined value. This can be changed 791e31aef6aSopenharmony_ci by setting `undefined_to_none` to `False`. 792e31aef6aSopenharmony_ci 793e31aef6aSopenharmony_ci >>> env.compile_expression('var')() is None 794e31aef6aSopenharmony_ci True 795e31aef6aSopenharmony_ci >>> env.compile_expression('var', undefined_to_none=False)() 796e31aef6aSopenharmony_ci Undefined 797e31aef6aSopenharmony_ci 798e31aef6aSopenharmony_ci .. versionadded:: 2.1 799e31aef6aSopenharmony_ci """ 800e31aef6aSopenharmony_ci parser = Parser(self, source, state="variable") 801e31aef6aSopenharmony_ci try: 802e31aef6aSopenharmony_ci expr = parser.parse_expression() 803e31aef6aSopenharmony_ci if not parser.stream.eos: 804e31aef6aSopenharmony_ci raise TemplateSyntaxError( 805e31aef6aSopenharmony_ci "chunk after expression", parser.stream.current.lineno, None, None 806e31aef6aSopenharmony_ci ) 807e31aef6aSopenharmony_ci expr.set_environment(self) 808e31aef6aSopenharmony_ci except TemplateSyntaxError: 809e31aef6aSopenharmony_ci self.handle_exception(source=source) 810e31aef6aSopenharmony_ci 811e31aef6aSopenharmony_ci body = [nodes.Assign(nodes.Name("result", "store"), expr, lineno=1)] 812e31aef6aSopenharmony_ci template = self.from_string(nodes.Template(body, lineno=1)) 813e31aef6aSopenharmony_ci return TemplateExpression(template, undefined_to_none) 814e31aef6aSopenharmony_ci 815e31aef6aSopenharmony_ci def compile_templates( 816e31aef6aSopenharmony_ci self, 817e31aef6aSopenharmony_ci target: t.Union[str, os.PathLike], 818e31aef6aSopenharmony_ci extensions: t.Optional[t.Collection[str]] = None, 819e31aef6aSopenharmony_ci filter_func: t.Optional[t.Callable[[str], bool]] = None, 820e31aef6aSopenharmony_ci zip: t.Optional[str] = "deflated", 821e31aef6aSopenharmony_ci log_function: t.Optional[t.Callable[[str], None]] = None, 822e31aef6aSopenharmony_ci ignore_errors: bool = True, 823e31aef6aSopenharmony_ci ) -> None: 824e31aef6aSopenharmony_ci """Finds all the templates the loader can find, compiles them 825e31aef6aSopenharmony_ci and stores them in `target`. If `zip` is `None`, instead of in a 826e31aef6aSopenharmony_ci zipfile, the templates will be stored in a directory. 827e31aef6aSopenharmony_ci By default a deflate zip algorithm is used. To switch to 828e31aef6aSopenharmony_ci the stored algorithm, `zip` can be set to ``'stored'``. 829e31aef6aSopenharmony_ci 830e31aef6aSopenharmony_ci `extensions` and `filter_func` are passed to :meth:`list_templates`. 831e31aef6aSopenharmony_ci Each template returned will be compiled to the target folder or 832e31aef6aSopenharmony_ci zipfile. 833e31aef6aSopenharmony_ci 834e31aef6aSopenharmony_ci By default template compilation errors are ignored. In case a 835e31aef6aSopenharmony_ci log function is provided, errors are logged. If you want template 836e31aef6aSopenharmony_ci syntax errors to abort the compilation you can set `ignore_errors` 837e31aef6aSopenharmony_ci to `False` and you will get an exception on syntax errors. 838e31aef6aSopenharmony_ci 839e31aef6aSopenharmony_ci .. versionadded:: 2.4 840e31aef6aSopenharmony_ci """ 841e31aef6aSopenharmony_ci from .loaders import ModuleLoader 842e31aef6aSopenharmony_ci 843e31aef6aSopenharmony_ci if log_function is None: 844e31aef6aSopenharmony_ci 845e31aef6aSopenharmony_ci def log_function(x: str) -> None: 846e31aef6aSopenharmony_ci pass 847e31aef6aSopenharmony_ci 848e31aef6aSopenharmony_ci assert log_function is not None 849e31aef6aSopenharmony_ci assert self.loader is not None, "No loader configured." 850e31aef6aSopenharmony_ci 851e31aef6aSopenharmony_ci def write_file(filename: str, data: str) -> None: 852e31aef6aSopenharmony_ci if zip: 853e31aef6aSopenharmony_ci info = ZipInfo(filename) 854e31aef6aSopenharmony_ci info.external_attr = 0o755 << 16 855e31aef6aSopenharmony_ci zip_file.writestr(info, data) 856e31aef6aSopenharmony_ci else: 857e31aef6aSopenharmony_ci with open(os.path.join(target, filename), "wb") as f: 858e31aef6aSopenharmony_ci f.write(data.encode("utf8")) 859e31aef6aSopenharmony_ci 860e31aef6aSopenharmony_ci if zip is not None: 861e31aef6aSopenharmony_ci from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED, ZIP_STORED 862e31aef6aSopenharmony_ci 863e31aef6aSopenharmony_ci zip_file = ZipFile( 864e31aef6aSopenharmony_ci target, "w", dict(deflated=ZIP_DEFLATED, stored=ZIP_STORED)[zip] 865e31aef6aSopenharmony_ci ) 866e31aef6aSopenharmony_ci log_function(f"Compiling into Zip archive {target!r}") 867e31aef6aSopenharmony_ci else: 868e31aef6aSopenharmony_ci if not os.path.isdir(target): 869e31aef6aSopenharmony_ci os.makedirs(target) 870e31aef6aSopenharmony_ci log_function(f"Compiling into folder {target!r}") 871e31aef6aSopenharmony_ci 872e31aef6aSopenharmony_ci try: 873e31aef6aSopenharmony_ci for name in self.list_templates(extensions, filter_func): 874e31aef6aSopenharmony_ci source, filename, _ = self.loader.get_source(self, name) 875e31aef6aSopenharmony_ci try: 876e31aef6aSopenharmony_ci code = self.compile(source, name, filename, True, True) 877e31aef6aSopenharmony_ci except TemplateSyntaxError as e: 878e31aef6aSopenharmony_ci if not ignore_errors: 879e31aef6aSopenharmony_ci raise 880e31aef6aSopenharmony_ci log_function(f'Could not compile "{name}": {e}') 881e31aef6aSopenharmony_ci continue 882e31aef6aSopenharmony_ci 883e31aef6aSopenharmony_ci filename = ModuleLoader.get_module_filename(name) 884e31aef6aSopenharmony_ci 885e31aef6aSopenharmony_ci write_file(filename, code) 886e31aef6aSopenharmony_ci log_function(f'Compiled "{name}" as {filename}') 887e31aef6aSopenharmony_ci finally: 888e31aef6aSopenharmony_ci if zip: 889e31aef6aSopenharmony_ci zip_file.close() 890e31aef6aSopenharmony_ci 891e31aef6aSopenharmony_ci log_function("Finished compiling templates") 892e31aef6aSopenharmony_ci 893e31aef6aSopenharmony_ci def list_templates( 894e31aef6aSopenharmony_ci self, 895e31aef6aSopenharmony_ci extensions: t.Optional[t.Collection[str]] = None, 896e31aef6aSopenharmony_ci filter_func: t.Optional[t.Callable[[str], bool]] = None, 897e31aef6aSopenharmony_ci ) -> t.List[str]: 898e31aef6aSopenharmony_ci """Returns a list of templates for this environment. This requires 899e31aef6aSopenharmony_ci that the loader supports the loader's 900e31aef6aSopenharmony_ci :meth:`~BaseLoader.list_templates` method. 901e31aef6aSopenharmony_ci 902e31aef6aSopenharmony_ci If there are other files in the template folder besides the 903e31aef6aSopenharmony_ci actual templates, the returned list can be filtered. There are two 904e31aef6aSopenharmony_ci ways: either `extensions` is set to a list of file extensions for 905e31aef6aSopenharmony_ci templates, or a `filter_func` can be provided which is a callable that 906e31aef6aSopenharmony_ci is passed a template name and should return `True` if it should end up 907e31aef6aSopenharmony_ci in the result list. 908e31aef6aSopenharmony_ci 909e31aef6aSopenharmony_ci If the loader does not support that, a :exc:`TypeError` is raised. 910e31aef6aSopenharmony_ci 911e31aef6aSopenharmony_ci .. versionadded:: 2.4 912e31aef6aSopenharmony_ci """ 913e31aef6aSopenharmony_ci assert self.loader is not None, "No loader configured." 914e31aef6aSopenharmony_ci names = self.loader.list_templates() 915e31aef6aSopenharmony_ci 916e31aef6aSopenharmony_ci if extensions is not None: 917e31aef6aSopenharmony_ci if filter_func is not None: 918e31aef6aSopenharmony_ci raise TypeError( 919e31aef6aSopenharmony_ci "either extensions or filter_func can be passed, but not both" 920e31aef6aSopenharmony_ci ) 921e31aef6aSopenharmony_ci 922e31aef6aSopenharmony_ci def filter_func(x: str) -> bool: 923e31aef6aSopenharmony_ci return "." in x and x.rsplit(".", 1)[1] in extensions 924e31aef6aSopenharmony_ci 925e31aef6aSopenharmony_ci if filter_func is not None: 926e31aef6aSopenharmony_ci names = [name for name in names if filter_func(name)] 927e31aef6aSopenharmony_ci 928e31aef6aSopenharmony_ci return names 929e31aef6aSopenharmony_ci 930e31aef6aSopenharmony_ci def handle_exception(self, source: t.Optional[str] = None) -> "te.NoReturn": 931e31aef6aSopenharmony_ci """Exception handling helper. This is used internally to either raise 932e31aef6aSopenharmony_ci rewritten exceptions or return a rendered traceback for the template. 933e31aef6aSopenharmony_ci """ 934e31aef6aSopenharmony_ci from .debug import rewrite_traceback_stack 935e31aef6aSopenharmony_ci 936e31aef6aSopenharmony_ci raise rewrite_traceback_stack(source=source) 937e31aef6aSopenharmony_ci 938e31aef6aSopenharmony_ci def join_path(self, template: str, parent: str) -> str: 939e31aef6aSopenharmony_ci """Join a template with the parent. By default all the lookups are 940e31aef6aSopenharmony_ci relative to the loader root so this method returns the `template` 941e31aef6aSopenharmony_ci parameter unchanged, but if the paths should be relative to the 942e31aef6aSopenharmony_ci parent template, this function can be used to calculate the real 943e31aef6aSopenharmony_ci template name. 944e31aef6aSopenharmony_ci 945e31aef6aSopenharmony_ci Subclasses may override this method and implement template path 946e31aef6aSopenharmony_ci joining here. 947e31aef6aSopenharmony_ci """ 948e31aef6aSopenharmony_ci return template 949e31aef6aSopenharmony_ci 950e31aef6aSopenharmony_ci @internalcode 951e31aef6aSopenharmony_ci def _load_template( 952e31aef6aSopenharmony_ci self, name: str, globals: t.Optional[t.MutableMapping[str, t.Any]] 953e31aef6aSopenharmony_ci ) -> "Template": 954e31aef6aSopenharmony_ci if self.loader is None: 955e31aef6aSopenharmony_ci raise TypeError("no loader for this environment specified") 956e31aef6aSopenharmony_ci cache_key = (weakref.ref(self.loader), name) 957e31aef6aSopenharmony_ci if self.cache is not None: 958e31aef6aSopenharmony_ci template = self.cache.get(cache_key) 959e31aef6aSopenharmony_ci if template is not None and ( 960e31aef6aSopenharmony_ci not self.auto_reload or template.is_up_to_date 961e31aef6aSopenharmony_ci ): 962e31aef6aSopenharmony_ci # template.globals is a ChainMap, modifying it will only 963e31aef6aSopenharmony_ci # affect the template, not the environment globals. 964e31aef6aSopenharmony_ci if globals: 965e31aef6aSopenharmony_ci template.globals.update(globals) 966e31aef6aSopenharmony_ci 967e31aef6aSopenharmony_ci return template 968e31aef6aSopenharmony_ci 969e31aef6aSopenharmony_ci template = self.loader.load(self, name, self.make_globals(globals)) 970e31aef6aSopenharmony_ci 971e31aef6aSopenharmony_ci if self.cache is not None: 972e31aef6aSopenharmony_ci self.cache[cache_key] = template 973e31aef6aSopenharmony_ci return template 974e31aef6aSopenharmony_ci 975e31aef6aSopenharmony_ci @internalcode 976e31aef6aSopenharmony_ci def get_template( 977e31aef6aSopenharmony_ci self, 978e31aef6aSopenharmony_ci name: t.Union[str, "Template"], 979e31aef6aSopenharmony_ci parent: t.Optional[str] = None, 980e31aef6aSopenharmony_ci globals: t.Optional[t.MutableMapping[str, t.Any]] = None, 981e31aef6aSopenharmony_ci ) -> "Template": 982e31aef6aSopenharmony_ci """Load a template by name with :attr:`loader` and return a 983e31aef6aSopenharmony_ci :class:`Template`. If the template does not exist a 984e31aef6aSopenharmony_ci :exc:`TemplateNotFound` exception is raised. 985e31aef6aSopenharmony_ci 986e31aef6aSopenharmony_ci :param name: Name of the template to load. When loading 987e31aef6aSopenharmony_ci templates from the filesystem, "/" is used as the path 988e31aef6aSopenharmony_ci separator, even on Windows. 989e31aef6aSopenharmony_ci :param parent: The name of the parent template importing this 990e31aef6aSopenharmony_ci template. :meth:`join_path` can be used to implement name 991e31aef6aSopenharmony_ci transformations with this. 992e31aef6aSopenharmony_ci :param globals: Extend the environment :attr:`globals` with 993e31aef6aSopenharmony_ci these extra variables available for all renders of this 994e31aef6aSopenharmony_ci template. If the template has already been loaded and 995e31aef6aSopenharmony_ci cached, its globals are updated with any new items. 996e31aef6aSopenharmony_ci 997e31aef6aSopenharmony_ci .. versionchanged:: 3.0 998e31aef6aSopenharmony_ci If a template is loaded from cache, ``globals`` will update 999e31aef6aSopenharmony_ci the template's globals instead of ignoring the new values. 1000e31aef6aSopenharmony_ci 1001e31aef6aSopenharmony_ci .. versionchanged:: 2.4 1002e31aef6aSopenharmony_ci If ``name`` is a :class:`Template` object it is returned 1003e31aef6aSopenharmony_ci unchanged. 1004e31aef6aSopenharmony_ci """ 1005e31aef6aSopenharmony_ci if isinstance(name, Template): 1006e31aef6aSopenharmony_ci return name 1007e31aef6aSopenharmony_ci if parent is not None: 1008e31aef6aSopenharmony_ci name = self.join_path(name, parent) 1009e31aef6aSopenharmony_ci 1010e31aef6aSopenharmony_ci return self._load_template(name, globals) 1011e31aef6aSopenharmony_ci 1012e31aef6aSopenharmony_ci @internalcode 1013e31aef6aSopenharmony_ci def select_template( 1014e31aef6aSopenharmony_ci self, 1015e31aef6aSopenharmony_ci names: t.Iterable[t.Union[str, "Template"]], 1016e31aef6aSopenharmony_ci parent: t.Optional[str] = None, 1017e31aef6aSopenharmony_ci globals: t.Optional[t.MutableMapping[str, t.Any]] = None, 1018e31aef6aSopenharmony_ci ) -> "Template": 1019e31aef6aSopenharmony_ci """Like :meth:`get_template`, but tries loading multiple names. 1020e31aef6aSopenharmony_ci If none of the names can be loaded a :exc:`TemplatesNotFound` 1021e31aef6aSopenharmony_ci exception is raised. 1022e31aef6aSopenharmony_ci 1023e31aef6aSopenharmony_ci :param names: List of template names to try loading in order. 1024e31aef6aSopenharmony_ci :param parent: The name of the parent template importing this 1025e31aef6aSopenharmony_ci template. :meth:`join_path` can be used to implement name 1026e31aef6aSopenharmony_ci transformations with this. 1027e31aef6aSopenharmony_ci :param globals: Extend the environment :attr:`globals` with 1028e31aef6aSopenharmony_ci these extra variables available for all renders of this 1029e31aef6aSopenharmony_ci template. If the template has already been loaded and 1030e31aef6aSopenharmony_ci cached, its globals are updated with any new items. 1031e31aef6aSopenharmony_ci 1032e31aef6aSopenharmony_ci .. versionchanged:: 3.0 1033e31aef6aSopenharmony_ci If a template is loaded from cache, ``globals`` will update 1034e31aef6aSopenharmony_ci the template's globals instead of ignoring the new values. 1035e31aef6aSopenharmony_ci 1036e31aef6aSopenharmony_ci .. versionchanged:: 2.11 1037e31aef6aSopenharmony_ci If ``names`` is :class:`Undefined`, an :exc:`UndefinedError` 1038e31aef6aSopenharmony_ci is raised instead. If no templates were found and ``names`` 1039e31aef6aSopenharmony_ci contains :class:`Undefined`, the message is more helpful. 1040e31aef6aSopenharmony_ci 1041e31aef6aSopenharmony_ci .. versionchanged:: 2.4 1042e31aef6aSopenharmony_ci If ``names`` contains a :class:`Template` object it is 1043e31aef6aSopenharmony_ci returned unchanged. 1044e31aef6aSopenharmony_ci 1045e31aef6aSopenharmony_ci .. versionadded:: 2.3 1046e31aef6aSopenharmony_ci """ 1047e31aef6aSopenharmony_ci if isinstance(names, Undefined): 1048e31aef6aSopenharmony_ci names._fail_with_undefined_error() 1049e31aef6aSopenharmony_ci 1050e31aef6aSopenharmony_ci if not names: 1051e31aef6aSopenharmony_ci raise TemplatesNotFound( 1052e31aef6aSopenharmony_ci message="Tried to select from an empty list of templates." 1053e31aef6aSopenharmony_ci ) 1054e31aef6aSopenharmony_ci 1055e31aef6aSopenharmony_ci for name in names: 1056e31aef6aSopenharmony_ci if isinstance(name, Template): 1057e31aef6aSopenharmony_ci return name 1058e31aef6aSopenharmony_ci if parent is not None: 1059e31aef6aSopenharmony_ci name = self.join_path(name, parent) 1060e31aef6aSopenharmony_ci try: 1061e31aef6aSopenharmony_ci return self._load_template(name, globals) 1062e31aef6aSopenharmony_ci except (TemplateNotFound, UndefinedError): 1063e31aef6aSopenharmony_ci pass 1064e31aef6aSopenharmony_ci raise TemplatesNotFound(names) # type: ignore 1065e31aef6aSopenharmony_ci 1066e31aef6aSopenharmony_ci @internalcode 1067e31aef6aSopenharmony_ci def get_or_select_template( 1068e31aef6aSopenharmony_ci self, 1069e31aef6aSopenharmony_ci template_name_or_list: t.Union[ 1070e31aef6aSopenharmony_ci str, "Template", t.List[t.Union[str, "Template"]] 1071e31aef6aSopenharmony_ci ], 1072e31aef6aSopenharmony_ci parent: t.Optional[str] = None, 1073e31aef6aSopenharmony_ci globals: t.Optional[t.MutableMapping[str, t.Any]] = None, 1074e31aef6aSopenharmony_ci ) -> "Template": 1075e31aef6aSopenharmony_ci """Use :meth:`select_template` if an iterable of template names 1076e31aef6aSopenharmony_ci is given, or :meth:`get_template` if one name is given. 1077e31aef6aSopenharmony_ci 1078e31aef6aSopenharmony_ci .. versionadded:: 2.3 1079e31aef6aSopenharmony_ci """ 1080e31aef6aSopenharmony_ci if isinstance(template_name_or_list, (str, Undefined)): 1081e31aef6aSopenharmony_ci return self.get_template(template_name_or_list, parent, globals) 1082e31aef6aSopenharmony_ci elif isinstance(template_name_or_list, Template): 1083e31aef6aSopenharmony_ci return template_name_or_list 1084e31aef6aSopenharmony_ci return self.select_template(template_name_or_list, parent, globals) 1085e31aef6aSopenharmony_ci 1086e31aef6aSopenharmony_ci def from_string( 1087e31aef6aSopenharmony_ci self, 1088e31aef6aSopenharmony_ci source: t.Union[str, nodes.Template], 1089e31aef6aSopenharmony_ci globals: t.Optional[t.MutableMapping[str, t.Any]] = None, 1090e31aef6aSopenharmony_ci template_class: t.Optional[t.Type["Template"]] = None, 1091e31aef6aSopenharmony_ci ) -> "Template": 1092e31aef6aSopenharmony_ci """Load a template from a source string without using 1093e31aef6aSopenharmony_ci :attr:`loader`. 1094e31aef6aSopenharmony_ci 1095e31aef6aSopenharmony_ci :param source: Jinja source to compile into a template. 1096e31aef6aSopenharmony_ci :param globals: Extend the environment :attr:`globals` with 1097e31aef6aSopenharmony_ci these extra variables available for all renders of this 1098e31aef6aSopenharmony_ci template. If the template has already been loaded and 1099e31aef6aSopenharmony_ci cached, its globals are updated with any new items. 1100e31aef6aSopenharmony_ci :param template_class: Return an instance of this 1101e31aef6aSopenharmony_ci :class:`Template` class. 1102e31aef6aSopenharmony_ci """ 1103e31aef6aSopenharmony_ci gs = self.make_globals(globals) 1104e31aef6aSopenharmony_ci cls = template_class or self.template_class 1105e31aef6aSopenharmony_ci return cls.from_code(self, self.compile(source), gs, None) 1106e31aef6aSopenharmony_ci 1107e31aef6aSopenharmony_ci def make_globals( 1108e31aef6aSopenharmony_ci self, d: t.Optional[t.MutableMapping[str, t.Any]] 1109e31aef6aSopenharmony_ci ) -> t.MutableMapping[str, t.Any]: 1110e31aef6aSopenharmony_ci """Make the globals map for a template. Any given template 1111e31aef6aSopenharmony_ci globals overlay the environment :attr:`globals`. 1112e31aef6aSopenharmony_ci 1113e31aef6aSopenharmony_ci Returns a :class:`collections.ChainMap`. This allows any changes 1114e31aef6aSopenharmony_ci to a template's globals to only affect that template, while 1115e31aef6aSopenharmony_ci changes to the environment's globals are still reflected. 1116e31aef6aSopenharmony_ci However, avoid modifying any globals after a template is loaded. 1117e31aef6aSopenharmony_ci 1118e31aef6aSopenharmony_ci :param d: Dict of template-specific globals. 1119e31aef6aSopenharmony_ci 1120e31aef6aSopenharmony_ci .. versionchanged:: 3.0 1121e31aef6aSopenharmony_ci Use :class:`collections.ChainMap` to always prevent mutating 1122e31aef6aSopenharmony_ci environment globals. 1123e31aef6aSopenharmony_ci """ 1124e31aef6aSopenharmony_ci if d is None: 1125e31aef6aSopenharmony_ci d = {} 1126e31aef6aSopenharmony_ci 1127e31aef6aSopenharmony_ci return ChainMap(d, self.globals) 1128e31aef6aSopenharmony_ci 1129e31aef6aSopenharmony_ci 1130e31aef6aSopenharmony_ciclass Template: 1131e31aef6aSopenharmony_ci """A compiled template that can be rendered. 1132e31aef6aSopenharmony_ci 1133e31aef6aSopenharmony_ci Use the methods on :class:`Environment` to create or load templates. 1134e31aef6aSopenharmony_ci The environment is used to configure how templates are compiled and 1135e31aef6aSopenharmony_ci behave. 1136e31aef6aSopenharmony_ci 1137e31aef6aSopenharmony_ci It is also possible to create a template object directly. This is 1138e31aef6aSopenharmony_ci not usually recommended. The constructor takes most of the same 1139e31aef6aSopenharmony_ci arguments as :class:`Environment`. All templates created with the 1140e31aef6aSopenharmony_ci same environment arguments share the same ephemeral ``Environment`` 1141e31aef6aSopenharmony_ci instance behind the scenes. 1142e31aef6aSopenharmony_ci 1143e31aef6aSopenharmony_ci A template object should be considered immutable. Modifications on 1144e31aef6aSopenharmony_ci the object are not supported. 1145e31aef6aSopenharmony_ci """ 1146e31aef6aSopenharmony_ci 1147e31aef6aSopenharmony_ci #: Type of environment to create when creating a template directly 1148e31aef6aSopenharmony_ci #: rather than through an existing environment. 1149e31aef6aSopenharmony_ci environment_class: t.Type[Environment] = Environment 1150e31aef6aSopenharmony_ci 1151e31aef6aSopenharmony_ci environment: Environment 1152e31aef6aSopenharmony_ci globals: t.MutableMapping[str, t.Any] 1153e31aef6aSopenharmony_ci name: t.Optional[str] 1154e31aef6aSopenharmony_ci filename: t.Optional[str] 1155e31aef6aSopenharmony_ci blocks: t.Dict[str, t.Callable[[Context], t.Iterator[str]]] 1156e31aef6aSopenharmony_ci root_render_func: t.Callable[[Context], t.Iterator[str]] 1157e31aef6aSopenharmony_ci _module: t.Optional["TemplateModule"] 1158e31aef6aSopenharmony_ci _debug_info: str 1159e31aef6aSopenharmony_ci _uptodate: t.Optional[t.Callable[[], bool]] 1160e31aef6aSopenharmony_ci 1161e31aef6aSopenharmony_ci def __new__( 1162e31aef6aSopenharmony_ci cls, 1163e31aef6aSopenharmony_ci source: t.Union[str, nodes.Template], 1164e31aef6aSopenharmony_ci block_start_string: str = BLOCK_START_STRING, 1165e31aef6aSopenharmony_ci block_end_string: str = BLOCK_END_STRING, 1166e31aef6aSopenharmony_ci variable_start_string: str = VARIABLE_START_STRING, 1167e31aef6aSopenharmony_ci variable_end_string: str = VARIABLE_END_STRING, 1168e31aef6aSopenharmony_ci comment_start_string: str = COMMENT_START_STRING, 1169e31aef6aSopenharmony_ci comment_end_string: str = COMMENT_END_STRING, 1170e31aef6aSopenharmony_ci line_statement_prefix: t.Optional[str] = LINE_STATEMENT_PREFIX, 1171e31aef6aSopenharmony_ci line_comment_prefix: t.Optional[str] = LINE_COMMENT_PREFIX, 1172e31aef6aSopenharmony_ci trim_blocks: bool = TRIM_BLOCKS, 1173e31aef6aSopenharmony_ci lstrip_blocks: bool = LSTRIP_BLOCKS, 1174e31aef6aSopenharmony_ci newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = NEWLINE_SEQUENCE, 1175e31aef6aSopenharmony_ci keep_trailing_newline: bool = KEEP_TRAILING_NEWLINE, 1176e31aef6aSopenharmony_ci extensions: t.Sequence[t.Union[str, t.Type["Extension"]]] = (), 1177e31aef6aSopenharmony_ci optimized: bool = True, 1178e31aef6aSopenharmony_ci undefined: t.Type[Undefined] = Undefined, 1179e31aef6aSopenharmony_ci finalize: t.Optional[t.Callable[..., t.Any]] = None, 1180e31aef6aSopenharmony_ci autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = False, 1181e31aef6aSopenharmony_ci enable_async: bool = False, 1182e31aef6aSopenharmony_ci ) -> t.Any: # it returns a `Template`, but this breaks the sphinx build... 1183e31aef6aSopenharmony_ci env = get_spontaneous_environment( 1184e31aef6aSopenharmony_ci cls.environment_class, # type: ignore 1185e31aef6aSopenharmony_ci block_start_string, 1186e31aef6aSopenharmony_ci block_end_string, 1187e31aef6aSopenharmony_ci variable_start_string, 1188e31aef6aSopenharmony_ci variable_end_string, 1189e31aef6aSopenharmony_ci comment_start_string, 1190e31aef6aSopenharmony_ci comment_end_string, 1191e31aef6aSopenharmony_ci line_statement_prefix, 1192e31aef6aSopenharmony_ci line_comment_prefix, 1193e31aef6aSopenharmony_ci trim_blocks, 1194e31aef6aSopenharmony_ci lstrip_blocks, 1195e31aef6aSopenharmony_ci newline_sequence, 1196e31aef6aSopenharmony_ci keep_trailing_newline, 1197e31aef6aSopenharmony_ci frozenset(extensions), 1198e31aef6aSopenharmony_ci optimized, 1199e31aef6aSopenharmony_ci undefined, # type: ignore 1200e31aef6aSopenharmony_ci finalize, 1201e31aef6aSopenharmony_ci autoescape, 1202e31aef6aSopenharmony_ci None, 1203e31aef6aSopenharmony_ci 0, 1204e31aef6aSopenharmony_ci False, 1205e31aef6aSopenharmony_ci None, 1206e31aef6aSopenharmony_ci enable_async, 1207e31aef6aSopenharmony_ci ) 1208e31aef6aSopenharmony_ci return env.from_string(source, template_class=cls) 1209e31aef6aSopenharmony_ci 1210e31aef6aSopenharmony_ci @classmethod 1211e31aef6aSopenharmony_ci def from_code( 1212e31aef6aSopenharmony_ci cls, 1213e31aef6aSopenharmony_ci environment: Environment, 1214e31aef6aSopenharmony_ci code: CodeType, 1215e31aef6aSopenharmony_ci globals: t.MutableMapping[str, t.Any], 1216e31aef6aSopenharmony_ci uptodate: t.Optional[t.Callable[[], bool]] = None, 1217e31aef6aSopenharmony_ci ) -> "Template": 1218e31aef6aSopenharmony_ci """Creates a template object from compiled code and the globals. This 1219e31aef6aSopenharmony_ci is used by the loaders and environment to create a template object. 1220e31aef6aSopenharmony_ci """ 1221e31aef6aSopenharmony_ci namespace = {"environment": environment, "__file__": code.co_filename} 1222e31aef6aSopenharmony_ci exec(code, namespace) 1223e31aef6aSopenharmony_ci rv = cls._from_namespace(environment, namespace, globals) 1224e31aef6aSopenharmony_ci rv._uptodate = uptodate 1225e31aef6aSopenharmony_ci return rv 1226e31aef6aSopenharmony_ci 1227e31aef6aSopenharmony_ci @classmethod 1228e31aef6aSopenharmony_ci def from_module_dict( 1229e31aef6aSopenharmony_ci cls, 1230e31aef6aSopenharmony_ci environment: Environment, 1231e31aef6aSopenharmony_ci module_dict: t.MutableMapping[str, t.Any], 1232e31aef6aSopenharmony_ci globals: t.MutableMapping[str, t.Any], 1233e31aef6aSopenharmony_ci ) -> "Template": 1234e31aef6aSopenharmony_ci """Creates a template object from a module. This is used by the 1235e31aef6aSopenharmony_ci module loader to create a template object. 1236e31aef6aSopenharmony_ci 1237e31aef6aSopenharmony_ci .. versionadded:: 2.4 1238e31aef6aSopenharmony_ci """ 1239e31aef6aSopenharmony_ci return cls._from_namespace(environment, module_dict, globals) 1240e31aef6aSopenharmony_ci 1241e31aef6aSopenharmony_ci @classmethod 1242e31aef6aSopenharmony_ci def _from_namespace( 1243e31aef6aSopenharmony_ci cls, 1244e31aef6aSopenharmony_ci environment: Environment, 1245e31aef6aSopenharmony_ci namespace: t.MutableMapping[str, t.Any], 1246e31aef6aSopenharmony_ci globals: t.MutableMapping[str, t.Any], 1247e31aef6aSopenharmony_ci ) -> "Template": 1248e31aef6aSopenharmony_ci t: "Template" = object.__new__(cls) 1249e31aef6aSopenharmony_ci t.environment = environment 1250e31aef6aSopenharmony_ci t.globals = globals 1251e31aef6aSopenharmony_ci t.name = namespace["name"] 1252e31aef6aSopenharmony_ci t.filename = namespace["__file__"] 1253e31aef6aSopenharmony_ci t.blocks = namespace["blocks"] 1254e31aef6aSopenharmony_ci 1255e31aef6aSopenharmony_ci # render function and module 1256e31aef6aSopenharmony_ci t.root_render_func = namespace["root"] 1257e31aef6aSopenharmony_ci t._module = None 1258e31aef6aSopenharmony_ci 1259e31aef6aSopenharmony_ci # debug and loader helpers 1260e31aef6aSopenharmony_ci t._debug_info = namespace["debug_info"] 1261e31aef6aSopenharmony_ci t._uptodate = None 1262e31aef6aSopenharmony_ci 1263e31aef6aSopenharmony_ci # store the reference 1264e31aef6aSopenharmony_ci namespace["environment"] = environment 1265e31aef6aSopenharmony_ci namespace["__jinja_template__"] = t 1266e31aef6aSopenharmony_ci 1267e31aef6aSopenharmony_ci return t 1268e31aef6aSopenharmony_ci 1269e31aef6aSopenharmony_ci def render(self, *args: t.Any, **kwargs: t.Any) -> str: 1270e31aef6aSopenharmony_ci """This method accepts the same arguments as the `dict` constructor: 1271e31aef6aSopenharmony_ci A dict, a dict subclass or some keyword arguments. If no arguments 1272e31aef6aSopenharmony_ci are given the context will be empty. These two calls do the same:: 1273e31aef6aSopenharmony_ci 1274e31aef6aSopenharmony_ci template.render(knights='that say nih') 1275e31aef6aSopenharmony_ci template.render({'knights': 'that say nih'}) 1276e31aef6aSopenharmony_ci 1277e31aef6aSopenharmony_ci This will return the rendered template as a string. 1278e31aef6aSopenharmony_ci """ 1279e31aef6aSopenharmony_ci if self.environment.is_async: 1280e31aef6aSopenharmony_ci import asyncio 1281e31aef6aSopenharmony_ci 1282e31aef6aSopenharmony_ci close = False 1283e31aef6aSopenharmony_ci 1284e31aef6aSopenharmony_ci try: 1285e31aef6aSopenharmony_ci loop = asyncio.get_running_loop() 1286e31aef6aSopenharmony_ci except RuntimeError: 1287e31aef6aSopenharmony_ci loop = asyncio.new_event_loop() 1288e31aef6aSopenharmony_ci close = True 1289e31aef6aSopenharmony_ci 1290e31aef6aSopenharmony_ci try: 1291e31aef6aSopenharmony_ci return loop.run_until_complete(self.render_async(*args, **kwargs)) 1292e31aef6aSopenharmony_ci finally: 1293e31aef6aSopenharmony_ci if close: 1294e31aef6aSopenharmony_ci loop.close() 1295e31aef6aSopenharmony_ci 1296e31aef6aSopenharmony_ci ctx = self.new_context(dict(*args, **kwargs)) 1297e31aef6aSopenharmony_ci 1298e31aef6aSopenharmony_ci try: 1299e31aef6aSopenharmony_ci return self.environment.concat(self.root_render_func(ctx)) # type: ignore 1300e31aef6aSopenharmony_ci except Exception: 1301e31aef6aSopenharmony_ci self.environment.handle_exception() 1302e31aef6aSopenharmony_ci 1303e31aef6aSopenharmony_ci async def render_async(self, *args: t.Any, **kwargs: t.Any) -> str: 1304e31aef6aSopenharmony_ci """This works similar to :meth:`render` but returns a coroutine 1305e31aef6aSopenharmony_ci that when awaited returns the entire rendered template string. This 1306e31aef6aSopenharmony_ci requires the async feature to be enabled. 1307e31aef6aSopenharmony_ci 1308e31aef6aSopenharmony_ci Example usage:: 1309e31aef6aSopenharmony_ci 1310e31aef6aSopenharmony_ci await template.render_async(knights='that say nih; asynchronously') 1311e31aef6aSopenharmony_ci """ 1312e31aef6aSopenharmony_ci if not self.environment.is_async: 1313e31aef6aSopenharmony_ci raise RuntimeError( 1314e31aef6aSopenharmony_ci "The environment was not created with async mode enabled." 1315e31aef6aSopenharmony_ci ) 1316e31aef6aSopenharmony_ci 1317e31aef6aSopenharmony_ci ctx = self.new_context(dict(*args, **kwargs)) 1318e31aef6aSopenharmony_ci 1319e31aef6aSopenharmony_ci try: 1320e31aef6aSopenharmony_ci return self.environment.concat( # type: ignore 1321e31aef6aSopenharmony_ci [n async for n in self.root_render_func(ctx)] # type: ignore 1322e31aef6aSopenharmony_ci ) 1323e31aef6aSopenharmony_ci except Exception: 1324e31aef6aSopenharmony_ci return self.environment.handle_exception() 1325e31aef6aSopenharmony_ci 1326e31aef6aSopenharmony_ci def stream(self, *args: t.Any, **kwargs: t.Any) -> "TemplateStream": 1327e31aef6aSopenharmony_ci """Works exactly like :meth:`generate` but returns a 1328e31aef6aSopenharmony_ci :class:`TemplateStream`. 1329e31aef6aSopenharmony_ci """ 1330e31aef6aSopenharmony_ci return TemplateStream(self.generate(*args, **kwargs)) 1331e31aef6aSopenharmony_ci 1332e31aef6aSopenharmony_ci def generate(self, *args: t.Any, **kwargs: t.Any) -> t.Iterator[str]: 1333e31aef6aSopenharmony_ci """For very large templates it can be useful to not render the whole 1334e31aef6aSopenharmony_ci template at once but evaluate each statement after another and yield 1335e31aef6aSopenharmony_ci piece for piece. This method basically does exactly that and returns 1336e31aef6aSopenharmony_ci a generator that yields one item after another as strings. 1337e31aef6aSopenharmony_ci 1338e31aef6aSopenharmony_ci It accepts the same arguments as :meth:`render`. 1339e31aef6aSopenharmony_ci """ 1340e31aef6aSopenharmony_ci if self.environment.is_async: 1341e31aef6aSopenharmony_ci import asyncio 1342e31aef6aSopenharmony_ci 1343e31aef6aSopenharmony_ci async def to_list() -> t.List[str]: 1344e31aef6aSopenharmony_ci return [x async for x in self.generate_async(*args, **kwargs)] 1345e31aef6aSopenharmony_ci 1346e31aef6aSopenharmony_ci yield from asyncio.run(to_list()) 1347e31aef6aSopenharmony_ci return 1348e31aef6aSopenharmony_ci 1349e31aef6aSopenharmony_ci ctx = self.new_context(dict(*args, **kwargs)) 1350e31aef6aSopenharmony_ci 1351e31aef6aSopenharmony_ci try: 1352e31aef6aSopenharmony_ci yield from self.root_render_func(ctx) 1353e31aef6aSopenharmony_ci except Exception: 1354e31aef6aSopenharmony_ci yield self.environment.handle_exception() 1355e31aef6aSopenharmony_ci 1356e31aef6aSopenharmony_ci async def generate_async( 1357e31aef6aSopenharmony_ci self, *args: t.Any, **kwargs: t.Any 1358e31aef6aSopenharmony_ci ) -> t.AsyncIterator[str]: 1359e31aef6aSopenharmony_ci """An async version of :meth:`generate`. Works very similarly but 1360e31aef6aSopenharmony_ci returns an async iterator instead. 1361e31aef6aSopenharmony_ci """ 1362e31aef6aSopenharmony_ci if not self.environment.is_async: 1363e31aef6aSopenharmony_ci raise RuntimeError( 1364e31aef6aSopenharmony_ci "The environment was not created with async mode enabled." 1365e31aef6aSopenharmony_ci ) 1366e31aef6aSopenharmony_ci 1367e31aef6aSopenharmony_ci ctx = self.new_context(dict(*args, **kwargs)) 1368e31aef6aSopenharmony_ci 1369e31aef6aSopenharmony_ci try: 1370e31aef6aSopenharmony_ci async for event in self.root_render_func(ctx): # type: ignore 1371e31aef6aSopenharmony_ci yield event 1372e31aef6aSopenharmony_ci except Exception: 1373e31aef6aSopenharmony_ci yield self.environment.handle_exception() 1374e31aef6aSopenharmony_ci 1375e31aef6aSopenharmony_ci def new_context( 1376e31aef6aSopenharmony_ci self, 1377e31aef6aSopenharmony_ci vars: t.Optional[t.Dict[str, t.Any]] = None, 1378e31aef6aSopenharmony_ci shared: bool = False, 1379e31aef6aSopenharmony_ci locals: t.Optional[t.Mapping[str, t.Any]] = None, 1380e31aef6aSopenharmony_ci ) -> Context: 1381e31aef6aSopenharmony_ci """Create a new :class:`Context` for this template. The vars 1382e31aef6aSopenharmony_ci provided will be passed to the template. Per default the globals 1383e31aef6aSopenharmony_ci are added to the context. If shared is set to `True` the data 1384e31aef6aSopenharmony_ci is passed as is to the context without adding the globals. 1385e31aef6aSopenharmony_ci 1386e31aef6aSopenharmony_ci `locals` can be a dict of local variables for internal usage. 1387e31aef6aSopenharmony_ci """ 1388e31aef6aSopenharmony_ci return new_context( 1389e31aef6aSopenharmony_ci self.environment, self.name, self.blocks, vars, shared, self.globals, locals 1390e31aef6aSopenharmony_ci ) 1391e31aef6aSopenharmony_ci 1392e31aef6aSopenharmony_ci def make_module( 1393e31aef6aSopenharmony_ci self, 1394e31aef6aSopenharmony_ci vars: t.Optional[t.Dict[str, t.Any]] = None, 1395e31aef6aSopenharmony_ci shared: bool = False, 1396e31aef6aSopenharmony_ci locals: t.Optional[t.Mapping[str, t.Any]] = None, 1397e31aef6aSopenharmony_ci ) -> "TemplateModule": 1398e31aef6aSopenharmony_ci """This method works like the :attr:`module` attribute when called 1399e31aef6aSopenharmony_ci without arguments but it will evaluate the template on every call 1400e31aef6aSopenharmony_ci rather than caching it. It's also possible to provide 1401e31aef6aSopenharmony_ci a dict which is then used as context. The arguments are the same 1402e31aef6aSopenharmony_ci as for the :meth:`new_context` method. 1403e31aef6aSopenharmony_ci """ 1404e31aef6aSopenharmony_ci ctx = self.new_context(vars, shared, locals) 1405e31aef6aSopenharmony_ci return TemplateModule(self, ctx) 1406e31aef6aSopenharmony_ci 1407e31aef6aSopenharmony_ci async def make_module_async( 1408e31aef6aSopenharmony_ci self, 1409e31aef6aSopenharmony_ci vars: t.Optional[t.Dict[str, t.Any]] = None, 1410e31aef6aSopenharmony_ci shared: bool = False, 1411e31aef6aSopenharmony_ci locals: t.Optional[t.Mapping[str, t.Any]] = None, 1412e31aef6aSopenharmony_ci ) -> "TemplateModule": 1413e31aef6aSopenharmony_ci """As template module creation can invoke template code for 1414e31aef6aSopenharmony_ci asynchronous executions this method must be used instead of the 1415e31aef6aSopenharmony_ci normal :meth:`make_module` one. Likewise the module attribute 1416e31aef6aSopenharmony_ci becomes unavailable in async mode. 1417e31aef6aSopenharmony_ci """ 1418e31aef6aSopenharmony_ci ctx = self.new_context(vars, shared, locals) 1419e31aef6aSopenharmony_ci return TemplateModule( 1420e31aef6aSopenharmony_ci self, ctx, [x async for x in self.root_render_func(ctx)] # type: ignore 1421e31aef6aSopenharmony_ci ) 1422e31aef6aSopenharmony_ci 1423e31aef6aSopenharmony_ci @internalcode 1424e31aef6aSopenharmony_ci def _get_default_module(self, ctx: t.Optional[Context] = None) -> "TemplateModule": 1425e31aef6aSopenharmony_ci """If a context is passed in, this means that the template was 1426e31aef6aSopenharmony_ci imported. Imported templates have access to the current 1427e31aef6aSopenharmony_ci template's globals by default, but they can only be accessed via 1428e31aef6aSopenharmony_ci the context during runtime. 1429e31aef6aSopenharmony_ci 1430e31aef6aSopenharmony_ci If there are new globals, we need to create a new module because 1431e31aef6aSopenharmony_ci the cached module is already rendered and will not have access 1432e31aef6aSopenharmony_ci to globals from the current context. This new module is not 1433e31aef6aSopenharmony_ci cached because the template can be imported elsewhere, and it 1434e31aef6aSopenharmony_ci should have access to only the current template's globals. 1435e31aef6aSopenharmony_ci """ 1436e31aef6aSopenharmony_ci if self.environment.is_async: 1437e31aef6aSopenharmony_ci raise RuntimeError("Module is not available in async mode.") 1438e31aef6aSopenharmony_ci 1439e31aef6aSopenharmony_ci if ctx is not None: 1440e31aef6aSopenharmony_ci keys = ctx.globals_keys - self.globals.keys() 1441e31aef6aSopenharmony_ci 1442e31aef6aSopenharmony_ci if keys: 1443e31aef6aSopenharmony_ci return self.make_module({k: ctx.parent[k] for k in keys}) 1444e31aef6aSopenharmony_ci 1445e31aef6aSopenharmony_ci if self._module is None: 1446e31aef6aSopenharmony_ci self._module = self.make_module() 1447e31aef6aSopenharmony_ci 1448e31aef6aSopenharmony_ci return self._module 1449e31aef6aSopenharmony_ci 1450e31aef6aSopenharmony_ci async def _get_default_module_async( 1451e31aef6aSopenharmony_ci self, ctx: t.Optional[Context] = None 1452e31aef6aSopenharmony_ci ) -> "TemplateModule": 1453e31aef6aSopenharmony_ci if ctx is not None: 1454e31aef6aSopenharmony_ci keys = ctx.globals_keys - self.globals.keys() 1455e31aef6aSopenharmony_ci 1456e31aef6aSopenharmony_ci if keys: 1457e31aef6aSopenharmony_ci return await self.make_module_async({k: ctx.parent[k] for k in keys}) 1458e31aef6aSopenharmony_ci 1459e31aef6aSopenharmony_ci if self._module is None: 1460e31aef6aSopenharmony_ci self._module = await self.make_module_async() 1461e31aef6aSopenharmony_ci 1462e31aef6aSopenharmony_ci return self._module 1463e31aef6aSopenharmony_ci 1464e31aef6aSopenharmony_ci @property 1465e31aef6aSopenharmony_ci def module(self) -> "TemplateModule": 1466e31aef6aSopenharmony_ci """The template as module. This is used for imports in the 1467e31aef6aSopenharmony_ci template runtime but is also useful if one wants to access 1468e31aef6aSopenharmony_ci exported template variables from the Python layer: 1469e31aef6aSopenharmony_ci 1470e31aef6aSopenharmony_ci >>> t = Template('{% macro foo() %}42{% endmacro %}23') 1471e31aef6aSopenharmony_ci >>> str(t.module) 1472e31aef6aSopenharmony_ci '23' 1473e31aef6aSopenharmony_ci >>> t.module.foo() == u'42' 1474e31aef6aSopenharmony_ci True 1475e31aef6aSopenharmony_ci 1476e31aef6aSopenharmony_ci This attribute is not available if async mode is enabled. 1477e31aef6aSopenharmony_ci """ 1478e31aef6aSopenharmony_ci return self._get_default_module() 1479e31aef6aSopenharmony_ci 1480e31aef6aSopenharmony_ci def get_corresponding_lineno(self, lineno: int) -> int: 1481e31aef6aSopenharmony_ci """Return the source line number of a line number in the 1482e31aef6aSopenharmony_ci generated bytecode as they are not in sync. 1483e31aef6aSopenharmony_ci """ 1484e31aef6aSopenharmony_ci for template_line, code_line in reversed(self.debug_info): 1485e31aef6aSopenharmony_ci if code_line <= lineno: 1486e31aef6aSopenharmony_ci return template_line 1487e31aef6aSopenharmony_ci return 1 1488e31aef6aSopenharmony_ci 1489e31aef6aSopenharmony_ci @property 1490e31aef6aSopenharmony_ci def is_up_to_date(self) -> bool: 1491e31aef6aSopenharmony_ci """If this variable is `False` there is a newer version available.""" 1492e31aef6aSopenharmony_ci if self._uptodate is None: 1493e31aef6aSopenharmony_ci return True 1494e31aef6aSopenharmony_ci return self._uptodate() 1495e31aef6aSopenharmony_ci 1496e31aef6aSopenharmony_ci @property 1497e31aef6aSopenharmony_ci def debug_info(self) -> t.List[t.Tuple[int, int]]: 1498e31aef6aSopenharmony_ci """The debug info mapping.""" 1499e31aef6aSopenharmony_ci if self._debug_info: 1500e31aef6aSopenharmony_ci return [ 1501e31aef6aSopenharmony_ci tuple(map(int, x.split("="))) # type: ignore 1502e31aef6aSopenharmony_ci for x in self._debug_info.split("&") 1503e31aef6aSopenharmony_ci ] 1504e31aef6aSopenharmony_ci 1505e31aef6aSopenharmony_ci return [] 1506e31aef6aSopenharmony_ci 1507e31aef6aSopenharmony_ci def __repr__(self) -> str: 1508e31aef6aSopenharmony_ci if self.name is None: 1509e31aef6aSopenharmony_ci name = f"memory:{id(self):x}" 1510e31aef6aSopenharmony_ci else: 1511e31aef6aSopenharmony_ci name = repr(self.name) 1512e31aef6aSopenharmony_ci return f"<{type(self).__name__} {name}>" 1513e31aef6aSopenharmony_ci 1514e31aef6aSopenharmony_ci 1515e31aef6aSopenharmony_ciclass TemplateModule: 1516e31aef6aSopenharmony_ci """Represents an imported template. All the exported names of the 1517e31aef6aSopenharmony_ci template are available as attributes on this object. Additionally 1518e31aef6aSopenharmony_ci converting it into a string renders the contents. 1519e31aef6aSopenharmony_ci """ 1520e31aef6aSopenharmony_ci 1521e31aef6aSopenharmony_ci def __init__( 1522e31aef6aSopenharmony_ci self, 1523e31aef6aSopenharmony_ci template: Template, 1524e31aef6aSopenharmony_ci context: Context, 1525e31aef6aSopenharmony_ci body_stream: t.Optional[t.Iterable[str]] = None, 1526e31aef6aSopenharmony_ci ) -> None: 1527e31aef6aSopenharmony_ci if body_stream is None: 1528e31aef6aSopenharmony_ci if context.environment.is_async: 1529e31aef6aSopenharmony_ci raise RuntimeError( 1530e31aef6aSopenharmony_ci "Async mode requires a body stream to be passed to" 1531e31aef6aSopenharmony_ci " a template module. Use the async methods of the" 1532e31aef6aSopenharmony_ci " API you are using." 1533e31aef6aSopenharmony_ci ) 1534e31aef6aSopenharmony_ci 1535e31aef6aSopenharmony_ci body_stream = list(template.root_render_func(context)) 1536e31aef6aSopenharmony_ci 1537e31aef6aSopenharmony_ci self._body_stream = body_stream 1538e31aef6aSopenharmony_ci self.__dict__.update(context.get_exported()) 1539e31aef6aSopenharmony_ci self.__name__ = template.name 1540e31aef6aSopenharmony_ci 1541e31aef6aSopenharmony_ci def __html__(self) -> Markup: 1542e31aef6aSopenharmony_ci return Markup(concat(self._body_stream)) 1543e31aef6aSopenharmony_ci 1544e31aef6aSopenharmony_ci def __str__(self) -> str: 1545e31aef6aSopenharmony_ci return concat(self._body_stream) 1546e31aef6aSopenharmony_ci 1547e31aef6aSopenharmony_ci def __repr__(self) -> str: 1548e31aef6aSopenharmony_ci if self.__name__ is None: 1549e31aef6aSopenharmony_ci name = f"memory:{id(self):x}" 1550e31aef6aSopenharmony_ci else: 1551e31aef6aSopenharmony_ci name = repr(self.__name__) 1552e31aef6aSopenharmony_ci return f"<{type(self).__name__} {name}>" 1553e31aef6aSopenharmony_ci 1554e31aef6aSopenharmony_ci 1555e31aef6aSopenharmony_ciclass TemplateExpression: 1556e31aef6aSopenharmony_ci """The :meth:`jinja2.Environment.compile_expression` method returns an 1557e31aef6aSopenharmony_ci instance of this object. It encapsulates the expression-like access 1558e31aef6aSopenharmony_ci to the template with an expression it wraps. 1559e31aef6aSopenharmony_ci """ 1560e31aef6aSopenharmony_ci 1561e31aef6aSopenharmony_ci def __init__(self, template: Template, undefined_to_none: bool) -> None: 1562e31aef6aSopenharmony_ci self._template = template 1563e31aef6aSopenharmony_ci self._undefined_to_none = undefined_to_none 1564e31aef6aSopenharmony_ci 1565e31aef6aSopenharmony_ci def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Optional[t.Any]: 1566e31aef6aSopenharmony_ci context = self._template.new_context(dict(*args, **kwargs)) 1567e31aef6aSopenharmony_ci consume(self._template.root_render_func(context)) 1568e31aef6aSopenharmony_ci rv = context.vars["result"] 1569e31aef6aSopenharmony_ci if self._undefined_to_none and isinstance(rv, Undefined): 1570e31aef6aSopenharmony_ci rv = None 1571e31aef6aSopenharmony_ci return rv 1572e31aef6aSopenharmony_ci 1573e31aef6aSopenharmony_ci 1574e31aef6aSopenharmony_ciclass TemplateStream: 1575e31aef6aSopenharmony_ci """A template stream works pretty much like an ordinary python generator 1576e31aef6aSopenharmony_ci but it can buffer multiple items to reduce the number of total iterations. 1577e31aef6aSopenharmony_ci Per default the output is unbuffered which means that for every unbuffered 1578e31aef6aSopenharmony_ci instruction in the template one string is yielded. 1579e31aef6aSopenharmony_ci 1580e31aef6aSopenharmony_ci If buffering is enabled with a buffer size of 5, five items are combined 1581e31aef6aSopenharmony_ci into a new string. This is mainly useful if you are streaming 1582e31aef6aSopenharmony_ci big templates to a client via WSGI which flushes after each iteration. 1583e31aef6aSopenharmony_ci """ 1584e31aef6aSopenharmony_ci 1585e31aef6aSopenharmony_ci def __init__(self, gen: t.Iterator[str]) -> None: 1586e31aef6aSopenharmony_ci self._gen = gen 1587e31aef6aSopenharmony_ci self.disable_buffering() 1588e31aef6aSopenharmony_ci 1589e31aef6aSopenharmony_ci def dump( 1590e31aef6aSopenharmony_ci self, 1591e31aef6aSopenharmony_ci fp: t.Union[str, t.IO], 1592e31aef6aSopenharmony_ci encoding: t.Optional[str] = None, 1593e31aef6aSopenharmony_ci errors: t.Optional[str] = "strict", 1594e31aef6aSopenharmony_ci ) -> None: 1595e31aef6aSopenharmony_ci """Dump the complete stream into a file or file-like object. 1596e31aef6aSopenharmony_ci Per default strings are written, if you want to encode 1597e31aef6aSopenharmony_ci before writing specify an `encoding`. 1598e31aef6aSopenharmony_ci 1599e31aef6aSopenharmony_ci Example usage:: 1600e31aef6aSopenharmony_ci 1601e31aef6aSopenharmony_ci Template('Hello {{ name }}!').stream(name='foo').dump('hello.html') 1602e31aef6aSopenharmony_ci """ 1603e31aef6aSopenharmony_ci close = False 1604e31aef6aSopenharmony_ci 1605e31aef6aSopenharmony_ci if isinstance(fp, str): 1606e31aef6aSopenharmony_ci if encoding is None: 1607e31aef6aSopenharmony_ci encoding = "utf-8" 1608e31aef6aSopenharmony_ci 1609e31aef6aSopenharmony_ci fp = open(fp, "wb") 1610e31aef6aSopenharmony_ci close = True 1611e31aef6aSopenharmony_ci try: 1612e31aef6aSopenharmony_ci if encoding is not None: 1613e31aef6aSopenharmony_ci iterable = (x.encode(encoding, errors) for x in self) # type: ignore 1614e31aef6aSopenharmony_ci else: 1615e31aef6aSopenharmony_ci iterable = self # type: ignore 1616e31aef6aSopenharmony_ci 1617e31aef6aSopenharmony_ci if hasattr(fp, "writelines"): 1618e31aef6aSopenharmony_ci fp.writelines(iterable) 1619e31aef6aSopenharmony_ci else: 1620e31aef6aSopenharmony_ci for item in iterable: 1621e31aef6aSopenharmony_ci fp.write(item) 1622e31aef6aSopenharmony_ci finally: 1623e31aef6aSopenharmony_ci if close: 1624e31aef6aSopenharmony_ci fp.close() 1625e31aef6aSopenharmony_ci 1626e31aef6aSopenharmony_ci def disable_buffering(self) -> None: 1627e31aef6aSopenharmony_ci """Disable the output buffering.""" 1628e31aef6aSopenharmony_ci self._next = partial(next, self._gen) 1629e31aef6aSopenharmony_ci self.buffered = False 1630e31aef6aSopenharmony_ci 1631e31aef6aSopenharmony_ci def _buffered_generator(self, size: int) -> t.Iterator[str]: 1632e31aef6aSopenharmony_ci buf: t.List[str] = [] 1633e31aef6aSopenharmony_ci c_size = 0 1634e31aef6aSopenharmony_ci push = buf.append 1635e31aef6aSopenharmony_ci 1636e31aef6aSopenharmony_ci while True: 1637e31aef6aSopenharmony_ci try: 1638e31aef6aSopenharmony_ci while c_size < size: 1639e31aef6aSopenharmony_ci c = next(self._gen) 1640e31aef6aSopenharmony_ci push(c) 1641e31aef6aSopenharmony_ci if c: 1642e31aef6aSopenharmony_ci c_size += 1 1643e31aef6aSopenharmony_ci except StopIteration: 1644e31aef6aSopenharmony_ci if not c_size: 1645e31aef6aSopenharmony_ci return 1646e31aef6aSopenharmony_ci yield concat(buf) 1647e31aef6aSopenharmony_ci del buf[:] 1648e31aef6aSopenharmony_ci c_size = 0 1649e31aef6aSopenharmony_ci 1650e31aef6aSopenharmony_ci def enable_buffering(self, size: int = 5) -> None: 1651e31aef6aSopenharmony_ci """Enable buffering. Buffer `size` items before yielding them.""" 1652e31aef6aSopenharmony_ci if size <= 1: 1653e31aef6aSopenharmony_ci raise ValueError("buffer size too small") 1654e31aef6aSopenharmony_ci 1655e31aef6aSopenharmony_ci self.buffered = True 1656e31aef6aSopenharmony_ci self._next = partial(next, self._buffered_generator(size)) 1657e31aef6aSopenharmony_ci 1658e31aef6aSopenharmony_ci def __iter__(self) -> "TemplateStream": 1659e31aef6aSopenharmony_ci return self 1660e31aef6aSopenharmony_ci 1661e31aef6aSopenharmony_ci def __next__(self) -> str: 1662e31aef6aSopenharmony_ci return self._next() # type: ignore 1663e31aef6aSopenharmony_ci 1664e31aef6aSopenharmony_ci 1665e31aef6aSopenharmony_ci# hook in default template class. if anyone reads this comment: ignore that 1666e31aef6aSopenharmony_ci# it's possible to use custom templates ;-) 1667e31aef6aSopenharmony_ciEnvironment.template_class = Template 1668