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