jinja2.runtime

The runtime functions and state used by compiled templates.

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

Returns its argument. Useful for certain things in the environment.

def markup_join(seq: Iterable[Any]) -> str:
78def markup_join(seq: t.Iterable[t.Any]) -> str:
79    """Concatenation that escapes if necessary and converts to string."""
80    buf = []
81    iterator = map(soft_str, seq)
82    for arg in iterator:
83        buf.append(arg)
84        if hasattr(arg, "__html__"):
85            return Markup("").join(chain(buf, iterator))
86    return concat(buf)

Concatenation that escapes if necessary and converts to string.

def str_join(seq: Iterable[Any]) -> str:
89def str_join(seq: t.Iterable[t.Any]) -> str:
90    """Simple args to string conversion and concatenation."""
91    return concat(map(str, seq))

Simple args to string conversion and concatenation.

def new_context( environment: jinja2.environment.Environment, template_name: Optional[str], blocks: Dict[str, Callable[[Context], Iterator[str]]], vars: Optional[Dict[str, Any]] = None, shared: bool = False, globals: Optional[MutableMapping[str, Any]] = None, locals: Optional[Mapping[str, Any]] = None) -> Context:
 94def new_context(
 95    environment: "Environment",
 96    template_name: t.Optional[str],
 97    blocks: t.Dict[str, t.Callable[["Context"], t.Iterator[str]]],
 98    vars: t.Optional[t.Dict[str, t.Any]] = None,
 99    shared: bool = False,
100    globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
101    locals: t.Optional[t.Mapping[str, t.Any]] = None,
102) -> "Context":
103    """Internal helper for context creation."""
104    if vars is None:
105        vars = {}
106    if shared:
107        parent = vars
108    else:
109        parent = dict(globals or (), **vars)
110    if locals:
111        # if the parent is shared a copy should be created because
112        # we don't want to modify the dict passed
113        if shared:
114            parent = dict(parent)
115        for key, value in locals.items():
116            if value is not missing:
117                parent[key] = value
118    return environment.context_class(
119        environment, parent, template_name, blocks, globals=globals
120    )

Internal helper for context creation.

class TemplateReference:
123class TemplateReference:
124    """The `self` in templates."""
125
126    def __init__(self, context: "Context") -> None:
127        self.__context = context
128
129    def __getitem__(self, name: str) -> t.Any:
130        blocks = self.__context.blocks[name]
131        return BlockReference(name, self.__context, blocks, 0)
132
133    def __repr__(self) -> str:
134        return f"<{type(self).__name__} {self.__context.name!r}>"

The self in templates.

TemplateReference(context: Context)
126    def __init__(self, context: "Context") -> None:
127        self.__context = context
@abc.Mapping.register
class Context:
145@abc.Mapping.register
146class Context:
147    """The template context holds the variables of a template.  It stores the
148    values passed to the template and also the names the template exports.
149    Creating instances is neither supported nor useful as it's created
150    automatically at various stages of the template evaluation and should not
151    be created by hand.
152
153    The context is immutable.  Modifications on :attr:`parent` **must not**
154    happen and modifications on :attr:`vars` are allowed from generated
155    template code only.  Template filters and global functions marked as
156    :func:`pass_context` get the active context passed as first argument
157    and are allowed to access the context read-only.
158
159    The template context supports read only dict operations (`get`,
160    `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`,
161    `__getitem__`, `__contains__`).  Additionally there is a :meth:`resolve`
162    method that doesn't fail with a `KeyError` but returns an
163    :class:`Undefined` object for missing variables.
164    """
165
166    def __init__(
167        self,
168        environment: "Environment",
169        parent: t.Dict[str, t.Any],
170        name: t.Optional[str],
171        blocks: t.Dict[str, t.Callable[["Context"], t.Iterator[str]]],
172        globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
173    ):
174        self.parent = parent
175        self.vars: t.Dict[str, t.Any] = {}
176        self.environment: "Environment" = environment
177        self.eval_ctx = EvalContext(self.environment, name)
178        self.exported_vars: t.Set[str] = set()
179        self.name = name
180        self.globals_keys = set() if globals is None else set(globals)
181
182        # create the initial mapping of blocks.  Whenever template inheritance
183        # takes place the runtime will update this mapping with the new blocks
184        # from the template.
185        self.blocks = {k: [v] for k, v in blocks.items()}
186
187    def super(
188        self, name: str, current: t.Callable[["Context"], t.Iterator[str]]
189    ) -> t.Union["BlockReference", "Undefined"]:
190        """Render a parent block."""
191        try:
192            blocks = self.blocks[name]
193            index = blocks.index(current) + 1
194            blocks[index]
195        except LookupError:
196            return self.environment.undefined(
197                f"there is no parent block called {name!r}.", name="super"
198            )
199        return BlockReference(name, self, blocks, index)
200
201    def get(self, key: str, default: t.Any = None) -> t.Any:
202        """Look up a variable by name, or return a default if the key is
203        not found.
204
205        :param key: The variable name to look up.
206        :param default: The value to return if the key is not found.
207        """
208        try:
209            return self[key]
210        except KeyError:
211            return default
212
213    def resolve(self, key: str) -> t.Union[t.Any, "Undefined"]:
214        """Look up a variable by name, or return an :class:`Undefined`
215        object if the key is not found.
216
217        If you need to add custom behavior, override
218        :meth:`resolve_or_missing`, not this method. The various lookup
219        functions use that method, not this one.
220
221        :param key: The variable name to look up.
222        """
223        rv = self.resolve_or_missing(key)
224
225        if rv is missing:
226            return self.environment.undefined(name=key)
227
228        return rv
229
230    def resolve_or_missing(self, key: str) -> t.Any:
231        """Look up a variable by name, or return a ``missing`` sentinel
232        if the key is not found.
233
234        Override this method to add custom lookup behavior.
235        :meth:`resolve`, :meth:`get`, and :meth:`__getitem__` use this
236        method. Don't call this method directly.
237
238        :param key: The variable name to look up.
239        """
240        if key in self.vars:
241            return self.vars[key]
242
243        if key in self.parent:
244            return self.parent[key]
245
246        return missing
247
248    def get_exported(self) -> t.Dict[str, t.Any]:
249        """Get a new dict with the exported variables."""
250        return {k: self.vars[k] for k in self.exported_vars}
251
252    def get_all(self) -> t.Dict[str, t.Any]:
253        """Return the complete context as dict including the exported
254        variables.  For optimizations reasons this might not return an
255        actual copy so be careful with using it.
256        """
257        if not self.vars:
258            return self.parent
259        if not self.parent:
260            return self.vars
261        return dict(self.parent, **self.vars)
262
263    @internalcode
264    def call(
265        __self,
266        __obj: t.Callable[..., t.Any],
267        *args: t.Any,
268        **kwargs: t.Any,  # noqa: B902
269    ) -> t.Union[t.Any, "Undefined"]:
270        """Call the callable with the arguments and keyword arguments
271        provided but inject the active context or environment as first
272        argument if the callable has :func:`pass_context` or
273        :func:`pass_environment`.
274        """
275        if __debug__:
276            __traceback_hide__ = True  # noqa
277
278        # Allow callable classes to take a context
279        if (
280            hasattr(__obj, "__call__")  # noqa: B004
281            and _PassArg.from_obj(__obj.__call__) is not None
282        ):
283            __obj = __obj.__call__
284
285        pass_arg = _PassArg.from_obj(__obj)
286
287        if pass_arg is _PassArg.context:
288            # the active context should have access to variables set in
289            # loops and blocks without mutating the context itself
290            if kwargs.get("_loop_vars"):
291                __self = __self.derived(kwargs["_loop_vars"])
292            if kwargs.get("_block_vars"):
293                __self = __self.derived(kwargs["_block_vars"])
294            args = (__self,) + args
295        elif pass_arg is _PassArg.eval_context:
296            args = (__self.eval_ctx,) + args
297        elif pass_arg is _PassArg.environment:
298            args = (__self.environment,) + args
299
300        kwargs.pop("_block_vars", None)
301        kwargs.pop("_loop_vars", None)
302
303        try:
304            return __obj(*args, **kwargs)
305        except StopIteration:
306            return __self.environment.undefined(
307                "value was undefined because a callable raised a"
308                " StopIteration exception"
309            )
310
311    def derived(self, locals: t.Optional[t.Dict[str, t.Any]] = None) -> "Context":
312        """Internal helper function to create a derived context.  This is
313        used in situations where the system needs a new context in the same
314        template that is independent.
315        """
316        context = new_context(
317            self.environment, self.name, {}, self.get_all(), True, None, locals
318        )
319        context.eval_ctx = self.eval_ctx
320        context.blocks.update((k, list(v)) for k, v in self.blocks.items())
321        return context
322
323    keys = _dict_method_all(dict.keys)
324    values = _dict_method_all(dict.values)
325    items = _dict_method_all(dict.items)
326
327    def __contains__(self, name: str) -> bool:
328        return name in self.vars or name in self.parent
329
330    def __getitem__(self, key: str) -> t.Any:
331        """Look up a variable by name with ``[]`` syntax, or raise a
332        ``KeyError`` if the key is not found.
333        """
334        item = self.resolve_or_missing(key)
335
336        if item is missing:
337            raise KeyError(key)
338
339        return item
340
341    def __repr__(self) -> str:
342        return f"<{type(self).__name__} {self.get_all()!r} of {self.name!r}>"

The template context holds the variables of a template. It stores the values passed to the template and also the names the template exports. Creating instances is neither supported nor useful as it's created automatically at various stages of the template evaluation and should not be created by hand.

The context is immutable. Modifications on parent must not happen and modifications on vars are allowed from generated template code only. Template filters and global functions marked as pass_context() get the active context passed as first argument and are allowed to access the context read-only.

The template context supports read only dict operations (get, keys, values, items, iterkeys, itervalues, iteritems, __getitem__, __contains__). Additionally there is a resolve() method that doesn't fail with a KeyError but returns an Undefined object for missing variables.

Context( environment: jinja2.environment.Environment, parent: Dict[str, Any], name: Optional[str], blocks: Dict[str, Callable[[Context], Iterator[str]]], globals: Optional[MutableMapping[str, Any]] = None)
166    def __init__(
167        self,
168        environment: "Environment",
169        parent: t.Dict[str, t.Any],
170        name: t.Optional[str],
171        blocks: t.Dict[str, t.Callable[["Context"], t.Iterator[str]]],
172        globals: t.Optional[t.MutableMapping[str, t.Any]] = None,
173    ):
174        self.parent = parent
175        self.vars: t.Dict[str, t.Any] = {}
176        self.environment: "Environment" = environment
177        self.eval_ctx = EvalContext(self.environment, name)
178        self.exported_vars: t.Set[str] = set()
179        self.name = name
180        self.globals_keys = set() if globals is None else set(globals)
181
182        # create the initial mapping of blocks.  Whenever template inheritance
183        # takes place the runtime will update this mapping with the new blocks
184        # from the template.
185        self.blocks = {k: [v] for k, v in blocks.items()}
parent
vars: Dict[str, Any]
eval_ctx
exported_vars: Set[str]
name
globals_keys
blocks
def super( self, name: str, current: Callable[[Context], Iterator[str]]) -> Union[BlockReference, Undefined]:
187    def super(
188        self, name: str, current: t.Callable[["Context"], t.Iterator[str]]
189    ) -> t.Union["BlockReference", "Undefined"]:
190        """Render a parent block."""
191        try:
192            blocks = self.blocks[name]
193            index = blocks.index(current) + 1
194            blocks[index]
195        except LookupError:
196            return self.environment.undefined(
197                f"there is no parent block called {name!r}.", name="super"
198            )
199        return BlockReference(name, self, blocks, index)

Render a parent block.

def get(self, key: str, default: Any = None) -> Any:
201    def get(self, key: str, default: t.Any = None) -> t.Any:
202        """Look up a variable by name, or return a default if the key is
203        not found.
204
205        :param key: The variable name to look up.
206        :param default: The value to return if the key is not found.
207        """
208        try:
209            return self[key]
210        except KeyError:
211            return default

Look up a variable by name, or return a default if the key is not found.

Parameters
  • key: The variable name to look up.
  • default: The value to return if the key is not found.
def resolve(self, key: str) -> Union[Any, Undefined]:
213    def resolve(self, key: str) -> t.Union[t.Any, "Undefined"]:
214        """Look up a variable by name, or return an :class:`Undefined`
215        object if the key is not found.
216
217        If you need to add custom behavior, override
218        :meth:`resolve_or_missing`, not this method. The various lookup
219        functions use that method, not this one.
220
221        :param key: The variable name to look up.
222        """
223        rv = self.resolve_or_missing(key)
224
225        if rv is missing:
226            return self.environment.undefined(name=key)
227
228        return rv

Look up a variable by name, or return an Undefined object if the key is not found.

If you need to add custom behavior, override resolve_or_missing(), not this method. The various lookup functions use that method, not this one.

Parameters
  • key: The variable name to look up.
def resolve_or_missing(self, key: str) -> Any:
230    def resolve_or_missing(self, key: str) -> t.Any:
231        """Look up a variable by name, or return a ``missing`` sentinel
232        if the key is not found.
233
234        Override this method to add custom lookup behavior.
235        :meth:`resolve`, :meth:`get`, and :meth:`__getitem__` use this
236        method. Don't call this method directly.
237
238        :param key: The variable name to look up.
239        """
240        if key in self.vars:
241            return self.vars[key]
242
243        if key in self.parent:
244            return self.parent[key]
245
246        return missing

Look up a variable by name, or return a missing sentinel if the key is not found.

Override this method to add custom lookup behavior. resolve(), get(), and __getitem__() use this method. Don't call this method directly.

Parameters
  • key: The variable name to look up.
def get_exported(self) -> Dict[str, Any]:
248    def get_exported(self) -> t.Dict[str, t.Any]:
249        """Get a new dict with the exported variables."""
250        return {k: self.vars[k] for k in self.exported_vars}

Get a new dict with the exported variables.

def get_all(self) -> Dict[str, Any]:
252    def get_all(self) -> t.Dict[str, t.Any]:
253        """Return the complete context as dict including the exported
254        variables.  For optimizations reasons this might not return an
255        actual copy so be careful with using it.
256        """
257        if not self.vars:
258            return self.parent
259        if not self.parent:
260            return self.vars
261        return dict(self.parent, **self.vars)

Return the complete context as dict including the exported variables. For optimizations reasons this might not return an actual copy so be careful with using it.

@internalcode
def call( _Context__self, _Context__obj: Callable[..., Any], *args: Any, **kwargs: Any) -> Union[Any, Undefined]:
263    @internalcode
264    def call(
265        __self,
266        __obj: t.Callable[..., t.Any],
267        *args: t.Any,
268        **kwargs: t.Any,  # noqa: B902
269    ) -> t.Union[t.Any, "Undefined"]:
270        """Call the callable with the arguments and keyword arguments
271        provided but inject the active context or environment as first
272        argument if the callable has :func:`pass_context` or
273        :func:`pass_environment`.
274        """
275        if __debug__:
276            __traceback_hide__ = True  # noqa
277
278        # Allow callable classes to take a context
279        if (
280            hasattr(__obj, "__call__")  # noqa: B004
281            and _PassArg.from_obj(__obj.__call__) is not None
282        ):
283            __obj = __obj.__call__
284
285        pass_arg = _PassArg.from_obj(__obj)
286
287        if pass_arg is _PassArg.context:
288            # the active context should have access to variables set in
289            # loops and blocks without mutating the context itself
290            if kwargs.get("_loop_vars"):
291                __self = __self.derived(kwargs["_loop_vars"])
292            if kwargs.get("_block_vars"):
293                __self = __self.derived(kwargs["_block_vars"])
294            args = (__self,) + args
295        elif pass_arg is _PassArg.eval_context:
296            args = (__self.eval_ctx,) + args
297        elif pass_arg is _PassArg.environment:
298            args = (__self.environment,) + args
299
300        kwargs.pop("_block_vars", None)
301        kwargs.pop("_loop_vars", None)
302
303        try:
304            return __obj(*args, **kwargs)
305        except StopIteration:
306            return __self.environment.undefined(
307                "value was undefined because a callable raised a"
308                " StopIteration exception"
309            )

Call the callable with the arguments and keyword arguments provided but inject the active context or environment as first argument if the callable has pass_context() or pass_environment().

def derived(self, locals: Optional[Dict[str, Any]] = None) -> Context:
311    def derived(self, locals: t.Optional[t.Dict[str, t.Any]] = None) -> "Context":
312        """Internal helper function to create a derived context.  This is
313        used in situations where the system needs a new context in the same
314        template that is independent.
315        """
316        context = new_context(
317            self.environment, self.name, {}, self.get_all(), True, None, locals
318        )
319        context.eval_ctx = self.eval_ctx
320        context.blocks.update((k, list(v)) for k, v in self.blocks.items())
321        return context

Internal helper function to create a derived context. This is used in situations where the system needs a new context in the same template that is independent.

def keys(unknown):

D.keys() -> a set-like object providing a view on D's keys

def values(unknown):

D.values() -> an object providing a view on D's values

def items(unknown):

D.items() -> a set-like object providing a view on D's items

class BlockReference:
345class BlockReference:
346    """One block on a template reference."""
347
348    def __init__(
349        self,
350        name: str,
351        context: "Context",
352        stack: t.List[t.Callable[["Context"], t.Iterator[str]]],
353        depth: int,
354    ) -> None:
355        self.name = name
356        self._context = context
357        self._stack = stack
358        self._depth = depth
359
360    @property
361    def super(self) -> t.Union["BlockReference", "Undefined"]:
362        """Super the block."""
363        if self._depth + 1 >= len(self._stack):
364            return self._context.environment.undefined(
365                f"there is no parent block called {self.name!r}.", name="super"
366            )
367        return BlockReference(self.name, self._context, self._stack, self._depth + 1)
368
369    @internalcode
370    async def _async_call(self) -> str:
371        rv = concat(
372            [x async for x in self._stack[self._depth](self._context)]  # type: ignore
373        )
374
375        if self._context.eval_ctx.autoescape:
376            return Markup(rv)
377
378        return rv
379
380    @internalcode
381    def __call__(self) -> str:
382        if self._context.environment.is_async:
383            return self._async_call()  # type: ignore
384
385        rv = concat(self._stack[self._depth](self._context))
386
387        if self._context.eval_ctx.autoescape:
388            return Markup(rv)
389
390        return rv

One block on a template reference.

BlockReference( name: str, context: Context, stack: List[Callable[[Context], Iterator[str]]], depth: int)
348    def __init__(
349        self,
350        name: str,
351        context: "Context",
352        stack: t.List[t.Callable[["Context"], t.Iterator[str]]],
353        depth: int,
354    ) -> None:
355        self.name = name
356        self._context = context
357        self._stack = stack
358        self._depth = depth
name
super: Union[BlockReference, Undefined]
360    @property
361    def super(self) -> t.Union["BlockReference", "Undefined"]:
362        """Super the block."""
363        if self._depth + 1 >= len(self._stack):
364            return self._context.environment.undefined(
365                f"there is no parent block called {self.name!r}.", name="super"
366            )
367        return BlockReference(self.name, self._context, self._stack, self._depth + 1)

Super the block.

class LoopContext:
393class LoopContext:
394    """A wrapper iterable for dynamic ``for`` loops, with information
395    about the loop and iteration.
396    """
397
398    #: Current iteration of the loop, starting at 0.
399    index0 = -1
400
401    _length: t.Optional[int] = None
402    _after: t.Any = missing
403    _current: t.Any = missing
404    _before: t.Any = missing
405    _last_changed_value: t.Any = missing
406
407    def __init__(
408        self,
409        iterable: t.Iterable[V],
410        undefined: t.Type["Undefined"],
411        recurse: t.Optional["LoopRenderFunc"] = None,
412        depth0: int = 0,
413    ) -> None:
414        """
415        :param iterable: Iterable to wrap.
416        :param undefined: :class:`Undefined` class to use for next and
417            previous items.
418        :param recurse: The function to render the loop body when the
419            loop is marked recursive.
420        :param depth0: Incremented when looping recursively.
421        """
422        self._iterable = iterable
423        self._iterator = self._to_iterator(iterable)
424        self._undefined = undefined
425        self._recurse = recurse
426        #: How many levels deep a recursive loop currently is, starting at 0.
427        self.depth0 = depth0
428
429    @staticmethod
430    def _to_iterator(iterable: t.Iterable[V]) -> t.Iterator[V]:
431        return iter(iterable)
432
433    @property
434    def length(self) -> int:
435        """Length of the iterable.
436
437        If the iterable is a generator or otherwise does not have a
438        size, it is eagerly evaluated to get a size.
439        """
440        if self._length is not None:
441            return self._length
442
443        try:
444            self._length = len(self._iterable)  # type: ignore
445        except TypeError:
446            iterable = list(self._iterator)
447            self._iterator = self._to_iterator(iterable)
448            self._length = len(iterable) + self.index + (self._after is not missing)
449
450        return self._length
451
452    def __len__(self) -> int:
453        return self.length
454
455    @property
456    def depth(self) -> int:
457        """How many levels deep a recursive loop currently is, starting at 1."""
458        return self.depth0 + 1
459
460    @property
461    def index(self) -> int:
462        """Current iteration of the loop, starting at 1."""
463        return self.index0 + 1
464
465    @property
466    def revindex0(self) -> int:
467        """Number of iterations from the end of the loop, ending at 0.
468
469        Requires calculating :attr:`length`.
470        """
471        return self.length - self.index
472
473    @property
474    def revindex(self) -> int:
475        """Number of iterations from the end of the loop, ending at 1.
476
477        Requires calculating :attr:`length`.
478        """
479        return self.length - self.index0
480
481    @property
482    def first(self) -> bool:
483        """Whether this is the first iteration of the loop."""
484        return self.index0 == 0
485
486    def _peek_next(self) -> t.Any:
487        """Return the next element in the iterable, or :data:`missing`
488        if the iterable is exhausted. Only peeks one item ahead, caching
489        the result in :attr:`_last` for use in subsequent checks. The
490        cache is reset when :meth:`__next__` is called.
491        """
492        if self._after is not missing:
493            return self._after
494
495        self._after = next(self._iterator, missing)
496        return self._after
497
498    @property
499    def last(self) -> bool:
500        """Whether this is the last iteration of the loop.
501
502        Causes the iterable to advance early. See
503        :func:`itertools.groupby` for issues this can cause.
504        The :func:`groupby` filter avoids that issue.
505        """
506        return self._peek_next() is missing
507
508    @property
509    def previtem(self) -> t.Union[t.Any, "Undefined"]:
510        """The item in the previous iteration. Undefined during the
511        first iteration.
512        """
513        if self.first:
514            return self._undefined("there is no previous item")
515
516        return self._before
517
518    @property
519    def nextitem(self) -> t.Union[t.Any, "Undefined"]:
520        """The item in the next iteration. Undefined during the last
521        iteration.
522
523        Causes the iterable to advance early. See
524        :func:`itertools.groupby` for issues this can cause.
525        The :func:`jinja-filters.groupby` filter avoids that issue.
526        """
527        rv = self._peek_next()
528
529        if rv is missing:
530            return self._undefined("there is no next item")
531
532        return rv
533
534    def cycle(self, *args: V) -> V:
535        """Return a value from the given args, cycling through based on
536        the current :attr:`index0`.
537
538        :param args: One or more values to cycle through.
539        """
540        if not args:
541            raise TypeError("no items for cycling given")
542
543        return args[self.index0 % len(args)]
544
545    def changed(self, *value: t.Any) -> bool:
546        """Return ``True`` if previously called with a different value
547        (including when called for the first time).
548
549        :param value: One or more values to compare to the last call.
550        """
551        if self._last_changed_value != value:
552            self._last_changed_value = value
553            return True
554
555        return False
556
557    def __iter__(self) -> "LoopContext":
558        return self
559
560    def __next__(self) -> t.Tuple[t.Any, "LoopContext"]:
561        if self._after is not missing:
562            rv = self._after
563            self._after = missing
564        else:
565            rv = next(self._iterator)
566
567        self.index0 += 1
568        self._before = self._current
569        self._current = rv
570        return rv, self
571
572    @internalcode
573    def __call__(self, iterable: t.Iterable[V]) -> str:
574        """When iterating over nested data, render the body of the loop
575        recursively with the given inner iterable data.
576
577        The loop must have the ``recursive`` marker for this to work.
578        """
579        if self._recurse is None:
580            raise TypeError(
581                "The loop must have the 'recursive' marker to be called recursively."
582            )
583
584        return self._recurse(iterable, self._recurse, depth=self.depth)
585
586    def __repr__(self) -> str:
587        return f"<{type(self).__name__} {self.index}/{self.length}>"

A wrapper iterable for dynamic for loops, with information about the loop and iteration.

LoopContext( iterable: Iterable[~V], undefined: Type[Undefined], recurse: Optional[jinja2.runtime.LoopRenderFunc] = None, depth0: int = 0)
407    def __init__(
408        self,
409        iterable: t.Iterable[V],
410        undefined: t.Type["Undefined"],
411        recurse: t.Optional["LoopRenderFunc"] = None,
412        depth0: int = 0,
413    ) -> None:
414        """
415        :param iterable: Iterable to wrap.
416        :param undefined: :class:`Undefined` class to use for next and
417            previous items.
418        :param recurse: The function to render the loop body when the
419            loop is marked recursive.
420        :param depth0: Incremented when looping recursively.
421        """
422        self._iterable = iterable
423        self._iterator = self._to_iterator(iterable)
424        self._undefined = undefined
425        self._recurse = recurse
426        #: How many levels deep a recursive loop currently is, starting at 0.
427        self.depth0 = depth0
Parameters
  • iterable: Iterable to wrap.
  • undefined: Undefined class to use for next and previous items.
  • recurse: The function to render the loop body when the loop is marked recursive.
  • depth0: Incremented when looping recursively.
index0 = -1
depth0
length: int
433    @property
434    def length(self) -> int:
435        """Length of the iterable.
436
437        If the iterable is a generator or otherwise does not have a
438        size, it is eagerly evaluated to get a size.
439        """
440        if self._length is not None:
441            return self._length
442
443        try:
444            self._length = len(self._iterable)  # type: ignore
445        except TypeError:
446            iterable = list(self._iterator)
447            self._iterator = self._to_iterator(iterable)
448            self._length = len(iterable) + self.index + (self._after is not missing)
449
450        return self._length

Length of the iterable.

If the iterable is a generator or otherwise does not have a size, it is eagerly evaluated to get a size.

depth: int
455    @property
456    def depth(self) -> int:
457        """How many levels deep a recursive loop currently is, starting at 1."""
458        return self.depth0 + 1

How many levels deep a recursive loop currently is, starting at 1.

index: int
460    @property
461    def index(self) -> int:
462        """Current iteration of the loop, starting at 1."""
463        return self.index0 + 1

Current iteration of the loop, starting at 1.

revindex0: int
465    @property
466    def revindex0(self) -> int:
467        """Number of iterations from the end of the loop, ending at 0.
468
469        Requires calculating :attr:`length`.
470        """
471        return self.length - self.index

Number of iterations from the end of the loop, ending at 0.

Requires calculating length.

revindex: int
473    @property
474    def revindex(self) -> int:
475        """Number of iterations from the end of the loop, ending at 1.
476
477        Requires calculating :attr:`length`.
478        """
479        return self.length - self.index0

Number of iterations from the end of the loop, ending at 1.

Requires calculating length.

first: bool
481    @property
482    def first(self) -> bool:
483        """Whether this is the first iteration of the loop."""
484        return self.index0 == 0

Whether this is the first iteration of the loop.

last: bool
498    @property
499    def last(self) -> bool:
500        """Whether this is the last iteration of the loop.
501
502        Causes the iterable to advance early. See
503        :func:`itertools.groupby` for issues this can cause.
504        The :func:`groupby` filter avoids that issue.
505        """
506        return self._peek_next() is missing

Whether this is the last iteration of the loop.

Causes the iterable to advance early. See itertools.groupby() for issues this can cause. The groupby() filter avoids that issue.

previtem: Union[Any, Undefined]
508    @property
509    def previtem(self) -> t.Union[t.Any, "Undefined"]:
510        """The item in the previous iteration. Undefined during the
511        first iteration.
512        """
513        if self.first:
514            return self._undefined("there is no previous item")
515
516        return self._before

The item in the previous iteration. Undefined during the first iteration.

nextitem: Union[Any, Undefined]
518    @property
519    def nextitem(self) -> t.Union[t.Any, "Undefined"]:
520        """The item in the next iteration. Undefined during the last
521        iteration.
522
523        Causes the iterable to advance early. See
524        :func:`itertools.groupby` for issues this can cause.
525        The :func:`jinja-filters.groupby` filter avoids that issue.
526        """
527        rv = self._peek_next()
528
529        if rv is missing:
530            return self._undefined("there is no next item")
531
532        return rv

The item in the next iteration. Undefined during the last iteration.

Causes the iterable to advance early. See itertools.groupby() for issues this can cause. The jinja-filters.groupby() filter avoids that issue.

def cycle(self, *args: ~V) -> ~V:
534    def cycle(self, *args: V) -> V:
535        """Return a value from the given args, cycling through based on
536        the current :attr:`index0`.
537
538        :param args: One or more values to cycle through.
539        """
540        if not args:
541            raise TypeError("no items for cycling given")
542
543        return args[self.index0 % len(args)]

Return a value from the given args, cycling through based on the current index0.

Parameters
  • args: One or more values to cycle through.
def changed(self, *value: Any) -> bool:
545    def changed(self, *value: t.Any) -> bool:
546        """Return ``True`` if previously called with a different value
547        (including when called for the first time).
548
549        :param value: One or more values to compare to the last call.
550        """
551        if self._last_changed_value != value:
552            self._last_changed_value = value
553            return True
554
555        return False

Return True if previously called with a different value (including when called for the first time).

Parameters
  • value: One or more values to compare to the last call.
class AsyncLoopContext(LoopContext):
590class AsyncLoopContext(LoopContext):
591    _iterator: t.AsyncIterator[t.Any]  # type: ignore
592
593    @staticmethod
594    def _to_iterator(  # type: ignore
595        iterable: t.Union[t.Iterable[V], t.AsyncIterable[V]],
596    ) -> t.AsyncIterator[V]:
597        return auto_aiter(iterable)
598
599    @property
600    async def length(self) -> int:  # type: ignore
601        if self._length is not None:
602            return self._length
603
604        try:
605            self._length = len(self._iterable)  # type: ignore
606        except TypeError:
607            iterable = [x async for x in self._iterator]
608            self._iterator = self._to_iterator(iterable)
609            self._length = len(iterable) + self.index + (self._after is not missing)
610
611        return self._length
612
613    @property
614    async def revindex0(self) -> int:  # type: ignore
615        return await self.length - self.index
616
617    @property
618    async def revindex(self) -> int:  # type: ignore
619        return await self.length - self.index0
620
621    async def _peek_next(self) -> t.Any:
622        if self._after is not missing:
623            return self._after
624
625        try:
626            self._after = await self._iterator.__anext__()
627        except StopAsyncIteration:
628            self._after = missing
629
630        return self._after
631
632    @property
633    async def last(self) -> bool:  # type: ignore
634        return await self._peek_next() is missing
635
636    @property
637    async def nextitem(self) -> t.Union[t.Any, "Undefined"]:
638        rv = await self._peek_next()
639
640        if rv is missing:
641            return self._undefined("there is no next item")
642
643        return rv
644
645    def __aiter__(self) -> "AsyncLoopContext":
646        return self
647
648    async def __anext__(self) -> t.Tuple[t.Any, "AsyncLoopContext"]:
649        if self._after is not missing:
650            rv = self._after
651            self._after = missing
652        else:
653            rv = await self._iterator.__anext__()
654
655        self.index0 += 1
656        self._before = self._current
657        self._current = rv
658        return rv, self

A wrapper iterable for dynamic for loops, with information about the loop and iteration.

length: int
599    @property
600    async def length(self) -> int:  # type: ignore
601        if self._length is not None:
602            return self._length
603
604        try:
605            self._length = len(self._iterable)  # type: ignore
606        except TypeError:
607            iterable = [x async for x in self._iterator]
608            self._iterator = self._to_iterator(iterable)
609            self._length = len(iterable) + self.index + (self._after is not missing)
610
611        return self._length

Length of the iterable.

If the iterable is a generator or otherwise does not have a size, it is eagerly evaluated to get a size.

revindex0: int
613    @property
614    async def revindex0(self) -> int:  # type: ignore
615        return await self.length - self.index

Number of iterations from the end of the loop, ending at 0.

Requires calculating length.

revindex: int
617    @property
618    async def revindex(self) -> int:  # type: ignore
619        return await self.length - self.index0

Number of iterations from the end of the loop, ending at 1.

Requires calculating length.

last: bool
632    @property
633    async def last(self) -> bool:  # type: ignore
634        return await self._peek_next() is missing

Whether this is the last iteration of the loop.

Causes the iterable to advance early. See itertools.groupby() for issues this can cause. The groupby() filter avoids that issue.

nextitem: Union[Any, Undefined]
636    @property
637    async def nextitem(self) -> t.Union[t.Any, "Undefined"]:
638        rv = await self._peek_next()
639
640        if rv is missing:
641            return self._undefined("there is no next item")
642
643        return rv

The item in the next iteration. Undefined during the last iteration.

Causes the iterable to advance early. See itertools.groupby() for issues this can cause. The jinja-filters.groupby() filter avoids that issue.

class Macro:
661class Macro:
662    """Wraps a macro function."""
663
664    def __init__(
665        self,
666        environment: "Environment",
667        func: t.Callable[..., str],
668        name: str,
669        arguments: t.List[str],
670        catch_kwargs: bool,
671        catch_varargs: bool,
672        caller: bool,
673        default_autoescape: t.Optional[bool] = None,
674    ):
675        self._environment = environment
676        self._func = func
677        self._argument_count = len(arguments)
678        self.name = name
679        self.arguments = arguments
680        self.catch_kwargs = catch_kwargs
681        self.catch_varargs = catch_varargs
682        self.caller = caller
683        self.explicit_caller = "caller" in arguments
684
685        if default_autoescape is None:
686            if callable(environment.autoescape):
687                default_autoescape = environment.autoescape(None)
688            else:
689                default_autoescape = environment.autoescape
690
691        self._default_autoescape = default_autoescape
692
693    @internalcode
694    @pass_eval_context
695    def __call__(self, *args: t.Any, **kwargs: t.Any) -> str:
696        # This requires a bit of explanation,  In the past we used to
697        # decide largely based on compile-time information if a macro is
698        # safe or unsafe.  While there was a volatile mode it was largely
699        # unused for deciding on escaping.  This turns out to be
700        # problematic for macros because whether a macro is safe depends not
701        # on the escape mode when it was defined, but rather when it was used.
702        #
703        # Because however we export macros from the module system and
704        # there are historic callers that do not pass an eval context (and
705        # will continue to not pass one), we need to perform an instance
706        # check here.
707        #
708        # This is considered safe because an eval context is not a valid
709        # argument to callables otherwise anyway.  Worst case here is
710        # that if no eval context is passed we fall back to the compile
711        # time autoescape flag.
712        if args and isinstance(args[0], EvalContext):
713            autoescape = args[0].autoescape
714            args = args[1:]
715        else:
716            autoescape = self._default_autoescape
717
718        # try to consume the positional arguments
719        arguments = list(args[: self._argument_count])
720        off = len(arguments)
721
722        # For information why this is necessary refer to the handling
723        # of caller in the `macro_body` handler in the compiler.
724        found_caller = False
725
726        # if the number of arguments consumed is not the number of
727        # arguments expected we start filling in keyword arguments
728        # and defaults.
729        if off != self._argument_count:
730            for name in self.arguments[len(arguments) :]:
731                try:
732                    value = kwargs.pop(name)
733                except KeyError:
734                    value = missing
735                if name == "caller":
736                    found_caller = True
737                arguments.append(value)
738        else:
739            found_caller = self.explicit_caller
740
741        # it's important that the order of these arguments does not change
742        # if not also changed in the compiler's `function_scoping` method.
743        # the order is caller, keyword arguments, positional arguments!
744        if self.caller and not found_caller:
745            caller = kwargs.pop("caller", None)
746            if caller is None:
747                caller = self._environment.undefined("No caller defined", name="caller")
748            arguments.append(caller)
749
750        if self.catch_kwargs:
751            arguments.append(kwargs)
752        elif kwargs:
753            if "caller" in kwargs:
754                raise TypeError(
755                    f"macro {self.name!r} was invoked with two values for the special"
756                    " caller argument. This is most likely a bug."
757                )
758            raise TypeError(
759                f"macro {self.name!r} takes no keyword argument {next(iter(kwargs))!r}"
760            )
761        if self.catch_varargs:
762            arguments.append(args[self._argument_count :])
763        elif len(args) > self._argument_count:
764            raise TypeError(
765                f"macro {self.name!r} takes not more than"
766                f" {len(self.arguments)} argument(s)"
767            )
768
769        return self._invoke(arguments, autoescape)
770
771    async def _async_invoke(self, arguments: t.List[t.Any], autoescape: bool) -> str:
772        rv = await self._func(*arguments)  # type: ignore
773
774        if autoescape:
775            return Markup(rv)
776
777        return rv  # type: ignore
778
779    def _invoke(self, arguments: t.List[t.Any], autoescape: bool) -> str:
780        if self._environment.is_async:
781            return self._async_invoke(arguments, autoescape)  # type: ignore
782
783        rv = self._func(*arguments)
784
785        if autoescape:
786            rv = Markup(rv)
787
788        return rv
789
790    def __repr__(self) -> str:
791        name = "anonymous" if self.name is None else repr(self.name)
792        return f"<{type(self).__name__} {name}>"

Wraps a macro function.

Macro( environment: jinja2.environment.Environment, func: Callable[..., str], name: str, arguments: List[str], catch_kwargs: bool, catch_varargs: bool, caller: bool, default_autoescape: Optional[bool] = None)
664    def __init__(
665        self,
666        environment: "Environment",
667        func: t.Callable[..., str],
668        name: str,
669        arguments: t.List[str],
670        catch_kwargs: bool,
671        catch_varargs: bool,
672        caller: bool,
673        default_autoescape: t.Optional[bool] = None,
674    ):
675        self._environment = environment
676        self._func = func
677        self._argument_count = len(arguments)
678        self.name = name
679        self.arguments = arguments
680        self.catch_kwargs = catch_kwargs
681        self.catch_varargs = catch_varargs
682        self.caller = caller
683        self.explicit_caller = "caller" in arguments
684
685        if default_autoescape is None:
686            if callable(environment.autoescape):
687                default_autoescape = environment.autoescape(None)
688            else:
689                default_autoescape = environment.autoescape
690
691        self._default_autoescape = default_autoescape
name
arguments
catch_kwargs
catch_varargs
caller
explicit_caller
class Undefined:
795class Undefined:
796    """The default undefined type.  This undefined type can be printed and
797    iterated over, but every other access will raise an :exc:`UndefinedError`:
798
799    >>> foo = Undefined(name='foo')
800    >>> str(foo)
801    ''
802    >>> not foo
803    True
804    >>> foo + 42
805    Traceback (most recent call last):
806      ...
807    jinja2.exceptions.UndefinedError: 'foo' is undefined
808    """
809
810    __slots__ = (
811        "_undefined_hint",
812        "_undefined_obj",
813        "_undefined_name",
814        "_undefined_exception",
815    )
816
817    def __init__(
818        self,
819        hint: t.Optional[str] = None,
820        obj: t.Any = missing,
821        name: t.Optional[str] = None,
822        exc: t.Type[TemplateRuntimeError] = UndefinedError,
823    ) -> None:
824        self._undefined_hint = hint
825        self._undefined_obj = obj
826        self._undefined_name = name
827        self._undefined_exception = exc
828
829    @property
830    def _undefined_message(self) -> str:
831        """Build a message about the undefined value based on how it was
832        accessed.
833        """
834        if self._undefined_hint:
835            return self._undefined_hint
836
837        if self._undefined_obj is missing:
838            return f"{self._undefined_name!r} is undefined"
839
840        if not isinstance(self._undefined_name, str):
841            return (
842                f"{object_type_repr(self._undefined_obj)} has no"
843                f" element {self._undefined_name!r}"
844            )
845
846        return (
847            f"{object_type_repr(self._undefined_obj)!r} has no"
848            f" attribute {self._undefined_name!r}"
849        )
850
851    @internalcode
852    def _fail_with_undefined_error(
853        self, *args: t.Any, **kwargs: t.Any
854    ) -> "te.NoReturn":
855        """Raise an :exc:`UndefinedError` when operations are performed
856        on the undefined value.
857        """
858        raise self._undefined_exception(self._undefined_message)
859
860    @internalcode
861    def __getattr__(self, name: str) -> t.Any:
862        if name[:2] == "__":
863            raise AttributeError(name)
864
865        return self._fail_with_undefined_error()
866
867    __add__ = __radd__ = __sub__ = __rsub__ = _fail_with_undefined_error
868    __mul__ = __rmul__ = __div__ = __rdiv__ = _fail_with_undefined_error
869    __truediv__ = __rtruediv__ = _fail_with_undefined_error
870    __floordiv__ = __rfloordiv__ = _fail_with_undefined_error
871    __mod__ = __rmod__ = _fail_with_undefined_error
872    __pos__ = __neg__ = _fail_with_undefined_error
873    __call__ = __getitem__ = _fail_with_undefined_error
874    __lt__ = __le__ = __gt__ = __ge__ = _fail_with_undefined_error
875    __int__ = __float__ = __complex__ = _fail_with_undefined_error
876    __pow__ = __rpow__ = _fail_with_undefined_error
877
878    def __eq__(self, other: t.Any) -> bool:
879        return type(self) is type(other)
880
881    def __ne__(self, other: t.Any) -> bool:
882        return not self.__eq__(other)
883
884    def __hash__(self) -> int:
885        return id(type(self))
886
887    def __str__(self) -> str:
888        return ""
889
890    def __len__(self) -> int:
891        return 0
892
893    def __iter__(self) -> t.Iterator[t.Any]:
894        yield from ()
895
896    async def __aiter__(self) -> t.AsyncIterator[t.Any]:
897        for _ in ():
898            yield
899
900    def __bool__(self) -> bool:
901        return False
902
903    def __repr__(self) -> str:
904        return "Undefined"

The default undefined type. This undefined type can be printed and iterated over, but every other access will raise an UndefinedError:

>>> foo = Undefined(name='foo')
>>> str(foo)
''
>>> not foo
True
>>> foo + 42
Traceback (most recent call last):
  ...
jinja2.exceptions.UndefinedError: 'foo' is undefined
Undefined( hint: Optional[str] = None, obj: Any = missing, name: Optional[str] = None, exc: Type[jinja2.exceptions.TemplateRuntimeError] = <class 'jinja2.exceptions.UndefinedError'>)
817    def __init__(
818        self,
819        hint: t.Optional[str] = None,
820        obj: t.Any = missing,
821        name: t.Optional[str] = None,
822        exc: t.Type[TemplateRuntimeError] = UndefinedError,
823    ) -> None:
824        self._undefined_hint = hint
825        self._undefined_obj = obj
826        self._undefined_name = name
827        self._undefined_exception = exc
def make_logging_undefined( logger: Optional[logging.Logger] = None, base: Type[Undefined] = <class 'Undefined'>) -> Type[Undefined]:
907def make_logging_undefined(
908    logger: t.Optional["logging.Logger"] = None, base: t.Type[Undefined] = Undefined
909) -> t.Type[Undefined]:
910    """Given a logger object this returns a new undefined class that will
911    log certain failures.  It will log iterations and printing.  If no
912    logger is given a default logger is created.
913
914    Example::
915
916        logger = logging.getLogger(__name__)
917        LoggingUndefined = make_logging_undefined(
918            logger=logger,
919            base=Undefined
920        )
921
922    .. versionadded:: 2.8
923
924    :param logger: the logger to use.  If not provided, a default logger
925                   is created.
926    :param base: the base class to add logging functionality to.  This
927                 defaults to :class:`Undefined`.
928    """
929    if logger is None:
930        import logging
931
932        logger = logging.getLogger(__name__)
933        logger.addHandler(logging.StreamHandler(sys.stderr))
934
935    def _log_message(undef: Undefined) -> None:
936        logger.warning("Template variable warning: %s", undef._undefined_message)
937
938    class LoggingUndefined(base):  # type: ignore
939        __slots__ = ()
940
941        def _fail_with_undefined_error(  # type: ignore
942            self, *args: t.Any, **kwargs: t.Any
943        ) -> "te.NoReturn":
944            try:
945                super()._fail_with_undefined_error(*args, **kwargs)
946            except self._undefined_exception as e:
947                logger.error("Template variable error: %s", e)  # type: ignore
948                raise e
949
950        def __str__(self) -> str:
951            _log_message(self)
952            return super().__str__()  # type: ignore
953
954        def __iter__(self) -> t.Iterator[t.Any]:
955            _log_message(self)
956            return super().__iter__()  # type: ignore
957
958        def __bool__(self) -> bool:
959            _log_message(self)
960            return super().__bool__()  # type: ignore
961
962    return LoggingUndefined

Given a logger object this returns a new undefined class that will log certain failures. It will log iterations and printing. If no logger is given a default logger is created.

Example::

logger = logging.getLogger(__name__)
LoggingUndefined = make_logging_undefined(
    logger=logger,
    base=Undefined
)

New in version 2.8.

Parameters
  • logger: the logger to use. If not provided, a default logger is created.
  • base: the base class to add logging functionality to. This defaults to Undefined.
class ChainableUndefined(Undefined):
965class ChainableUndefined(Undefined):
966    """An undefined that is chainable, where both ``__getattr__`` and
967    ``__getitem__`` return itself rather than raising an
968    :exc:`UndefinedError`.
969
970    >>> foo = ChainableUndefined(name='foo')
971    >>> str(foo.bar['baz'])
972    ''
973    >>> foo.bar['baz'] + 42
974    Traceback (most recent call last):
975      ...
976    jinja2.exceptions.UndefinedError: 'foo' is undefined
977
978    .. versionadded:: 2.11.0
979    """
980
981    __slots__ = ()
982
983    def __html__(self) -> str:
984        return str(self)
985
986    def __getattr__(self, _: str) -> "ChainableUndefined":
987        return self
988
989    __getitem__ = __getattr__  # type: ignore

An undefined that is chainable, where both __getattr__ and __getitem__ return itself rather than raising an UndefinedError.

>>> foo = ChainableUndefined(name='foo')
>>> str(foo.bar['baz'])
''
>>> foo.bar['baz'] + 42
Traceback (most recent call last):
  ...
jinja2.exceptions.UndefinedError: 'foo' is undefined

New in version 2.11.0.

Inherited Members
Undefined
Undefined
class DebugUndefined(Undefined):
 992class DebugUndefined(Undefined):
 993    """An undefined that returns the debug info when printed.
 994
 995    >>> foo = DebugUndefined(name='foo')
 996    >>> str(foo)
 997    '{{ foo }}'
 998    >>> not foo
 999    True
1000    >>> foo + 42
1001    Traceback (most recent call last):
1002      ...
1003    jinja2.exceptions.UndefinedError: 'foo' is undefined
1004    """
1005
1006    __slots__ = ()
1007
1008    def __str__(self) -> str:
1009        if self._undefined_hint:
1010            message = f"undefined value printed: {self._undefined_hint}"
1011
1012        elif self._undefined_obj is missing:
1013            message = self._undefined_name  # type: ignore
1014
1015        else:
1016            message = (
1017                f"no such element: {object_type_repr(self._undefined_obj)}"
1018                f"[{self._undefined_name!r}]"
1019            )
1020
1021        return f"{{{{ {message} }}}}"

An undefined that returns the debug info when printed.

>>> foo = DebugUndefined(name='foo')
>>> str(foo)
'{{ foo }}'
>>> not foo
True
>>> foo + 42
Traceback (most recent call last):
  ...
jinja2.exceptions.UndefinedError: 'foo' is undefined
Inherited Members
Undefined
Undefined
class StrictUndefined(Undefined):
1024class StrictUndefined(Undefined):
1025    """An undefined that barks on print and iteration as well as boolean
1026    tests and all kinds of comparisons.  In other words: you can do nothing
1027    with it except checking if it's defined using the `defined` test.
1028
1029    >>> foo = StrictUndefined(name='foo')
1030    >>> str(foo)
1031    Traceback (most recent call last):
1032      ...
1033    jinja2.exceptions.UndefinedError: 'foo' is undefined
1034    >>> not foo
1035    Traceback (most recent call last):
1036      ...
1037    jinja2.exceptions.UndefinedError: 'foo' is undefined
1038    >>> foo + 42
1039    Traceback (most recent call last):
1040      ...
1041    jinja2.exceptions.UndefinedError: 'foo' is undefined
1042    """
1043
1044    __slots__ = ()
1045    __iter__ = __str__ = __len__ = Undefined._fail_with_undefined_error
1046    __eq__ = __ne__ = __bool__ = __hash__ = Undefined._fail_with_undefined_error
1047    __contains__ = Undefined._fail_with_undefined_error

An undefined that barks on print and iteration as well as boolean tests and all kinds of comparisons. In other words: you can do nothing with it except checking if it's defined using the defined test.

>>> foo = StrictUndefined(name='foo')
>>> str(foo)
Traceback (most recent call last):
  ...
jinja2.exceptions.UndefinedError: 'foo' is undefined
>>> not foo
Traceback (most recent call last):
  ...
jinja2.exceptions.UndefinedError: 'foo' is undefined
>>> foo + 42
Traceback (most recent call last):
  ...
jinja2.exceptions.UndefinedError: 'foo' is undefined
Inherited Members
Undefined
Undefined