1 """The runtime functions and state used by compiled templates."""
5 from collections
import abc
6 from itertools
import chain
8 from markupsafe
import escape
# noqa: F401
9 from markupsafe
import Markup
10 from markupsafe
import soft_str
12 from .async_utils
import auto_aiter
13 from .async_utils
import auto_await
# noqa: F401
14 from .exceptions
import TemplateNotFound
# noqa: F401
15 from .exceptions
import TemplateRuntimeError
# noqa: F401
16 from .exceptions
import UndefinedError
17 from .nodes
import EvalContext
18 from .utils
import _PassArg
19 from .utils
import concat
20 from .utils
import internalcode
21 from .utils
import missing
22 from .utils
import Namespace
# noqa: F401
23 from .utils
import object_type_repr
24 from .utils
import pass_eval_context
27 F
= t
.TypeVar("F", bound
=t
.Callable
[..., t
.Any
])
31 import typing_extensions
as te
32 from .environment
import Environment
34 class LoopRenderFunc(te
.Protocol
):
37 reciter
: t
.Iterable
[V
],
38 loop_render_func
: "LoopRenderFunc",
44 # these variables are exported to the template runtime
50 "TemplateRuntimeError",
68 def identity(x
: V
) -> V
:
69 """Returns its argument. Useful for certain things in the
75 def markup_join(seq
: t
.Iterable
[t
.Any
]) -> str:
76 """Concatenation that escapes if necessary and converts to string."""
78 iterator
= map(soft_str
, seq
)
81 if hasattr(arg
, "__html__"):
82 return Markup("").join(chain(buf
, iterator
))
86 def str_join(seq
: t
.Iterable
[t
.Any
]) -> str:
87 """Simple args to string conversion and concatenation."""
88 return concat(map(str, seq
))
92 environment
: "Environment",
93 template_name
: t
.Optional
[str],
94 blocks
: t
.Dict
[str, t
.Callable
[["Context"], t
.Iterator
[str]]],
95 vars: t
.Optional
[t
.Dict
[str, t
.Any
]] = None,
97 globals: t
.Optional
[t
.MutableMapping
[str, t
.Any
]] = None,
98 locals: t
.Optional
[t
.Mapping
[str, t
.Any
]] = None,
100 """Internal helper for context creation."""
106 parent
= dict(globals or (), **vars)
108 # if the parent is shared a copy should be created because
109 # we don't want to modify the dict passed
111 parent
= dict(parent
)
112 for key
, value
in locals.items():
113 if value
is not missing
:
115 return environment
.context_class(
116 environment
, parent
, template_name
, blocks
, globals=globals
120 class TemplateReference
:
121 """The `self` in templates."""
123 def __init__(self
, context
: "Context") -> None:
124 self
.__context
= context
126 def __getitem__(self
, name
: str) -> t
.Any
:
127 blocks
= self
.__context
.blocks
[name
]
128 return BlockReference(name
, self
.__context
, blocks
, 0)
130 def __repr__(self
) -> str:
131 return f
"<{type(self).__name__} {self.__context.name!r}>"
134 def _dict_method_all(dict_method
: F
) -> F
:
135 @functools.wraps(dict_method
)
136 def f_all(self
: "Context") -> t
.Any
:
137 return dict_method(self
.get_all())
139 return t
.cast(F
, f_all
)
142 @abc.Mapping.register
144 """The template context holds the variables of a template. It stores the
145 values passed to the template and also the names the template exports.
146 Creating instances is neither supported nor useful as it's created
147 automatically at various stages of the template evaluation and should not
150 The context is immutable. Modifications on :attr:`parent` **must not**
151 happen and modifications on :attr:`vars` are allowed from generated
152 template code only. Template filters and global functions marked as
153 :func:`pass_context` get the active context passed as first argument
154 and are allowed to access the context read-only.
156 The template context supports read only dict operations (`get`,
157 `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`,
158 `__getitem__`, `__contains__`). Additionally there is a :meth:`resolve`
159 method that doesn't fail with a `KeyError` but returns an
160 :class:`Undefined` object for missing variables.
165 environment
: "Environment",
166 parent
: t
.Dict
[str, t
.Any
],
167 name
: t
.Optional
[str],
168 blocks
: t
.Dict
[str, t
.Callable
[["Context"], t
.Iterator
[str]]],
169 globals: t
.Optional
[t
.MutableMapping
[str, t
.Any
]] = None,
172 self
.vars: t
.Dict
[str, t
.Any
] = {}
173 self
.environment
: "Environment" = environment
174 self
.eval_ctx
= EvalContext(self
.environment
, name
)
175 self
.exported_vars
: t
.Set
[str] = set()
177 self
.globals_keys
= set() if globals is None else set(globals)
179 # create the initial mapping of blocks. Whenever template inheritance
180 # takes place the runtime will update this mapping with the new blocks
182 self
.blocks
= {k: [v] for k, v in blocks.items()}
185 self
, name
: str, current
: t
.Callable
[["Context"], t
.Iterator
[str]]
186 ) -> t
.Union
["BlockReference", "Undefined"]:
187 """Render a parent block."""
189 blocks
= self
.blocks
[name
]
190 index
= blocks
.index(current
) + 1
193 return self
.environment
.undefined(
194 f
"there is no parent block called {name!r}.", name
="super"
196 return BlockReference(name
, self
, blocks
, index
)
198 def get(self
, key
: str, default
: t
.Any
= None) -> t
.Any
:
199 """Look up a variable by name, or return a default if the key is
202 :param key: The variable name to look up.
203 :param default: The value to return if the key is not found.
210 def resolve(self
, key
: str) -> t
.Union
[t
.Any
, "Undefined"]:
211 """Look up a variable by name, or return an :class:`Undefined`
212 object if the key is not found.
214 If you need to add custom behavior, override
215 :meth:`resolve_or_missing`, not this method. The various lookup
216 functions use that method, not this one.
218 :param key: The variable name to look up.
220 rv
= self
.resolve_or_missing(key
)
223 return self
.environment
.undefined(name
=key
)
227 def resolve_or_missing(self
, key
: str) -> t
.Any
:
228 """Look up a variable by name, or return a ``missing`` sentinel
229 if the key is not found.
231 Override this method to add custom lookup behavior.
232 :meth:`resolve`, :meth:`get`, and :meth:`__getitem__` use this
233 method. Don't call this method directly.
235 :param key: The variable name to look up.
238 return self
.vars[key
]
240 if key
in self
.parent
:
241 return self
.parent
[key
]
245 def get_exported(self
) -> t
.Dict
[str, t
.Any
]:
246 """Get a new dict with the exported variables."""
247 return {k: self.vars[k] for k in self.exported_vars}
249 def get_all(self
) -> t
.Dict
[str, t
.Any
]:
250 """Return the complete context as dict including the exported
251 variables. For optimizations reasons this might not return an
252 actual copy so be careful with using it.
258 return dict(self
.parent
, **self
.vars)
262 __self
, __obj
: t
.Callable
, *args
: t
.Any
, **kwargs
: t
.Any
# noqa: B902
263 ) -> t
.Union
[t
.Any
, "Undefined"]:
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 has :func:`pass_context` or
267 :func:`pass_environment`.
270 __traceback_hide__
= True # noqa
272 # Allow callable classes to take a context
274 hasattr(__obj
, "__call__") # noqa: B004
275 and _PassArg
.from_obj(__obj
.__call
__) is not None # type: ignore
277 __obj
= __obj
.__call
__ # type: ignore
279 pass_arg
= _PassArg
.from_obj(__obj
)
281 if pass_arg
is _PassArg
.context
:
282 # the active context should have access to variables set in
283 # loops and blocks without mutating the context itself
284 if kwargs
.get("_loop_vars"):
285 __self
= __self
.derived(kwargs
["_loop_vars"])
286 if kwargs
.get("_block_vars"):
287 __self
= __self
.derived(kwargs
["_block_vars"])
288 args
= (__self
,) + args
289 elif pass_arg
is _PassArg
.eval_context
:
290 args
= (__self
.eval_ctx
,) + args
291 elif pass_arg
is _PassArg
.environment
:
292 args
= (__self
.environment
,) + args
294 kwargs
.pop("_block_vars", None)
295 kwargs
.pop("_loop_vars", None)
298 return __obj(*args
, **kwargs
)
299 except StopIteration:
300 return __self
.environment
.undefined(
301 "value was undefined because a callable raised a"
302 " StopIteration exception"
305 def derived(self
, locals: t
.Optional
[t
.Dict
[str, t
.Any
]] = None) -> "Context":
306 """Internal helper function to create a derived context. This is
307 used in situations where the system needs a new context in the same
308 template that is independent.
310 context
= new_context(
311 self
.environment
, self
.name
, {}, self
.get_all(), True, None, locals
313 context
.eval_ctx
= self
.eval_ctx
314 context
.blocks
.update((k
, list(v
)) for k
, v
in self
.blocks
.items())
317 keys
= _dict_method_all(dict.keys
)
318 values
= _dict_method_all(dict.values
)
319 items
= _dict_method_all(dict.items
)
321 def __contains__(self
, name
: str) -> bool:
322 return name
in self
.vars or name
in self
.parent
324 def __getitem__(self
, key
: str) -> t
.Any
:
325 """Look up a variable by name with ``[]`` syntax, or raise a
326 ``KeyError`` if the key is not found.
328 item
= self
.resolve_or_missing(key
)
335 def __repr__(self
) -> str:
336 return f
"<{type(self).__name__} {self.get_all()!r} of {self.name!r}>"
339 class BlockReference
:
340 """One block on a template reference."""
346 stack
: t
.List
[t
.Callable
[["Context"], t
.Iterator
[str]]],
350 self
._context
= context
355 def super(self
) -> t
.Union
["BlockReference", "Undefined"]:
356 """Super the block."""
357 if self
._depth
+ 1 >= len(self
._stack
):
358 return self
._context
.environment
.undefined(
359 f
"there is no parent block called {self.name!r}.", name
="super"
361 return BlockReference(self
.name
, self
._context
, self
._stack
, self
._depth
+ 1)
364 async def _async_call(self
) -> str:
366 [x
async for x
in self
._stack
[self
._depth
](self
._context
)] # type: ignore
369 if self
._context
.eval_ctx
.autoescape
:
375 def __call__(self
) -> str:
376 if self
._context
.environment
.is_async
:
377 return self
._async
_call
() # type: ignore
379 rv
= concat(self
._stack
[self
._depth
](self
._context
))
381 if self
._context
.eval_ctx
.autoescape
:
388 """A wrapper iterable for dynamic ``for`` loops, with information
389 about the loop and iteration.
392 #: Current iteration of the loop, starting at 0.
395 _length
: t
.Optional
[int] = None
396 _after
: t
.Any
= missing
397 _current
: t
.Any
= missing
398 _before
: t
.Any
= missing
399 _last_changed_value
: t
.Any
= missing
403 iterable
: t
.Iterable
[V
],
404 undefined
: t
.Type
["Undefined"],
405 recurse
: t
.Optional
["LoopRenderFunc"] = None,
409 :param iterable: Iterable to wrap.
410 :param undefined: :class:`Undefined` class to use for next and
412 :param recurse: The function to render the loop body when the
413 loop is marked recursive.
414 :param depth0: Incremented when looping recursively.
416 self
._iterable
= iterable
417 self
._iterator
= self
._to
_iterator
(iterable
)
418 self
._undefined
= undefined
419 self
._recurse
= recurse
420 #: How many levels deep a recursive loop currently is, starting at 0.
424 def _to_iterator(iterable
: t
.Iterable
[V
]) -> t
.Iterator
[V
]:
425 return iter(iterable
)
428 def length(self
) -> int:
429 """Length of the iterable.
431 If the iterable is a generator or otherwise does not have a
432 size, it is eagerly evaluated to get a size.
434 if self
._length
is not None:
438 self
._length
= len(self
._iterable
) # type: ignore
440 iterable
= list(self
._iterator
)
441 self
._iterator
= self
._to
_iterator
(iterable
)
442 self
._length
= len(iterable
) + self
.index
+ (self
._after
is not missing
)
446 def __len__(self
) -> int:
450 def depth(self
) -> int:
451 """How many levels deep a recursive loop currently is, starting at 1."""
452 return self
.depth0
+ 1
455 def index(self
) -> int:
456 """Current iteration of the loop, starting at 1."""
457 return self
.index0
+ 1
460 def revindex0(self
) -> int:
461 """Number of iterations from the end of the loop, ending at 0.
463 Requires calculating :attr:`length`.
465 return self
.length
- self
.index
468 def revindex(self
) -> int:
469 """Number of iterations from the end of the loop, ending at 1.
471 Requires calculating :attr:`length`.
473 return self
.length
- self
.index0
476 def first(self
) -> bool:
477 """Whether this is the first iteration of the loop."""
478 return self
.index0
== 0
480 def _peek_next(self
) -> t
.Any
:
481 """Return the next element in the iterable, or :data:`missing`
482 if the iterable is exhausted. Only peeks one item ahead, caching
483 the result in :attr:`_last` for use in subsequent checks. The
484 cache is reset when :meth:`__next__` is called.
486 if self
._after
is not missing
:
489 self
._after
= next(self
._iterator
, missing
)
493 def last(self
) -> bool:
494 """Whether this is the last iteration of the loop.
496 Causes the iterable to advance early. See
497 :func:`itertools.groupby` for issues this can cause.
498 The :func:`groupby` filter avoids that issue.
500 return self
._peek
_next
() is missing
503 def previtem(self
) -> t
.Union
[t
.Any
, "Undefined"]:
504 """The item in the previous iteration. Undefined during the
508 return self
._undefined
("there is no previous item")
513 def nextitem(self
) -> t
.Union
[t
.Any
, "Undefined"]:
514 """The item in the next iteration. Undefined during the last
517 Causes the iterable to advance early. See
518 :func:`itertools.groupby` for issues this can cause.
519 The :func:`jinja-filters.groupby` filter avoids that issue.
521 rv
= self
._peek
_next
()
524 return self
._undefined
("there is no next item")
528 def cycle(self
, *args
: V
) -> V
:
529 """Return a value from the given args, cycling through based on
530 the current :attr:`index0`.
532 :param args: One or more values to cycle through.
535 raise TypeError("no items for cycling given")
537 return args
[self
.index0
% len(args
)]
539 def changed(self
, *value
: t
.Any
) -> bool:
540 """Return ``True`` if previously called with a different value
541 (including when called for the first time).
543 :param value: One or more values to compare to the last call.
545 if self
._last
_changed
_value
!= value
:
546 self
._last
_changed
_value
= value
551 def __iter__(self
) -> "LoopContext":
554 def __next__(self
) -> t
.Tuple
[t
.Any
, "LoopContext"]:
555 if self
._after
is not missing
:
557 self
._after
= missing
559 rv
= next(self
._iterator
)
562 self
._before
= self
._current
567 def __call__(self
, iterable
: t
.Iterable
[V
]) -> str:
568 """When iterating over nested data, render the body of the loop
569 recursively with the given inner iterable data.
571 The loop must have the ``recursive`` marker for this to work.
573 if self
._recurse
is None:
575 "The loop must have the 'recursive' marker to be called recursively."
578 return self
._recurse
(iterable
, self
._recurse
, depth
=self
.depth
)
580 def __repr__(self
) -> str:
581 return f
"<{type(self).__name__} {self.index}/{self.length}>"
584 class AsyncLoopContext(LoopContext
):
585 _iterator
: t
.AsyncIterator
[t
.Any
] # type: ignore
588 def _to_iterator( # type: ignore
589 iterable
: t
.Union
[t
.Iterable
[V
], t
.AsyncIterable
[V
]]
590 ) -> t
.AsyncIterator
[V
]:
591 return auto_aiter(iterable
)
594 async def length(self
) -> int: # type: ignore
595 if self
._length
is not None:
599 self
._length
= len(self
._iterable
) # type: ignore
601 iterable
= [x
async for x
in self
._iterator
]
602 self
._iterator
= self
._to
_iterator
(iterable
)
603 self
._length
= len(iterable
) + self
.index
+ (self
._after
is not missing
)
608 async def revindex0(self
) -> int: # type: ignore
609 return await self
.length
- self
.index
612 async def revindex(self
) -> int: # type: ignore
613 return await self
.length
- self
.index0
615 async def _peek_next(self
) -> t
.Any
:
616 if self
._after
is not missing
:
620 self
._after
= await self
._iterator
.__anext
__()
621 except StopAsyncIteration
:
622 self
._after
= missing
627 async def last(self
) -> bool: # type: ignore
628 return await self
._peek
_next
() is missing
631 async def nextitem(self
) -> t
.Union
[t
.Any
, "Undefined"]:
632 rv
= await self
._peek
_next
()
635 return self
._undefined
("there is no next item")
639 def __aiter__(self
) -> "AsyncLoopContext":
642 async def __anext__(self
) -> t
.Tuple
[t
.Any
, "AsyncLoopContext"]:
643 if self
._after
is not missing
:
645 self
._after
= missing
647 rv
= await self
._iterator
.__anext
__()
650 self
._before
= self
._current
656 """Wraps a macro function."""
660 environment
: "Environment",
661 func
: t
.Callable
[..., str],
663 arguments
: t
.List
[str],
667 default_autoescape
: t
.Optional
[bool] = None,
669 self
._environment
= environment
671 self
._argument
_count
= len(arguments
)
673 self
.arguments
= arguments
674 self
.catch_kwargs
= catch_kwargs
675 self
.catch_varargs
= catch_varargs
677 self
.explicit_caller
= "caller" in arguments
679 if default_autoescape
is None:
680 if callable(environment
.autoescape
):
681 default_autoescape
= environment
.autoescape(None)
683 default_autoescape
= environment
.autoescape
685 self
._default
_autoescape
= default_autoescape
689 def __call__(self
, *args
: t
.Any
, **kwargs
: t
.Any
) -> str:
690 # This requires a bit of explanation, In the past we used to
691 # decide largely based on compile-time information if a macro is
692 # safe or unsafe. While there was a volatile mode it was largely
693 # unused for deciding on escaping. This turns out to be
694 # problematic for macros because whether a macro is safe depends not
695 # on the escape mode when it was defined, but rather when it was used.
697 # Because however we export macros from the module system and
698 # there are historic callers that do not pass an eval context (and
699 # will continue to not pass one), we need to perform an instance
702 # This is considered safe because an eval context is not a valid
703 # argument to callables otherwise anyway. Worst case here is
704 # that if no eval context is passed we fall back to the compile
705 # time autoescape flag.
706 if args
and isinstance(args
[0], EvalContext
):
707 autoescape
= args
[0].autoescape
710 autoescape
= self
._default
_autoescape
712 # try to consume the positional arguments
713 arguments
= list(args
[: self
._argument
_count
])
716 # For information why this is necessary refer to the handling
717 # of caller in the `macro_body` handler in the compiler.
720 # if the number of arguments consumed is not the number of
721 # arguments expected we start filling in keyword arguments
723 if off
!= self
._argument
_count
:
724 for name
in self
.arguments
[len(arguments
) :]:
726 value
= kwargs
.pop(name
)
731 arguments
.append(value
)
733 found_caller
= self
.explicit_caller
735 # it's important that the order of these arguments does not change
736 # if not also changed in the compiler's `function_scoping` method.
737 # the order is caller, keyword arguments, positional arguments!
738 if self
.caller
and not found_caller
:
739 caller
= kwargs
.pop("caller", None)
741 caller
= self
._environment
.undefined("No caller defined", name
="caller")
742 arguments
.append(caller
)
744 if self
.catch_kwargs
:
745 arguments
.append(kwargs
)
747 if "caller" in kwargs
:
749 f
"macro {self.name!r} was invoked with two values for the special"
750 " caller argument. This is most likely a bug."
753 f
"macro {self.name!r} takes no keyword argument {next(iter(kwargs))!r}"
755 if self
.catch_varargs
:
756 arguments
.append(args
[self
._argument
_count
:])
757 elif len(args
) > self
._argument
_count
:
759 f
"macro {self.name!r} takes not more than"
760 f
" {len(self.arguments)} argument(s)"
763 return self
._invoke
(arguments
, autoescape
)
765 async def _async_invoke(self
, arguments
: t
.List
[t
.Any
], autoescape
: bool) -> str:
766 rv
= await self
._func
(*arguments
) # type: ignore
771 return rv
# type: ignore
773 def _invoke(self
, arguments
: t
.List
[t
.Any
], autoescape
: bool) -> str:
774 if self
._environment
.is_async
:
775 return self
._async
_invoke
(arguments
, autoescape
) # type: ignore
777 rv
= self
._func
(*arguments
)
784 def __repr__(self
) -> str:
785 name
= "anonymous" if self
.name
is None else repr(self
.name
)
786 return f
"<{type(self).__name__} {name}>"
790 """The default undefined type. This undefined type can be printed and
791 iterated over, but every other access will raise an :exc:`UndefinedError`:
793 >>> foo = Undefined(name='foo')
799 Traceback (most recent call last):
801 jinja2.exceptions.UndefinedError: 'foo' is undefined
808 "_undefined_exception",
813 hint
: t
.Optional
[str] = None,
814 obj
: t
.Any
= missing
,
815 name
: t
.Optional
[str] = None,
816 exc
: t
.Type
[TemplateRuntimeError
] = UndefinedError
,
818 self
._undefined
_hint
= hint
819 self
._undefined
_obj
= obj
820 self
._undefined
_name
= name
821 self
._undefined
_exception
= exc
824 def _undefined_message(self
) -> str:
825 """Build a message about the undefined value based on how it was
828 if self
._undefined
_hint
:
829 return self
._undefined
_hint
831 if self
._undefined
_obj
is missing
:
832 return f
"{self._undefined_name!r} is undefined"
834 if not isinstance(self
._undefined
_name
, str):
836 f
"{object_type_repr(self._undefined_obj)} has no"
837 f
" element {self._undefined_name!r}"
841 f
"{object_type_repr(self._undefined_obj)!r} has no"
842 f
" attribute {self._undefined_name!r}"
846 def _fail_with_undefined_error(
847 self
, *args
: t
.Any
, **kwargs
: t
.Any
849 """Raise an :exc:`UndefinedError` when operations are performed
850 on the undefined value.
852 raise self
._undefined
_exception
(self
._undefined
_message
)
855 def __getattr__(self
, name
: str) -> t
.Any
:
857 raise AttributeError(name
)
859 return self
._fail
_with
_undefined
_error
()
861 __add__
= __radd__
= __sub__
= __rsub__
= _fail_with_undefined_error
862 __mul__
= __rmul__
= __div__
= __rdiv__
= _fail_with_undefined_error
863 __truediv__
= __rtruediv__
= _fail_with_undefined_error
864 __floordiv__
= __rfloordiv__
= _fail_with_undefined_error
865 __mod__
= __rmod__
= _fail_with_undefined_error
866 __pos__
= __neg__
= _fail_with_undefined_error
867 __call__
= __getitem__
= _fail_with_undefined_error
868 __lt__
= __le__
= __gt__
= __ge__
= _fail_with_undefined_error
869 __int__
= __float__
= __complex__
= _fail_with_undefined_error
870 __pow__
= __rpow__
= _fail_with_undefined_error
872 def __eq__(self
, other
: t
.Any
) -> bool:
873 return type(self
) is type(other
)
875 def __ne__(self
, other
: t
.Any
) -> bool:
876 return not self
.__eq
__(other
)
878 def __hash__(self
) -> int:
879 return id(type(self
))
881 def __str__(self
) -> str:
884 def __len__(self
) -> int:
887 def __iter__(self
) -> t
.Iterator
[t
.Any
]:
890 async def __aiter__(self
) -> t
.AsyncIterator
[t
.Any
]:
894 def __bool__(self
) -> bool:
897 def __repr__(self
) -> str:
901 def make_logging_undefined(
902 logger
: t
.Optional
["logging.Logger"] = None, base
: t
.Type
[Undefined
] = Undefined
903 ) -> t
.Type
[Undefined
]:
904 """Given a logger object this returns a new undefined class that will
905 log certain failures. It will log iterations and printing. If no
906 logger is given a default logger is created.
910 logger = logging.getLogger(__name__)
911 LoggingUndefined = make_logging_undefined(
916 .. versionadded:: 2.8
918 :param logger: the logger to use. If not provided, a default logger
920 :param base: the base class to add logging functionality to. This
921 defaults to :class:`Undefined`.
926 logger
= logging
.getLogger(__name__
)
927 logger
.addHandler(logging
.StreamHandler(sys
.stderr
))
929 def _log_message(undef
: Undefined
) -> None:
930 logger
.warning( # type: ignore
931 "Template variable warning: %s", undef
._undefined
_message
934 class LoggingUndefined(base
): # type: ignore
937 def _fail_with_undefined_error( # type: ignore
938 self
, *args
: t
.Any
, **kwargs
: t
.Any
941 super()._fail
_with
_undefined
_error
(*args
, **kwargs
)
942 except self
._undefined
_exception
as e
:
943 logger
.error("Template variable error: %s", e
) # type: ignore
946 def __str__(self
) -> str:
948 return super().__str
__() # type: ignore
950 def __iter__(self
) -> t
.Iterator
[t
.Any
]:
952 return super().__iter
__() # type: ignore
954 def __bool__(self
) -> bool:
956 return super().__bool
__() # type: ignore
958 return LoggingUndefined
961 class ChainableUndefined(Undefined
):
962 """An undefined that is chainable, where both ``__getattr__`` and
963 ``__getitem__`` return itself rather than raising an
964 :exc:`UndefinedError`.
966 >>> foo = ChainableUndefined(name='foo')
967 >>> str(foo.bar['baz'])
969 >>> foo.bar['baz'] + 42
970 Traceback (most recent call last):
972 jinja2.exceptions.UndefinedError: 'foo' is undefined
974 .. versionadded:: 2.11.0
979 def __html__(self
) -> str:
982 def __getattr__(self
, _
: str) -> "ChainableUndefined":
985 __getitem__
= __getattr__
# type: ignore
988 class DebugUndefined(Undefined
):
989 """An undefined that returns the debug info when printed.
991 >>> foo = DebugUndefined(name='foo')
997 Traceback (most recent call last):
999 jinja2.exceptions.UndefinedError: 'foo' is undefined
1004 def __str__(self
) -> str:
1005 if self
._undefined
_hint
:
1006 message
= f
"undefined value printed: {self._undefined_hint}"
1008 elif self
._undefined
_obj
is missing
:
1009 message
= self
._undefined
_name
# type: ignore
1013 f
"no such element: {object_type_repr(self._undefined_obj)}"
1014 f
"[{self._undefined_name!r}]"
1017 return f
"{{{{ {message} }}}}"
1020 class StrictUndefined(Undefined
):
1021 """An undefined that barks on print and iteration as well as boolean
1022 tests and all kinds of comparisons. In other words: you can do nothing
1023 with it except checking if it's defined using the `defined` test.
1025 >>> foo = StrictUndefined(name='foo')
1027 Traceback (most recent call last):
1029 jinja2.exceptions.UndefinedError: 'foo' is undefined
1031 Traceback (most recent call last):
1033 jinja2.exceptions.UndefinedError: 'foo' is undefined
1035 Traceback (most recent call last):
1037 jinja2.exceptions.UndefinedError: 'foo' is undefined
1041 __iter__
= __str__
= __len__
= Undefined
._fail
_with
_undefined
_error
1042 __eq__
= __ne__
= __bool__
= __hash__
= Undefined
._fail
_with
_undefined
_error
1043 __contains__
= Undefined
._fail
_with
_undefined
_error
1046 # Remove slots attributes, after the metaclass is applied they are
1047 # unneeded and contain wrong data for subclasses.
1049 Undefined
.__slots
__,
1050 ChainableUndefined
.__slots
__,
1051 DebugUndefined
.__slots
__,
1052 StrictUndefined
.__slots
__,