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