1e31aef6aSopenharmony_ci"""The runtime functions and state used by compiled templates."""
2e31aef6aSopenharmony_ciimport functools
3e31aef6aSopenharmony_ciimport sys
4e31aef6aSopenharmony_ciimport typing as t
5e31aef6aSopenharmony_cifrom collections import abc
6e31aef6aSopenharmony_cifrom itertools import chain
7e31aef6aSopenharmony_ci
8e31aef6aSopenharmony_cifrom markupsafe import escape  # noqa: F401
9e31aef6aSopenharmony_cifrom markupsafe import Markup
10e31aef6aSopenharmony_cifrom markupsafe import soft_str
11e31aef6aSopenharmony_ci
12e31aef6aSopenharmony_cifrom .async_utils import auto_aiter
13e31aef6aSopenharmony_cifrom .async_utils import auto_await  # noqa: F401
14e31aef6aSopenharmony_cifrom .exceptions import TemplateNotFound  # noqa: F401
15e31aef6aSopenharmony_cifrom .exceptions import TemplateRuntimeError  # noqa: F401
16e31aef6aSopenharmony_cifrom .exceptions import UndefinedError
17e31aef6aSopenharmony_cifrom .nodes import EvalContext
18e31aef6aSopenharmony_cifrom .utils import _PassArg
19e31aef6aSopenharmony_cifrom .utils import concat
20e31aef6aSopenharmony_cifrom .utils import internalcode
21e31aef6aSopenharmony_cifrom .utils import missing
22e31aef6aSopenharmony_cifrom .utils import Namespace  # noqa: F401
23e31aef6aSopenharmony_cifrom .utils import object_type_repr
24e31aef6aSopenharmony_cifrom .utils import pass_eval_context
25e31aef6aSopenharmony_ci
26e31aef6aSopenharmony_ciV = t.TypeVar("V")
27e31aef6aSopenharmony_ciF = t.TypeVar("F", bound=t.Callable[..., t.Any])
28e31aef6aSopenharmony_ci
29e31aef6aSopenharmony_ciif t.TYPE_CHECKING:
30e31aef6aSopenharmony_ci    import logging
31e31aef6aSopenharmony_ci    import typing_extensions as te
32e31aef6aSopenharmony_ci    from .environment import Environment
33e31aef6aSopenharmony_ci
34e31aef6aSopenharmony_ci    class LoopRenderFunc(te.Protocol):
35e31aef6aSopenharmony_ci        def __call__(
36e31aef6aSopenharmony_ci            self,
37e31aef6aSopenharmony_ci            reciter: t.Iterable[V],
38e31aef6aSopenharmony_ci            loop_render_func: "LoopRenderFunc",
39e31aef6aSopenharmony_ci            depth: int = 0,
40e31aef6aSopenharmony_ci        ) -> str:
41e31aef6aSopenharmony_ci            ...
42e31aef6aSopenharmony_ci
43e31aef6aSopenharmony_ci
44e31aef6aSopenharmony_ci# these variables are exported to the template runtime
45e31aef6aSopenharmony_ciexported = [
46e31aef6aSopenharmony_ci    "LoopContext",
47e31aef6aSopenharmony_ci    "TemplateReference",
48e31aef6aSopenharmony_ci    "Macro",
49e31aef6aSopenharmony_ci    "Markup",
50e31aef6aSopenharmony_ci    "TemplateRuntimeError",
51e31aef6aSopenharmony_ci    "missing",
52e31aef6aSopenharmony_ci    "escape",
53e31aef6aSopenharmony_ci    "markup_join",
54e31aef6aSopenharmony_ci    "str_join",
55e31aef6aSopenharmony_ci    "identity",
56e31aef6aSopenharmony_ci    "TemplateNotFound",
57e31aef6aSopenharmony_ci    "Namespace",
58e31aef6aSopenharmony_ci    "Undefined",
59e31aef6aSopenharmony_ci    "internalcode",
60e31aef6aSopenharmony_ci]
61e31aef6aSopenharmony_ciasync_exported = [
62e31aef6aSopenharmony_ci    "AsyncLoopContext",
63e31aef6aSopenharmony_ci    "auto_aiter",
64e31aef6aSopenharmony_ci    "auto_await",
65e31aef6aSopenharmony_ci]
66e31aef6aSopenharmony_ci
67e31aef6aSopenharmony_ci
68e31aef6aSopenharmony_cidef identity(x: V) -> V:
69e31aef6aSopenharmony_ci    """Returns its argument. Useful for certain things in the
70e31aef6aSopenharmony_ci    environment.
71e31aef6aSopenharmony_ci    """
72e31aef6aSopenharmony_ci    return x
73e31aef6aSopenharmony_ci
74e31aef6aSopenharmony_ci
75e31aef6aSopenharmony_cidef markup_join(seq: t.Iterable[t.Any]) -> str:
76e31aef6aSopenharmony_ci    """Concatenation that escapes if necessary and converts to string."""
77e31aef6aSopenharmony_ci    buf = []
78e31aef6aSopenharmony_ci    iterator = map(soft_str, seq)
79e31aef6aSopenharmony_ci    for arg in iterator:
80e31aef6aSopenharmony_ci        buf.append(arg)
81e31aef6aSopenharmony_ci        if hasattr(arg, "__html__"):
82e31aef6aSopenharmony_ci            return Markup("").join(chain(buf, iterator))
83e31aef6aSopenharmony_ci    return concat(buf)
84e31aef6aSopenharmony_ci
85e31aef6aSopenharmony_ci
86e31aef6aSopenharmony_cidef str_join(seq: t.Iterable[t.Any]) -> str:
87e31aef6aSopenharmony_ci    """Simple args to string conversion and concatenation."""
88e31aef6aSopenharmony_ci    return concat(map(str, seq))
89e31aef6aSopenharmony_ci
90e31aef6aSopenharmony_ci
91e31aef6aSopenharmony_cidef new_context(
92e31aef6aSopenharmony_ci    environment: "Environment",
93e31aef6aSopenharmony_ci    template_name: t.Optional[str],
94e31aef6aSopenharmony_ci    blocks: t.Dict[str, t.Callable[["Context"], t.Iterator[str]]],
95e31aef6aSopenharmony_ci    vars: t.Optional[t.Dict[str, t.Any]] = None,
96e31aef6aSopenharmony_ci    shared: bool = False,
97e31aef6aSopenharmony_ci    globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
98e31aef6aSopenharmony_ci    locals: t.Optional[t.Mapping[str, t.Any]] = None,
99e31aef6aSopenharmony_ci) -> "Context":
100e31aef6aSopenharmony_ci    """Internal helper for context creation."""
101e31aef6aSopenharmony_ci    if vars is None:
102e31aef6aSopenharmony_ci        vars = {}
103e31aef6aSopenharmony_ci    if shared:
104e31aef6aSopenharmony_ci        parent = vars
105e31aef6aSopenharmony_ci    else:
106e31aef6aSopenharmony_ci        parent = dict(globals or (), **vars)
107e31aef6aSopenharmony_ci    if locals:
108e31aef6aSopenharmony_ci        # if the parent is shared a copy should be created because
109e31aef6aSopenharmony_ci        # we don't want to modify the dict passed
110e31aef6aSopenharmony_ci        if shared:
111e31aef6aSopenharmony_ci            parent = dict(parent)
112e31aef6aSopenharmony_ci        for key, value in locals.items():
113e31aef6aSopenharmony_ci            if value is not missing:
114e31aef6aSopenharmony_ci                parent[key] = value
115e31aef6aSopenharmony_ci    return environment.context_class(
116e31aef6aSopenharmony_ci        environment, parent, template_name, blocks, globals=globals
117e31aef6aSopenharmony_ci    )
118e31aef6aSopenharmony_ci
119e31aef6aSopenharmony_ci
120e31aef6aSopenharmony_ciclass TemplateReference:
121e31aef6aSopenharmony_ci    """The `self` in templates."""
122e31aef6aSopenharmony_ci
123e31aef6aSopenharmony_ci    def __init__(self, context: "Context") -> None:
124e31aef6aSopenharmony_ci        self.__context = context
125e31aef6aSopenharmony_ci
126e31aef6aSopenharmony_ci    def __getitem__(self, name: str) -> t.Any:
127e31aef6aSopenharmony_ci        blocks = self.__context.blocks[name]
128e31aef6aSopenharmony_ci        return BlockReference(name, self.__context, blocks, 0)
129e31aef6aSopenharmony_ci
130e31aef6aSopenharmony_ci    def __repr__(self) -> str:
131e31aef6aSopenharmony_ci        return f"<{type(self).__name__} {self.__context.name!r}>"
132e31aef6aSopenharmony_ci
133e31aef6aSopenharmony_ci
134e31aef6aSopenharmony_cidef _dict_method_all(dict_method: F) -> F:
135e31aef6aSopenharmony_ci    @functools.wraps(dict_method)
136e31aef6aSopenharmony_ci    def f_all(self: "Context") -> t.Any:
137e31aef6aSopenharmony_ci        return dict_method(self.get_all())
138e31aef6aSopenharmony_ci
139e31aef6aSopenharmony_ci    return t.cast(F, f_all)
140e31aef6aSopenharmony_ci
141e31aef6aSopenharmony_ci
142e31aef6aSopenharmony_ci@abc.Mapping.register
143e31aef6aSopenharmony_ciclass Context:
144e31aef6aSopenharmony_ci    """The template context holds the variables of a template.  It stores the
145e31aef6aSopenharmony_ci    values passed to the template and also the names the template exports.
146e31aef6aSopenharmony_ci    Creating instances is neither supported nor useful as it's created
147e31aef6aSopenharmony_ci    automatically at various stages of the template evaluation and should not
148e31aef6aSopenharmony_ci    be created by hand.
149e31aef6aSopenharmony_ci
150e31aef6aSopenharmony_ci    The context is immutable.  Modifications on :attr:`parent` **must not**
151e31aef6aSopenharmony_ci    happen and modifications on :attr:`vars` are allowed from generated
152e31aef6aSopenharmony_ci    template code only.  Template filters and global functions marked as
153e31aef6aSopenharmony_ci    :func:`pass_context` get the active context passed as first argument
154e31aef6aSopenharmony_ci    and are allowed to access the context read-only.
155e31aef6aSopenharmony_ci
156e31aef6aSopenharmony_ci    The template context supports read only dict operations (`get`,
157e31aef6aSopenharmony_ci    `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`,
158e31aef6aSopenharmony_ci    `__getitem__`, `__contains__`).  Additionally there is a :meth:`resolve`
159e31aef6aSopenharmony_ci    method that doesn't fail with a `KeyError` but returns an
160e31aef6aSopenharmony_ci    :class:`Undefined` object for missing variables.
161e31aef6aSopenharmony_ci    """
162e31aef6aSopenharmony_ci
163e31aef6aSopenharmony_ci    def __init__(
164e31aef6aSopenharmony_ci        self,
165e31aef6aSopenharmony_ci        environment: "Environment",
166e31aef6aSopenharmony_ci        parent: t.Dict[str, t.Any],
167e31aef6aSopenharmony_ci        name: t.Optional[str],
168e31aef6aSopenharmony_ci        blocks: t.Dict[str, t.Callable[["Context"], t.Iterator[str]]],
169e31aef6aSopenharmony_ci        globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
170e31aef6aSopenharmony_ci    ):
171e31aef6aSopenharmony_ci        self.parent = parent
172e31aef6aSopenharmony_ci        self.vars: t.Dict[str, t.Any] = {}
173e31aef6aSopenharmony_ci        self.environment: "Environment" = environment
174e31aef6aSopenharmony_ci        self.eval_ctx = EvalContext(self.environment, name)
175e31aef6aSopenharmony_ci        self.exported_vars: t.Set[str] = set()
176e31aef6aSopenharmony_ci        self.name = name
177e31aef6aSopenharmony_ci        self.globals_keys = set() if globals is None else set(globals)
178e31aef6aSopenharmony_ci
179e31aef6aSopenharmony_ci        # create the initial mapping of blocks.  Whenever template inheritance
180e31aef6aSopenharmony_ci        # takes place the runtime will update this mapping with the new blocks
181e31aef6aSopenharmony_ci        # from the template.
182e31aef6aSopenharmony_ci        self.blocks = {k: [v] for k, v in blocks.items()}
183e31aef6aSopenharmony_ci
184e31aef6aSopenharmony_ci    def super(
185e31aef6aSopenharmony_ci        self, name: str, current: t.Callable[["Context"], t.Iterator[str]]
186e31aef6aSopenharmony_ci    ) -> t.Union["BlockReference", "Undefined"]:
187e31aef6aSopenharmony_ci        """Render a parent block."""
188e31aef6aSopenharmony_ci        try:
189e31aef6aSopenharmony_ci            blocks = self.blocks[name]
190e31aef6aSopenharmony_ci            index = blocks.index(current) + 1
191e31aef6aSopenharmony_ci            blocks[index]
192e31aef6aSopenharmony_ci        except LookupError:
193e31aef6aSopenharmony_ci            return self.environment.undefined(
194e31aef6aSopenharmony_ci                f"there is no parent block called {name!r}.", name="super"
195e31aef6aSopenharmony_ci            )
196e31aef6aSopenharmony_ci        return BlockReference(name, self, blocks, index)
197e31aef6aSopenharmony_ci
198e31aef6aSopenharmony_ci    def get(self, key: str, default: t.Any = None) -> t.Any:
199e31aef6aSopenharmony_ci        """Look up a variable by name, or return a default if the key is
200e31aef6aSopenharmony_ci        not found.
201e31aef6aSopenharmony_ci
202e31aef6aSopenharmony_ci        :param key: The variable name to look up.
203e31aef6aSopenharmony_ci        :param default: The value to return if the key is not found.
204e31aef6aSopenharmony_ci        """
205e31aef6aSopenharmony_ci        try:
206e31aef6aSopenharmony_ci            return self[key]
207e31aef6aSopenharmony_ci        except KeyError:
208e31aef6aSopenharmony_ci            return default
209e31aef6aSopenharmony_ci
210e31aef6aSopenharmony_ci    def resolve(self, key: str) -> t.Union[t.Any, "Undefined"]:
211e31aef6aSopenharmony_ci        """Look up a variable by name, or return an :class:`Undefined`
212e31aef6aSopenharmony_ci        object if the key is not found.
213e31aef6aSopenharmony_ci
214e31aef6aSopenharmony_ci        If you need to add custom behavior, override
215e31aef6aSopenharmony_ci        :meth:`resolve_or_missing`, not this method. The various lookup
216e31aef6aSopenharmony_ci        functions use that method, not this one.
217e31aef6aSopenharmony_ci
218e31aef6aSopenharmony_ci        :param key: The variable name to look up.
219e31aef6aSopenharmony_ci        """
220e31aef6aSopenharmony_ci        rv = self.resolve_or_missing(key)
221e31aef6aSopenharmony_ci
222e31aef6aSopenharmony_ci        if rv is missing:
223e31aef6aSopenharmony_ci            return self.environment.undefined(name=key)
224e31aef6aSopenharmony_ci
225e31aef6aSopenharmony_ci        return rv
226e31aef6aSopenharmony_ci
227e31aef6aSopenharmony_ci    def resolve_or_missing(self, key: str) -> t.Any:
228e31aef6aSopenharmony_ci        """Look up a variable by name, or return a ``missing`` sentinel
229e31aef6aSopenharmony_ci        if the key is not found.
230e31aef6aSopenharmony_ci
231e31aef6aSopenharmony_ci        Override this method to add custom lookup behavior.
232e31aef6aSopenharmony_ci        :meth:`resolve`, :meth:`get`, and :meth:`__getitem__` use this
233e31aef6aSopenharmony_ci        method. Don't call this method directly.
234e31aef6aSopenharmony_ci
235e31aef6aSopenharmony_ci        :param key: The variable name to look up.
236e31aef6aSopenharmony_ci        """
237e31aef6aSopenharmony_ci        if key in self.vars:
238e31aef6aSopenharmony_ci            return self.vars[key]
239e31aef6aSopenharmony_ci
240e31aef6aSopenharmony_ci        if key in self.parent:
241e31aef6aSopenharmony_ci            return self.parent[key]
242e31aef6aSopenharmony_ci
243e31aef6aSopenharmony_ci        return missing
244e31aef6aSopenharmony_ci
245e31aef6aSopenharmony_ci    def get_exported(self) -> t.Dict[str, t.Any]:
246e31aef6aSopenharmony_ci        """Get a new dict with the exported variables."""
247e31aef6aSopenharmony_ci        return {k: self.vars[k] for k in self.exported_vars}
248e31aef6aSopenharmony_ci
249e31aef6aSopenharmony_ci    def get_all(self) -> t.Dict[str, t.Any]:
250e31aef6aSopenharmony_ci        """Return the complete context as dict including the exported
251e31aef6aSopenharmony_ci        variables.  For optimizations reasons this might not return an
252e31aef6aSopenharmony_ci        actual copy so be careful with using it.
253e31aef6aSopenharmony_ci        """
254e31aef6aSopenharmony_ci        if not self.vars:
255e31aef6aSopenharmony_ci            return self.parent
256e31aef6aSopenharmony_ci        if not self.parent:
257e31aef6aSopenharmony_ci            return self.vars
258e31aef6aSopenharmony_ci        return dict(self.parent, **self.vars)
259e31aef6aSopenharmony_ci
260e31aef6aSopenharmony_ci    @internalcode
261e31aef6aSopenharmony_ci    def call(
262e31aef6aSopenharmony_ci        __self, __obj: t.Callable, *args: t.Any, **kwargs: t.Any  # noqa: B902
263e31aef6aSopenharmony_ci    ) -> t.Union[t.Any, "Undefined"]:
264e31aef6aSopenharmony_ci        """Call the callable with the arguments and keyword arguments
265e31aef6aSopenharmony_ci        provided but inject the active context or environment as first
266e31aef6aSopenharmony_ci        argument if the callable has :func:`pass_context` or
267e31aef6aSopenharmony_ci        :func:`pass_environment`.
268e31aef6aSopenharmony_ci        """
269e31aef6aSopenharmony_ci        if __debug__:
270e31aef6aSopenharmony_ci            __traceback_hide__ = True  # noqa
271e31aef6aSopenharmony_ci
272e31aef6aSopenharmony_ci        # Allow callable classes to take a context
273e31aef6aSopenharmony_ci        if (
274e31aef6aSopenharmony_ci            hasattr(__obj, "__call__")  # noqa: B004
275e31aef6aSopenharmony_ci            and _PassArg.from_obj(__obj.__call__) is not None
276e31aef6aSopenharmony_ci        ):
277e31aef6aSopenharmony_ci            __obj = __obj.__call__
278e31aef6aSopenharmony_ci
279e31aef6aSopenharmony_ci        pass_arg = _PassArg.from_obj(__obj)
280e31aef6aSopenharmony_ci
281e31aef6aSopenharmony_ci        if pass_arg is _PassArg.context:
282e31aef6aSopenharmony_ci            # the active context should have access to variables set in
283e31aef6aSopenharmony_ci            # loops and blocks without mutating the context itself
284e31aef6aSopenharmony_ci            if kwargs.get("_loop_vars"):
285e31aef6aSopenharmony_ci                __self = __self.derived(kwargs["_loop_vars"])
286e31aef6aSopenharmony_ci            if kwargs.get("_block_vars"):
287e31aef6aSopenharmony_ci                __self = __self.derived(kwargs["_block_vars"])
288e31aef6aSopenharmony_ci            args = (__self,) + args
289e31aef6aSopenharmony_ci        elif pass_arg is _PassArg.eval_context:
290e31aef6aSopenharmony_ci            args = (__self.eval_ctx,) + args
291e31aef6aSopenharmony_ci        elif pass_arg is _PassArg.environment:
292e31aef6aSopenharmony_ci            args = (__self.environment,) + args
293e31aef6aSopenharmony_ci
294e31aef6aSopenharmony_ci        kwargs.pop("_block_vars", None)
295e31aef6aSopenharmony_ci        kwargs.pop("_loop_vars", None)
296e31aef6aSopenharmony_ci
297e31aef6aSopenharmony_ci        try:
298e31aef6aSopenharmony_ci            return __obj(*args, **kwargs)
299e31aef6aSopenharmony_ci        except StopIteration:
300e31aef6aSopenharmony_ci            return __self.environment.undefined(
301e31aef6aSopenharmony_ci                "value was undefined because a callable raised a"
302e31aef6aSopenharmony_ci                " StopIteration exception"
303e31aef6aSopenharmony_ci            )
304e31aef6aSopenharmony_ci
305e31aef6aSopenharmony_ci    def derived(self, locals: t.Optional[t.Dict[str, t.Any]] = None) -> "Context":
306e31aef6aSopenharmony_ci        """Internal helper function to create a derived context.  This is
307e31aef6aSopenharmony_ci        used in situations where the system needs a new context in the same
308e31aef6aSopenharmony_ci        template that is independent.
309e31aef6aSopenharmony_ci        """
310e31aef6aSopenharmony_ci        context = new_context(
311e31aef6aSopenharmony_ci            self.environment, self.name, {}, self.get_all(), True, None, locals
312e31aef6aSopenharmony_ci        )
313e31aef6aSopenharmony_ci        context.eval_ctx = self.eval_ctx
314e31aef6aSopenharmony_ci        context.blocks.update((k, list(v)) for k, v in self.blocks.items())
315e31aef6aSopenharmony_ci        return context
316e31aef6aSopenharmony_ci
317e31aef6aSopenharmony_ci    keys = _dict_method_all(dict.keys)
318e31aef6aSopenharmony_ci    values = _dict_method_all(dict.values)
319e31aef6aSopenharmony_ci    items = _dict_method_all(dict.items)
320e31aef6aSopenharmony_ci
321e31aef6aSopenharmony_ci    def __contains__(self, name: str) -> bool:
322e31aef6aSopenharmony_ci        return name in self.vars or name in self.parent
323e31aef6aSopenharmony_ci
324e31aef6aSopenharmony_ci    def __getitem__(self, key: str) -> t.Any:
325e31aef6aSopenharmony_ci        """Look up a variable by name with ``[]`` syntax, or raise a
326e31aef6aSopenharmony_ci        ``KeyError`` if the key is not found.
327e31aef6aSopenharmony_ci        """
328e31aef6aSopenharmony_ci        item = self.resolve_or_missing(key)
329e31aef6aSopenharmony_ci
330e31aef6aSopenharmony_ci        if item is missing:
331e31aef6aSopenharmony_ci            raise KeyError(key)
332e31aef6aSopenharmony_ci
333e31aef6aSopenharmony_ci        return item
334e31aef6aSopenharmony_ci
335e31aef6aSopenharmony_ci    def __repr__(self) -> str:
336e31aef6aSopenharmony_ci        return f"<{type(self).__name__} {self.get_all()!r} of {self.name!r}>"
337e31aef6aSopenharmony_ci
338e31aef6aSopenharmony_ci
339e31aef6aSopenharmony_ciclass BlockReference:
340e31aef6aSopenharmony_ci    """One block on a template reference."""
341e31aef6aSopenharmony_ci
342e31aef6aSopenharmony_ci    def __init__(
343e31aef6aSopenharmony_ci        self,
344e31aef6aSopenharmony_ci        name: str,
345e31aef6aSopenharmony_ci        context: "Context",
346e31aef6aSopenharmony_ci        stack: t.List[t.Callable[["Context"], t.Iterator[str]]],
347e31aef6aSopenharmony_ci        depth: int,
348e31aef6aSopenharmony_ci    ) -> None:
349e31aef6aSopenharmony_ci        self.name = name
350e31aef6aSopenharmony_ci        self._context = context
351e31aef6aSopenharmony_ci        self._stack = stack
352e31aef6aSopenharmony_ci        self._depth = depth
353e31aef6aSopenharmony_ci
354e31aef6aSopenharmony_ci    @property
355e31aef6aSopenharmony_ci    def super(self) -> t.Union["BlockReference", "Undefined"]:
356e31aef6aSopenharmony_ci        """Super the block."""
357e31aef6aSopenharmony_ci        if self._depth + 1 >= len(self._stack):
358e31aef6aSopenharmony_ci            return self._context.environment.undefined(
359e31aef6aSopenharmony_ci                f"there is no parent block called {self.name!r}.", name="super"
360e31aef6aSopenharmony_ci            )
361e31aef6aSopenharmony_ci        return BlockReference(self.name, self._context, self._stack, self._depth + 1)
362e31aef6aSopenharmony_ci
363e31aef6aSopenharmony_ci    @internalcode
364e31aef6aSopenharmony_ci    async def _async_call(self) -> str:
365e31aef6aSopenharmony_ci        rv = concat(
366e31aef6aSopenharmony_ci            [x async for x in self._stack[self._depth](self._context)]  # type: ignore
367e31aef6aSopenharmony_ci        )
368e31aef6aSopenharmony_ci
369e31aef6aSopenharmony_ci        if self._context.eval_ctx.autoescape:
370e31aef6aSopenharmony_ci            return Markup(rv)
371e31aef6aSopenharmony_ci
372e31aef6aSopenharmony_ci        return rv
373e31aef6aSopenharmony_ci
374e31aef6aSopenharmony_ci    @internalcode
375e31aef6aSopenharmony_ci    def __call__(self) -> str:
376e31aef6aSopenharmony_ci        if self._context.environment.is_async:
377e31aef6aSopenharmony_ci            return self._async_call()  # type: ignore
378e31aef6aSopenharmony_ci
379e31aef6aSopenharmony_ci        rv = concat(self._stack[self._depth](self._context))
380e31aef6aSopenharmony_ci
381e31aef6aSopenharmony_ci        if self._context.eval_ctx.autoescape:
382e31aef6aSopenharmony_ci            return Markup(rv)
383e31aef6aSopenharmony_ci
384e31aef6aSopenharmony_ci        return rv
385e31aef6aSopenharmony_ci
386e31aef6aSopenharmony_ci
387e31aef6aSopenharmony_ciclass LoopContext:
388e31aef6aSopenharmony_ci    """A wrapper iterable for dynamic ``for`` loops, with information
389e31aef6aSopenharmony_ci    about the loop and iteration.
390e31aef6aSopenharmony_ci    """
391e31aef6aSopenharmony_ci
392e31aef6aSopenharmony_ci    #: Current iteration of the loop, starting at 0.
393e31aef6aSopenharmony_ci    index0 = -1
394e31aef6aSopenharmony_ci
395e31aef6aSopenharmony_ci    _length: t.Optional[int] = None
396e31aef6aSopenharmony_ci    _after: t.Any = missing
397e31aef6aSopenharmony_ci    _current: t.Any = missing
398e31aef6aSopenharmony_ci    _before: t.Any = missing
399e31aef6aSopenharmony_ci    _last_changed_value: t.Any = missing
400e31aef6aSopenharmony_ci
401e31aef6aSopenharmony_ci    def __init__(
402e31aef6aSopenharmony_ci        self,
403e31aef6aSopenharmony_ci        iterable: t.Iterable[V],
404e31aef6aSopenharmony_ci        undefined: t.Type["Undefined"],
405e31aef6aSopenharmony_ci        recurse: t.Optional["LoopRenderFunc"] = None,
406e31aef6aSopenharmony_ci        depth0: int = 0,
407e31aef6aSopenharmony_ci    ) -> None:
408e31aef6aSopenharmony_ci        """
409e31aef6aSopenharmony_ci        :param iterable: Iterable to wrap.
410e31aef6aSopenharmony_ci        :param undefined: :class:`Undefined` class to use for next and
411e31aef6aSopenharmony_ci            previous items.
412e31aef6aSopenharmony_ci        :param recurse: The function to render the loop body when the
413e31aef6aSopenharmony_ci            loop is marked recursive.
414e31aef6aSopenharmony_ci        :param depth0: Incremented when looping recursively.
415e31aef6aSopenharmony_ci        """
416e31aef6aSopenharmony_ci        self._iterable = iterable
417e31aef6aSopenharmony_ci        self._iterator = self._to_iterator(iterable)
418e31aef6aSopenharmony_ci        self._undefined = undefined
419e31aef6aSopenharmony_ci        self._recurse = recurse
420e31aef6aSopenharmony_ci        #: How many levels deep a recursive loop currently is, starting at 0.
421e31aef6aSopenharmony_ci        self.depth0 = depth0
422e31aef6aSopenharmony_ci
423e31aef6aSopenharmony_ci    @staticmethod
424e31aef6aSopenharmony_ci    def _to_iterator(iterable: t.Iterable[V]) -> t.Iterator[V]:
425e31aef6aSopenharmony_ci        return iter(iterable)
426e31aef6aSopenharmony_ci
427e31aef6aSopenharmony_ci    @property
428e31aef6aSopenharmony_ci    def length(self) -> int:
429e31aef6aSopenharmony_ci        """Length of the iterable.
430e31aef6aSopenharmony_ci
431e31aef6aSopenharmony_ci        If the iterable is a generator or otherwise does not have a
432e31aef6aSopenharmony_ci        size, it is eagerly evaluated to get a size.
433e31aef6aSopenharmony_ci        """
434e31aef6aSopenharmony_ci        if self._length is not None:
435e31aef6aSopenharmony_ci            return self._length
436e31aef6aSopenharmony_ci
437e31aef6aSopenharmony_ci        try:
438e31aef6aSopenharmony_ci            self._length = len(self._iterable)  # type: ignore
439e31aef6aSopenharmony_ci        except TypeError:
440e31aef6aSopenharmony_ci            iterable = list(self._iterator)
441e31aef6aSopenharmony_ci            self._iterator = self._to_iterator(iterable)
442e31aef6aSopenharmony_ci            self._length = len(iterable) + self.index + (self._after is not missing)
443e31aef6aSopenharmony_ci
444e31aef6aSopenharmony_ci        return self._length
445e31aef6aSopenharmony_ci
446e31aef6aSopenharmony_ci    def __len__(self) -> int:
447e31aef6aSopenharmony_ci        return self.length
448e31aef6aSopenharmony_ci
449e31aef6aSopenharmony_ci    @property
450e31aef6aSopenharmony_ci    def depth(self) -> int:
451e31aef6aSopenharmony_ci        """How many levels deep a recursive loop currently is, starting at 1."""
452e31aef6aSopenharmony_ci        return self.depth0 + 1
453e31aef6aSopenharmony_ci
454e31aef6aSopenharmony_ci    @property
455e31aef6aSopenharmony_ci    def index(self) -> int:
456e31aef6aSopenharmony_ci        """Current iteration of the loop, starting at 1."""
457e31aef6aSopenharmony_ci        return self.index0 + 1
458e31aef6aSopenharmony_ci
459e31aef6aSopenharmony_ci    @property
460e31aef6aSopenharmony_ci    def revindex0(self) -> int:
461e31aef6aSopenharmony_ci        """Number of iterations from the end of the loop, ending at 0.
462e31aef6aSopenharmony_ci
463e31aef6aSopenharmony_ci        Requires calculating :attr:`length`.
464e31aef6aSopenharmony_ci        """
465e31aef6aSopenharmony_ci        return self.length - self.index
466e31aef6aSopenharmony_ci
467e31aef6aSopenharmony_ci    @property
468e31aef6aSopenharmony_ci    def revindex(self) -> int:
469e31aef6aSopenharmony_ci        """Number of iterations from the end of the loop, ending at 1.
470e31aef6aSopenharmony_ci
471e31aef6aSopenharmony_ci        Requires calculating :attr:`length`.
472e31aef6aSopenharmony_ci        """
473e31aef6aSopenharmony_ci        return self.length - self.index0
474e31aef6aSopenharmony_ci
475e31aef6aSopenharmony_ci    @property
476e31aef6aSopenharmony_ci    def first(self) -> bool:
477e31aef6aSopenharmony_ci        """Whether this is the first iteration of the loop."""
478e31aef6aSopenharmony_ci        return self.index0 == 0
479e31aef6aSopenharmony_ci
480e31aef6aSopenharmony_ci    def _peek_next(self) -> t.Any:
481e31aef6aSopenharmony_ci        """Return the next element in the iterable, or :data:`missing`
482e31aef6aSopenharmony_ci        if the iterable is exhausted. Only peeks one item ahead, caching
483e31aef6aSopenharmony_ci        the result in :attr:`_last` for use in subsequent checks. The
484e31aef6aSopenharmony_ci        cache is reset when :meth:`__next__` is called.
485e31aef6aSopenharmony_ci        """
486e31aef6aSopenharmony_ci        if self._after is not missing:
487e31aef6aSopenharmony_ci            return self._after
488e31aef6aSopenharmony_ci
489e31aef6aSopenharmony_ci        self._after = next(self._iterator, missing)
490e31aef6aSopenharmony_ci        return self._after
491e31aef6aSopenharmony_ci
492e31aef6aSopenharmony_ci    @property
493e31aef6aSopenharmony_ci    def last(self) -> bool:
494e31aef6aSopenharmony_ci        """Whether this is the last iteration of the loop.
495e31aef6aSopenharmony_ci
496e31aef6aSopenharmony_ci        Causes the iterable to advance early. See
497e31aef6aSopenharmony_ci        :func:`itertools.groupby` for issues this can cause.
498e31aef6aSopenharmony_ci        The :func:`groupby` filter avoids that issue.
499e31aef6aSopenharmony_ci        """
500e31aef6aSopenharmony_ci        return self._peek_next() is missing
501e31aef6aSopenharmony_ci
502e31aef6aSopenharmony_ci    @property
503e31aef6aSopenharmony_ci    def previtem(self) -> t.Union[t.Any, "Undefined"]:
504e31aef6aSopenharmony_ci        """The item in the previous iteration. Undefined during the
505e31aef6aSopenharmony_ci        first iteration.
506e31aef6aSopenharmony_ci        """
507e31aef6aSopenharmony_ci        if self.first:
508e31aef6aSopenharmony_ci            return self._undefined("there is no previous item")
509e31aef6aSopenharmony_ci
510e31aef6aSopenharmony_ci        return self._before
511e31aef6aSopenharmony_ci
512e31aef6aSopenharmony_ci    @property
513e31aef6aSopenharmony_ci    def nextitem(self) -> t.Union[t.Any, "Undefined"]:
514e31aef6aSopenharmony_ci        """The item in the next iteration. Undefined during the last
515e31aef6aSopenharmony_ci        iteration.
516e31aef6aSopenharmony_ci
517e31aef6aSopenharmony_ci        Causes the iterable to advance early. See
518e31aef6aSopenharmony_ci        :func:`itertools.groupby` for issues this can cause.
519e31aef6aSopenharmony_ci        The :func:`jinja-filters.groupby` filter avoids that issue.
520e31aef6aSopenharmony_ci        """
521e31aef6aSopenharmony_ci        rv = self._peek_next()
522e31aef6aSopenharmony_ci
523e31aef6aSopenharmony_ci        if rv is missing:
524e31aef6aSopenharmony_ci            return self._undefined("there is no next item")
525e31aef6aSopenharmony_ci
526e31aef6aSopenharmony_ci        return rv
527e31aef6aSopenharmony_ci
528e31aef6aSopenharmony_ci    def cycle(self, *args: V) -> V:
529e31aef6aSopenharmony_ci        """Return a value from the given args, cycling through based on
530e31aef6aSopenharmony_ci        the current :attr:`index0`.
531e31aef6aSopenharmony_ci
532e31aef6aSopenharmony_ci        :param args: One or more values to cycle through.
533e31aef6aSopenharmony_ci        """
534e31aef6aSopenharmony_ci        if not args:
535e31aef6aSopenharmony_ci            raise TypeError("no items for cycling given")
536e31aef6aSopenharmony_ci
537e31aef6aSopenharmony_ci        return args[self.index0 % len(args)]
538e31aef6aSopenharmony_ci
539e31aef6aSopenharmony_ci    def changed(self, *value: t.Any) -> bool:
540e31aef6aSopenharmony_ci        """Return ``True`` if previously called with a different value
541e31aef6aSopenharmony_ci        (including when called for the first time).
542e31aef6aSopenharmony_ci
543e31aef6aSopenharmony_ci        :param value: One or more values to compare to the last call.
544e31aef6aSopenharmony_ci        """
545e31aef6aSopenharmony_ci        if self._last_changed_value != value:
546e31aef6aSopenharmony_ci            self._last_changed_value = value
547e31aef6aSopenharmony_ci            return True
548e31aef6aSopenharmony_ci
549e31aef6aSopenharmony_ci        return False
550e31aef6aSopenharmony_ci
551e31aef6aSopenharmony_ci    def __iter__(self) -> "LoopContext":
552e31aef6aSopenharmony_ci        return self
553e31aef6aSopenharmony_ci
554e31aef6aSopenharmony_ci    def __next__(self) -> t.Tuple[t.Any, "LoopContext"]:
555e31aef6aSopenharmony_ci        if self._after is not missing:
556e31aef6aSopenharmony_ci            rv = self._after
557e31aef6aSopenharmony_ci            self._after = missing
558e31aef6aSopenharmony_ci        else:
559e31aef6aSopenharmony_ci            rv = next(self._iterator)
560e31aef6aSopenharmony_ci
561e31aef6aSopenharmony_ci        self.index0 += 1
562e31aef6aSopenharmony_ci        self._before = self._current
563e31aef6aSopenharmony_ci        self._current = rv
564e31aef6aSopenharmony_ci        return rv, self
565e31aef6aSopenharmony_ci
566e31aef6aSopenharmony_ci    @internalcode
567e31aef6aSopenharmony_ci    def __call__(self, iterable: t.Iterable[V]) -> str:
568e31aef6aSopenharmony_ci        """When iterating over nested data, render the body of the loop
569e31aef6aSopenharmony_ci        recursively with the given inner iterable data.
570e31aef6aSopenharmony_ci
571e31aef6aSopenharmony_ci        The loop must have the ``recursive`` marker for this to work.
572e31aef6aSopenharmony_ci        """
573e31aef6aSopenharmony_ci        if self._recurse is None:
574e31aef6aSopenharmony_ci            raise TypeError(
575e31aef6aSopenharmony_ci                "The loop must have the 'recursive' marker to be called recursively."
576e31aef6aSopenharmony_ci            )
577e31aef6aSopenharmony_ci
578e31aef6aSopenharmony_ci        return self._recurse(iterable, self._recurse, depth=self.depth)
579e31aef6aSopenharmony_ci
580e31aef6aSopenharmony_ci    def __repr__(self) -> str:
581e31aef6aSopenharmony_ci        return f"<{type(self).__name__} {self.index}/{self.length}>"
582e31aef6aSopenharmony_ci
583e31aef6aSopenharmony_ci
584e31aef6aSopenharmony_ciclass AsyncLoopContext(LoopContext):
585e31aef6aSopenharmony_ci    _iterator: t.AsyncIterator[t.Any]  # type: ignore
586e31aef6aSopenharmony_ci
587e31aef6aSopenharmony_ci    @staticmethod
588e31aef6aSopenharmony_ci    def _to_iterator(  # type: ignore
589e31aef6aSopenharmony_ci        iterable: t.Union[t.Iterable[V], t.AsyncIterable[V]]
590e31aef6aSopenharmony_ci    ) -> t.AsyncIterator[V]:
591e31aef6aSopenharmony_ci        return auto_aiter(iterable)
592e31aef6aSopenharmony_ci
593e31aef6aSopenharmony_ci    @property
594e31aef6aSopenharmony_ci    async def length(self) -> int:  # type: ignore
595e31aef6aSopenharmony_ci        if self._length is not None:
596e31aef6aSopenharmony_ci            return self._length
597e31aef6aSopenharmony_ci
598e31aef6aSopenharmony_ci        try:
599e31aef6aSopenharmony_ci            self._length = len(self._iterable)  # type: ignore
600e31aef6aSopenharmony_ci        except TypeError:
601e31aef6aSopenharmony_ci            iterable = [x async for x in self._iterator]
602e31aef6aSopenharmony_ci            self._iterator = self._to_iterator(iterable)
603e31aef6aSopenharmony_ci            self._length = len(iterable) + self.index + (self._after is not missing)
604e31aef6aSopenharmony_ci
605e31aef6aSopenharmony_ci        return self._length
606e31aef6aSopenharmony_ci
607e31aef6aSopenharmony_ci    @property
608e31aef6aSopenharmony_ci    async def revindex0(self) -> int:  # type: ignore
609e31aef6aSopenharmony_ci        return await self.length - self.index
610e31aef6aSopenharmony_ci
611e31aef6aSopenharmony_ci    @property
612e31aef6aSopenharmony_ci    async def revindex(self) -> int:  # type: ignore
613e31aef6aSopenharmony_ci        return await self.length - self.index0
614e31aef6aSopenharmony_ci
615e31aef6aSopenharmony_ci    async def _peek_next(self) -> t.Any:
616e31aef6aSopenharmony_ci        if self._after is not missing:
617e31aef6aSopenharmony_ci            return self._after
618e31aef6aSopenharmony_ci
619e31aef6aSopenharmony_ci        try:
620e31aef6aSopenharmony_ci            self._after = await self._iterator.__anext__()
621e31aef6aSopenharmony_ci        except StopAsyncIteration:
622e31aef6aSopenharmony_ci            self._after = missing
623e31aef6aSopenharmony_ci
624e31aef6aSopenharmony_ci        return self._after
625e31aef6aSopenharmony_ci
626e31aef6aSopenharmony_ci    @property
627e31aef6aSopenharmony_ci    async def last(self) -> bool:  # type: ignore
628e31aef6aSopenharmony_ci        return await self._peek_next() is missing
629e31aef6aSopenharmony_ci
630e31aef6aSopenharmony_ci    @property
631e31aef6aSopenharmony_ci    async def nextitem(self) -> t.Union[t.Any, "Undefined"]:
632e31aef6aSopenharmony_ci        rv = await self._peek_next()
633e31aef6aSopenharmony_ci
634e31aef6aSopenharmony_ci        if rv is missing:
635e31aef6aSopenharmony_ci            return self._undefined("there is no next item")
636e31aef6aSopenharmony_ci
637e31aef6aSopenharmony_ci        return rv
638e31aef6aSopenharmony_ci
639e31aef6aSopenharmony_ci    def __aiter__(self) -> "AsyncLoopContext":
640e31aef6aSopenharmony_ci        return self
641e31aef6aSopenharmony_ci
642e31aef6aSopenharmony_ci    async def __anext__(self) -> t.Tuple[t.Any, "AsyncLoopContext"]:
643e31aef6aSopenharmony_ci        if self._after is not missing:
644e31aef6aSopenharmony_ci            rv = self._after
645e31aef6aSopenharmony_ci            self._after = missing
646e31aef6aSopenharmony_ci        else:
647e31aef6aSopenharmony_ci            rv = await self._iterator.__anext__()
648e31aef6aSopenharmony_ci
649e31aef6aSopenharmony_ci        self.index0 += 1
650e31aef6aSopenharmony_ci        self._before = self._current
651e31aef6aSopenharmony_ci        self._current = rv
652e31aef6aSopenharmony_ci        return rv, self
653e31aef6aSopenharmony_ci
654e31aef6aSopenharmony_ci
655e31aef6aSopenharmony_ciclass Macro:
656e31aef6aSopenharmony_ci    """Wraps a macro function."""
657e31aef6aSopenharmony_ci
658e31aef6aSopenharmony_ci    def __init__(
659e31aef6aSopenharmony_ci        self,
660e31aef6aSopenharmony_ci        environment: "Environment",
661e31aef6aSopenharmony_ci        func: t.Callable[..., str],
662e31aef6aSopenharmony_ci        name: str,
663e31aef6aSopenharmony_ci        arguments: t.List[str],
664e31aef6aSopenharmony_ci        catch_kwargs: bool,
665e31aef6aSopenharmony_ci        catch_varargs: bool,
666e31aef6aSopenharmony_ci        caller: bool,
667e31aef6aSopenharmony_ci        default_autoescape: t.Optional[bool] = None,
668e31aef6aSopenharmony_ci    ):
669e31aef6aSopenharmony_ci        self._environment = environment
670e31aef6aSopenharmony_ci        self._func = func
671e31aef6aSopenharmony_ci        self._argument_count = len(arguments)
672e31aef6aSopenharmony_ci        self.name = name
673e31aef6aSopenharmony_ci        self.arguments = arguments
674e31aef6aSopenharmony_ci        self.catch_kwargs = catch_kwargs
675e31aef6aSopenharmony_ci        self.catch_varargs = catch_varargs
676e31aef6aSopenharmony_ci        self.caller = caller
677e31aef6aSopenharmony_ci        self.explicit_caller = "caller" in arguments
678e31aef6aSopenharmony_ci
679e31aef6aSopenharmony_ci        if default_autoescape is None:
680e31aef6aSopenharmony_ci            if callable(environment.autoescape):
681e31aef6aSopenharmony_ci                default_autoescape = environment.autoescape(None)
682e31aef6aSopenharmony_ci            else:
683e31aef6aSopenharmony_ci                default_autoescape = environment.autoescape
684e31aef6aSopenharmony_ci
685e31aef6aSopenharmony_ci        self._default_autoescape = default_autoescape
686e31aef6aSopenharmony_ci
687e31aef6aSopenharmony_ci    @internalcode
688e31aef6aSopenharmony_ci    @pass_eval_context
689e31aef6aSopenharmony_ci    def __call__(self, *args: t.Any, **kwargs: t.Any) -> str:
690e31aef6aSopenharmony_ci        # This requires a bit of explanation,  In the past we used to
691e31aef6aSopenharmony_ci        # decide largely based on compile-time information if a macro is
692e31aef6aSopenharmony_ci        # safe or unsafe.  While there was a volatile mode it was largely
693e31aef6aSopenharmony_ci        # unused for deciding on escaping.  This turns out to be
694e31aef6aSopenharmony_ci        # problematic for macros because whether a macro is safe depends not
695e31aef6aSopenharmony_ci        # on the escape mode when it was defined, but rather when it was used.
696e31aef6aSopenharmony_ci        #
697e31aef6aSopenharmony_ci        # Because however we export macros from the module system and
698e31aef6aSopenharmony_ci        # there are historic callers that do not pass an eval context (and
699e31aef6aSopenharmony_ci        # will continue to not pass one), we need to perform an instance
700e31aef6aSopenharmony_ci        # check here.
701e31aef6aSopenharmony_ci        #
702e31aef6aSopenharmony_ci        # This is considered safe because an eval context is not a valid
703e31aef6aSopenharmony_ci        # argument to callables otherwise anyway.  Worst case here is
704e31aef6aSopenharmony_ci        # that if no eval context is passed we fall back to the compile
705e31aef6aSopenharmony_ci        # time autoescape flag.
706e31aef6aSopenharmony_ci        if args and isinstance(args[0], EvalContext):
707e31aef6aSopenharmony_ci            autoescape = args[0].autoescape
708e31aef6aSopenharmony_ci            args = args[1:]
709e31aef6aSopenharmony_ci        else:
710e31aef6aSopenharmony_ci            autoescape = self._default_autoescape
711e31aef6aSopenharmony_ci
712e31aef6aSopenharmony_ci        # try to consume the positional arguments
713e31aef6aSopenharmony_ci        arguments = list(args[: self._argument_count])
714e31aef6aSopenharmony_ci        off = len(arguments)
715e31aef6aSopenharmony_ci
716e31aef6aSopenharmony_ci        # For information why this is necessary refer to the handling
717e31aef6aSopenharmony_ci        # of caller in the `macro_body` handler in the compiler.
718e31aef6aSopenharmony_ci        found_caller = False
719e31aef6aSopenharmony_ci
720e31aef6aSopenharmony_ci        # if the number of arguments consumed is not the number of
721e31aef6aSopenharmony_ci        # arguments expected we start filling in keyword arguments
722e31aef6aSopenharmony_ci        # and defaults.
723e31aef6aSopenharmony_ci        if off != self._argument_count:
724e31aef6aSopenharmony_ci            for name in self.arguments[len(arguments) :]:
725e31aef6aSopenharmony_ci                try:
726e31aef6aSopenharmony_ci                    value = kwargs.pop(name)
727e31aef6aSopenharmony_ci                except KeyError:
728e31aef6aSopenharmony_ci                    value = missing
729e31aef6aSopenharmony_ci                if name == "caller":
730e31aef6aSopenharmony_ci                    found_caller = True
731e31aef6aSopenharmony_ci                arguments.append(value)
732e31aef6aSopenharmony_ci        else:
733e31aef6aSopenharmony_ci            found_caller = self.explicit_caller
734e31aef6aSopenharmony_ci
735e31aef6aSopenharmony_ci        # it's important that the order of these arguments does not change
736e31aef6aSopenharmony_ci        # if not also changed in the compiler's `function_scoping` method.
737e31aef6aSopenharmony_ci        # the order is caller, keyword arguments, positional arguments!
738e31aef6aSopenharmony_ci        if self.caller and not found_caller:
739e31aef6aSopenharmony_ci            caller = kwargs.pop("caller", None)
740e31aef6aSopenharmony_ci            if caller is None:
741e31aef6aSopenharmony_ci                caller = self._environment.undefined("No caller defined", name="caller")
742e31aef6aSopenharmony_ci            arguments.append(caller)
743e31aef6aSopenharmony_ci
744e31aef6aSopenharmony_ci        if self.catch_kwargs:
745e31aef6aSopenharmony_ci            arguments.append(kwargs)
746e31aef6aSopenharmony_ci        elif kwargs:
747e31aef6aSopenharmony_ci            if "caller" in kwargs:
748e31aef6aSopenharmony_ci                raise TypeError(
749e31aef6aSopenharmony_ci                    f"macro {self.name!r} was invoked with two values for the special"
750e31aef6aSopenharmony_ci                    " caller argument. This is most likely a bug."
751e31aef6aSopenharmony_ci                )
752e31aef6aSopenharmony_ci            raise TypeError(
753e31aef6aSopenharmony_ci                f"macro {self.name!r} takes no keyword argument {next(iter(kwargs))!r}"
754e31aef6aSopenharmony_ci            )
755e31aef6aSopenharmony_ci        if self.catch_varargs:
756e31aef6aSopenharmony_ci            arguments.append(args[self._argument_count :])
757e31aef6aSopenharmony_ci        elif len(args) > self._argument_count:
758e31aef6aSopenharmony_ci            raise TypeError(
759e31aef6aSopenharmony_ci                f"macro {self.name!r} takes not more than"
760e31aef6aSopenharmony_ci                f" {len(self.arguments)} argument(s)"
761e31aef6aSopenharmony_ci            )
762e31aef6aSopenharmony_ci
763e31aef6aSopenharmony_ci        return self._invoke(arguments, autoescape)
764e31aef6aSopenharmony_ci
765e31aef6aSopenharmony_ci    async def _async_invoke(self, arguments: t.List[t.Any], autoescape: bool) -> str:
766e31aef6aSopenharmony_ci        rv = await self._func(*arguments)  # type: ignore
767e31aef6aSopenharmony_ci
768e31aef6aSopenharmony_ci        if autoescape:
769e31aef6aSopenharmony_ci            return Markup(rv)
770e31aef6aSopenharmony_ci
771e31aef6aSopenharmony_ci        return rv  # type: ignore
772e31aef6aSopenharmony_ci
773e31aef6aSopenharmony_ci    def _invoke(self, arguments: t.List[t.Any], autoescape: bool) -> str:
774e31aef6aSopenharmony_ci        if self._environment.is_async:
775e31aef6aSopenharmony_ci            return self._async_invoke(arguments, autoescape)  # type: ignore
776e31aef6aSopenharmony_ci
777e31aef6aSopenharmony_ci        rv = self._func(*arguments)
778e31aef6aSopenharmony_ci
779e31aef6aSopenharmony_ci        if autoescape:
780e31aef6aSopenharmony_ci            rv = Markup(rv)
781e31aef6aSopenharmony_ci
782e31aef6aSopenharmony_ci        return rv
783e31aef6aSopenharmony_ci
784e31aef6aSopenharmony_ci    def __repr__(self) -> str:
785e31aef6aSopenharmony_ci        name = "anonymous" if self.name is None else repr(self.name)
786e31aef6aSopenharmony_ci        return f"<{type(self).__name__} {name}>"
787e31aef6aSopenharmony_ci
788e31aef6aSopenharmony_ci
789e31aef6aSopenharmony_ciclass Undefined:
790e31aef6aSopenharmony_ci    """The default undefined type.  This undefined type can be printed and
791e31aef6aSopenharmony_ci    iterated over, but every other access will raise an :exc:`UndefinedError`:
792e31aef6aSopenharmony_ci
793e31aef6aSopenharmony_ci    >>> foo = Undefined(name='foo')
794e31aef6aSopenharmony_ci    >>> str(foo)
795e31aef6aSopenharmony_ci    ''
796e31aef6aSopenharmony_ci    >>> not foo
797e31aef6aSopenharmony_ci    True
798e31aef6aSopenharmony_ci    >>> foo + 42
799e31aef6aSopenharmony_ci    Traceback (most recent call last):
800e31aef6aSopenharmony_ci      ...
801e31aef6aSopenharmony_ci    jinja2.exceptions.UndefinedError: 'foo' is undefined
802e31aef6aSopenharmony_ci    """
803e31aef6aSopenharmony_ci
804e31aef6aSopenharmony_ci    __slots__ = (
805e31aef6aSopenharmony_ci        "_undefined_hint",
806e31aef6aSopenharmony_ci        "_undefined_obj",
807e31aef6aSopenharmony_ci        "_undefined_name",
808e31aef6aSopenharmony_ci        "_undefined_exception",
809e31aef6aSopenharmony_ci    )
810e31aef6aSopenharmony_ci
811e31aef6aSopenharmony_ci    def __init__(
812e31aef6aSopenharmony_ci        self,
813e31aef6aSopenharmony_ci        hint: t.Optional[str] = None,
814e31aef6aSopenharmony_ci        obj: t.Any = missing,
815e31aef6aSopenharmony_ci        name: t.Optional[str] = None,
816e31aef6aSopenharmony_ci        exc: t.Type[TemplateRuntimeError] = UndefinedError,
817e31aef6aSopenharmony_ci    ) -> None:
818e31aef6aSopenharmony_ci        self._undefined_hint = hint
819e31aef6aSopenharmony_ci        self._undefined_obj = obj
820e31aef6aSopenharmony_ci        self._undefined_name = name
821e31aef6aSopenharmony_ci        self._undefined_exception = exc
822e31aef6aSopenharmony_ci
823e31aef6aSopenharmony_ci    @property
824e31aef6aSopenharmony_ci    def _undefined_message(self) -> str:
825e31aef6aSopenharmony_ci        """Build a message about the undefined value based on how it was
826e31aef6aSopenharmony_ci        accessed.
827e31aef6aSopenharmony_ci        """
828e31aef6aSopenharmony_ci        if self._undefined_hint:
829e31aef6aSopenharmony_ci            return self._undefined_hint
830e31aef6aSopenharmony_ci
831e31aef6aSopenharmony_ci        if self._undefined_obj is missing:
832e31aef6aSopenharmony_ci            return f"{self._undefined_name!r} is undefined"
833e31aef6aSopenharmony_ci
834e31aef6aSopenharmony_ci        if not isinstance(self._undefined_name, str):
835e31aef6aSopenharmony_ci            return (
836e31aef6aSopenharmony_ci                f"{object_type_repr(self._undefined_obj)} has no"
837e31aef6aSopenharmony_ci                f" element {self._undefined_name!r}"
838e31aef6aSopenharmony_ci            )
839e31aef6aSopenharmony_ci
840e31aef6aSopenharmony_ci        return (
841e31aef6aSopenharmony_ci            f"{object_type_repr(self._undefined_obj)!r} has no"
842e31aef6aSopenharmony_ci            f" attribute {self._undefined_name!r}"
843e31aef6aSopenharmony_ci        )
844e31aef6aSopenharmony_ci
845e31aef6aSopenharmony_ci    @internalcode
846e31aef6aSopenharmony_ci    def _fail_with_undefined_error(
847e31aef6aSopenharmony_ci        self, *args: t.Any, **kwargs: t.Any
848e31aef6aSopenharmony_ci    ) -> "te.NoReturn":
849e31aef6aSopenharmony_ci        """Raise an :exc:`UndefinedError` when operations are performed
850e31aef6aSopenharmony_ci        on the undefined value.
851e31aef6aSopenharmony_ci        """
852e31aef6aSopenharmony_ci        raise self._undefined_exception(self._undefined_message)
853e31aef6aSopenharmony_ci
854e31aef6aSopenharmony_ci    @internalcode
855e31aef6aSopenharmony_ci    def __getattr__(self, name: str) -> t.Any:
856e31aef6aSopenharmony_ci        if name[:2] == "__":
857e31aef6aSopenharmony_ci            raise AttributeError(name)
858e31aef6aSopenharmony_ci
859e31aef6aSopenharmony_ci        return self._fail_with_undefined_error()
860e31aef6aSopenharmony_ci
861e31aef6aSopenharmony_ci    __add__ = __radd__ = __sub__ = __rsub__ = _fail_with_undefined_error
862e31aef6aSopenharmony_ci    __mul__ = __rmul__ = __div__ = __rdiv__ = _fail_with_undefined_error
863e31aef6aSopenharmony_ci    __truediv__ = __rtruediv__ = _fail_with_undefined_error
864e31aef6aSopenharmony_ci    __floordiv__ = __rfloordiv__ = _fail_with_undefined_error
865e31aef6aSopenharmony_ci    __mod__ = __rmod__ = _fail_with_undefined_error
866e31aef6aSopenharmony_ci    __pos__ = __neg__ = _fail_with_undefined_error
867e31aef6aSopenharmony_ci    __call__ = __getitem__ = _fail_with_undefined_error
868e31aef6aSopenharmony_ci    __lt__ = __le__ = __gt__ = __ge__ = _fail_with_undefined_error
869e31aef6aSopenharmony_ci    __int__ = __float__ = __complex__ = _fail_with_undefined_error
870e31aef6aSopenharmony_ci    __pow__ = __rpow__ = _fail_with_undefined_error
871e31aef6aSopenharmony_ci
872e31aef6aSopenharmony_ci    def __eq__(self, other: t.Any) -> bool:
873e31aef6aSopenharmony_ci        return type(self) is type(other)
874e31aef6aSopenharmony_ci
875e31aef6aSopenharmony_ci    def __ne__(self, other: t.Any) -> bool:
876e31aef6aSopenharmony_ci        return not self.__eq__(other)
877e31aef6aSopenharmony_ci
878e31aef6aSopenharmony_ci    def __hash__(self) -> int:
879e31aef6aSopenharmony_ci        return id(type(self))
880e31aef6aSopenharmony_ci
881e31aef6aSopenharmony_ci    def __str__(self) -> str:
882e31aef6aSopenharmony_ci        return ""
883e31aef6aSopenharmony_ci
884e31aef6aSopenharmony_ci    def __len__(self) -> int:
885e31aef6aSopenharmony_ci        return 0
886e31aef6aSopenharmony_ci
887e31aef6aSopenharmony_ci    def __iter__(self) -> t.Iterator[t.Any]:
888e31aef6aSopenharmony_ci        yield from ()
889e31aef6aSopenharmony_ci
890e31aef6aSopenharmony_ci    async def __aiter__(self) -> t.AsyncIterator[t.Any]:
891e31aef6aSopenharmony_ci        for _ in ():
892e31aef6aSopenharmony_ci            yield
893e31aef6aSopenharmony_ci
894e31aef6aSopenharmony_ci    def __bool__(self) -> bool:
895e31aef6aSopenharmony_ci        return False
896e31aef6aSopenharmony_ci
897e31aef6aSopenharmony_ci    def __repr__(self) -> str:
898e31aef6aSopenharmony_ci        return "Undefined"
899e31aef6aSopenharmony_ci
900e31aef6aSopenharmony_ci
901e31aef6aSopenharmony_cidef make_logging_undefined(
902e31aef6aSopenharmony_ci    logger: t.Optional["logging.Logger"] = None, base: t.Type[Undefined] = Undefined
903e31aef6aSopenharmony_ci) -> t.Type[Undefined]:
904e31aef6aSopenharmony_ci    """Given a logger object this returns a new undefined class that will
905e31aef6aSopenharmony_ci    log certain failures.  It will log iterations and printing.  If no
906e31aef6aSopenharmony_ci    logger is given a default logger is created.
907e31aef6aSopenharmony_ci
908e31aef6aSopenharmony_ci    Example::
909e31aef6aSopenharmony_ci
910e31aef6aSopenharmony_ci        logger = logging.getLogger(__name__)
911e31aef6aSopenharmony_ci        LoggingUndefined = make_logging_undefined(
912e31aef6aSopenharmony_ci            logger=logger,
913e31aef6aSopenharmony_ci            base=Undefined
914e31aef6aSopenharmony_ci        )
915e31aef6aSopenharmony_ci
916e31aef6aSopenharmony_ci    .. versionadded:: 2.8
917e31aef6aSopenharmony_ci
918e31aef6aSopenharmony_ci    :param logger: the logger to use.  If not provided, a default logger
919e31aef6aSopenharmony_ci                   is created.
920e31aef6aSopenharmony_ci    :param base: the base class to add logging functionality to.  This
921e31aef6aSopenharmony_ci                 defaults to :class:`Undefined`.
922e31aef6aSopenharmony_ci    """
923e31aef6aSopenharmony_ci    if logger is None:
924e31aef6aSopenharmony_ci        import logging
925e31aef6aSopenharmony_ci
926e31aef6aSopenharmony_ci        logger = logging.getLogger(__name__)
927e31aef6aSopenharmony_ci        logger.addHandler(logging.StreamHandler(sys.stderr))
928e31aef6aSopenharmony_ci
929e31aef6aSopenharmony_ci    def _log_message(undef: Undefined) -> None:
930e31aef6aSopenharmony_ci        logger.warning("Template variable warning: %s", undef._undefined_message)
931e31aef6aSopenharmony_ci
932e31aef6aSopenharmony_ci    class LoggingUndefined(base):  # type: ignore
933e31aef6aSopenharmony_ci        __slots__ = ()
934e31aef6aSopenharmony_ci
935e31aef6aSopenharmony_ci        def _fail_with_undefined_error(  # type: ignore
936e31aef6aSopenharmony_ci            self, *args: t.Any, **kwargs: t.Any
937e31aef6aSopenharmony_ci        ) -> "te.NoReturn":
938e31aef6aSopenharmony_ci            try:
939e31aef6aSopenharmony_ci                super()._fail_with_undefined_error(*args, **kwargs)
940e31aef6aSopenharmony_ci            except self._undefined_exception as e:
941e31aef6aSopenharmony_ci                logger.error("Template variable error: %s", e)  # type: ignore
942e31aef6aSopenharmony_ci                raise e
943e31aef6aSopenharmony_ci
944e31aef6aSopenharmony_ci        def __str__(self) -> str:
945e31aef6aSopenharmony_ci            _log_message(self)
946e31aef6aSopenharmony_ci            return super().__str__()  # type: ignore
947e31aef6aSopenharmony_ci
948e31aef6aSopenharmony_ci        def __iter__(self) -> t.Iterator[t.Any]:
949e31aef6aSopenharmony_ci            _log_message(self)
950e31aef6aSopenharmony_ci            return super().__iter__()  # type: ignore
951e31aef6aSopenharmony_ci
952e31aef6aSopenharmony_ci        def __bool__(self) -> bool:
953e31aef6aSopenharmony_ci            _log_message(self)
954e31aef6aSopenharmony_ci            return super().__bool__()  # type: ignore
955e31aef6aSopenharmony_ci
956e31aef6aSopenharmony_ci    return LoggingUndefined
957e31aef6aSopenharmony_ci
958e31aef6aSopenharmony_ci
959e31aef6aSopenharmony_ciclass ChainableUndefined(Undefined):
960e31aef6aSopenharmony_ci    """An undefined that is chainable, where both ``__getattr__`` and
961e31aef6aSopenharmony_ci    ``__getitem__`` return itself rather than raising an
962e31aef6aSopenharmony_ci    :exc:`UndefinedError`.
963e31aef6aSopenharmony_ci
964e31aef6aSopenharmony_ci    >>> foo = ChainableUndefined(name='foo')
965e31aef6aSopenharmony_ci    >>> str(foo.bar['baz'])
966e31aef6aSopenharmony_ci    ''
967e31aef6aSopenharmony_ci    >>> foo.bar['baz'] + 42
968e31aef6aSopenharmony_ci    Traceback (most recent call last):
969e31aef6aSopenharmony_ci      ...
970e31aef6aSopenharmony_ci    jinja2.exceptions.UndefinedError: 'foo' is undefined
971e31aef6aSopenharmony_ci
972e31aef6aSopenharmony_ci    .. versionadded:: 2.11.0
973e31aef6aSopenharmony_ci    """
974e31aef6aSopenharmony_ci
975e31aef6aSopenharmony_ci    __slots__ = ()
976e31aef6aSopenharmony_ci
977e31aef6aSopenharmony_ci    def __html__(self) -> str:
978e31aef6aSopenharmony_ci        return str(self)
979e31aef6aSopenharmony_ci
980e31aef6aSopenharmony_ci    def __getattr__(self, _: str) -> "ChainableUndefined":
981e31aef6aSopenharmony_ci        return self
982e31aef6aSopenharmony_ci
983e31aef6aSopenharmony_ci    __getitem__ = __getattr__  # type: ignore
984e31aef6aSopenharmony_ci
985e31aef6aSopenharmony_ci
986e31aef6aSopenharmony_ciclass DebugUndefined(Undefined):
987e31aef6aSopenharmony_ci    """An undefined that returns the debug info when printed.
988e31aef6aSopenharmony_ci
989e31aef6aSopenharmony_ci    >>> foo = DebugUndefined(name='foo')
990e31aef6aSopenharmony_ci    >>> str(foo)
991e31aef6aSopenharmony_ci    '{{ foo }}'
992e31aef6aSopenharmony_ci    >>> not foo
993e31aef6aSopenharmony_ci    True
994e31aef6aSopenharmony_ci    >>> foo + 42
995e31aef6aSopenharmony_ci    Traceback (most recent call last):
996e31aef6aSopenharmony_ci      ...
997e31aef6aSopenharmony_ci    jinja2.exceptions.UndefinedError: 'foo' is undefined
998e31aef6aSopenharmony_ci    """
999e31aef6aSopenharmony_ci
1000e31aef6aSopenharmony_ci    __slots__ = ()
1001e31aef6aSopenharmony_ci
1002e31aef6aSopenharmony_ci    def __str__(self) -> str:
1003e31aef6aSopenharmony_ci        if self._undefined_hint:
1004e31aef6aSopenharmony_ci            message = f"undefined value printed: {self._undefined_hint}"
1005e31aef6aSopenharmony_ci
1006e31aef6aSopenharmony_ci        elif self._undefined_obj is missing:
1007e31aef6aSopenharmony_ci            message = self._undefined_name  # type: ignore
1008e31aef6aSopenharmony_ci
1009e31aef6aSopenharmony_ci        else:
1010e31aef6aSopenharmony_ci            message = (
1011e31aef6aSopenharmony_ci                f"no such element: {object_type_repr(self._undefined_obj)}"
1012e31aef6aSopenharmony_ci                f"[{self._undefined_name!r}]"
1013e31aef6aSopenharmony_ci            )
1014e31aef6aSopenharmony_ci
1015e31aef6aSopenharmony_ci        return f"{{{{ {message} }}}}"
1016e31aef6aSopenharmony_ci
1017e31aef6aSopenharmony_ci
1018e31aef6aSopenharmony_ciclass StrictUndefined(Undefined):
1019e31aef6aSopenharmony_ci    """An undefined that barks on print and iteration as well as boolean
1020e31aef6aSopenharmony_ci    tests and all kinds of comparisons.  In other words: you can do nothing
1021e31aef6aSopenharmony_ci    with it except checking if it's defined using the `defined` test.
1022e31aef6aSopenharmony_ci
1023e31aef6aSopenharmony_ci    >>> foo = StrictUndefined(name='foo')
1024e31aef6aSopenharmony_ci    >>> str(foo)
1025e31aef6aSopenharmony_ci    Traceback (most recent call last):
1026e31aef6aSopenharmony_ci      ...
1027e31aef6aSopenharmony_ci    jinja2.exceptions.UndefinedError: 'foo' is undefined
1028e31aef6aSopenharmony_ci    >>> not foo
1029e31aef6aSopenharmony_ci    Traceback (most recent call last):
1030e31aef6aSopenharmony_ci      ...
1031e31aef6aSopenharmony_ci    jinja2.exceptions.UndefinedError: 'foo' is undefined
1032e31aef6aSopenharmony_ci    >>> foo + 42
1033e31aef6aSopenharmony_ci    Traceback (most recent call last):
1034e31aef6aSopenharmony_ci      ...
1035e31aef6aSopenharmony_ci    jinja2.exceptions.UndefinedError: 'foo' is undefined
1036e31aef6aSopenharmony_ci    """
1037e31aef6aSopenharmony_ci
1038e31aef6aSopenharmony_ci    __slots__ = ()
1039e31aef6aSopenharmony_ci    __iter__ = __str__ = __len__ = Undefined._fail_with_undefined_error
1040e31aef6aSopenharmony_ci    __eq__ = __ne__ = __bool__ = __hash__ = Undefined._fail_with_undefined_error
1041e31aef6aSopenharmony_ci    __contains__ = Undefined._fail_with_undefined_error
1042e31aef6aSopenharmony_ci
1043e31aef6aSopenharmony_ci
1044e31aef6aSopenharmony_ci# Remove slots attributes, after the metaclass is applied they are
1045e31aef6aSopenharmony_ci# unneeded and contain wrong data for subclasses.
1046e31aef6aSopenharmony_cidel (
1047e31aef6aSopenharmony_ci    Undefined.__slots__,
1048e31aef6aSopenharmony_ci    ChainableUndefined.__slots__,
1049e31aef6aSopenharmony_ci    DebugUndefined.__slots__,
1050e31aef6aSopenharmony_ci    StrictUndefined.__slots__,
1051e31aef6aSopenharmony_ci)
1052