jinja2.runtime

The runtime functions and state used by compiled templates.

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

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

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

Concatenation that escapes if necessary and converts to string.

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

Internal helper for context creation.

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

The self in templates.

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

Render a parent block.

def get(self, key: str, default: Any = None) -> Any:
199    def get(self, key: str, default: t.Any = None) -> t.Any:
200        """Look up a variable by name, or return a default if the key is
201        not found.
202
203        :param key: The variable name to look up.
204        :param default: The value to return if the key is not found.
205        """
206        try:
207            return self[key]
208        except KeyError:
209            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]:
211    def resolve(self, key: str) -> t.Union[t.Any, "Undefined"]:
212        """Look up a variable by name, or return an :class:`Undefined`
213        object if the key is not found.
214
215        If you need to add custom behavior, override
216        :meth:`resolve_or_missing`, not this method. The various lookup
217        functions use that method, not this one.
218
219        :param key: The variable name to look up.
220        """
221        rv = self.resolve_or_missing(key)
222
223        if rv is missing:
224            return self.environment.undefined(name=key)
225
226        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:
228    def resolve_or_missing(self, key: str) -> t.Any:
229        """Look up a variable by name, or return a ``missing`` sentinel
230        if the key is not found.
231
232        Override this method to add custom lookup behavior.
233        :meth:`resolve`, :meth:`get`, and :meth:`__getitem__` use this
234        method. Don't call this method directly.
235
236        :param key: The variable name to look up.
237        """
238        if key in self.vars:
239            return self.vars[key]
240
241        if key in self.parent:
242            return self.parent[key]
243
244        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]:
246    def get_exported(self) -> t.Dict[str, t.Any]:
247        """Get a new dict with the exported variables."""
248        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]:
250    def get_all(self) -> t.Dict[str, t.Any]:
251        """Return the complete context as dict including the exported
252        variables.  For optimizations reasons this might not return an
253        actual copy so be careful with using it.
254        """
255        if not self.vars:
256            return self.parent
257        if not self.parent:
258            return self.vars
259        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, *args: Any, **kwargs: Any) -> Union[Any, Undefined]:
261    @internalcode
262    def call(
263        __self, __obj: t.Callable, *args: t.Any, **kwargs: t.Any  # noqa: B902
264    ) -> t.Union[t.Any, "Undefined"]:
265        """Call the callable with the arguments and keyword arguments
266        provided but inject the active context or environment as first
267        argument if the callable has :func:`pass_context` or
268        :func:`pass_environment`.
269        """
270        if __debug__:
271            __traceback_hide__ = True  # noqa
272
273        # Allow callable classes to take a context
274        if (
275            hasattr(__obj, "__call__")  # noqa: B004
276            and _PassArg.from_obj(__obj.__call__) is not None
277        ):
278            __obj = __obj.__call__
279
280        pass_arg = _PassArg.from_obj(__obj)
281
282        if pass_arg is _PassArg.context:
283            # the active context should have access to variables set in
284            # loops and blocks without mutating the context itself
285            if kwargs.get("_loop_vars"):
286                __self = __self.derived(kwargs["_loop_vars"])
287            if kwargs.get("_block_vars"):
288                __self = __self.derived(kwargs["_block_vars"])
289            args = (__self,) + args
290        elif pass_arg is _PassArg.eval_context:
291            args = (__self.eval_ctx,) + args
292        elif pass_arg is _PassArg.environment:
293            args = (__self.environment,) + args
294
295        kwargs.pop("_block_vars", None)
296        kwargs.pop("_loop_vars", None)
297
298        try:
299            return __obj(*args, **kwargs)
300        except StopIteration:
301            return __self.environment.undefined(
302                "value was undefined because a callable raised a"
303                " StopIteration exception"
304            )

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:
306    def derived(self, locals: t.Optional[t.Dict[str, t.Any]] = None) -> "Context":
307        """Internal helper function to create a derived context.  This is
308        used in situations where the system needs a new context in the same
309        template that is independent.
310        """
311        context = new_context(
312            self.environment, self.name, {}, self.get_all(), True, None, locals
313        )
314        context.eval_ctx = self.eval_ctx
315        context.blocks.update((k, list(v)) for k, v in self.blocks.items())
316        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:
340class BlockReference:
341    """One block on a template reference."""
342
343    def __init__(
344        self,
345        name: str,
346        context: "Context",
347        stack: t.List[t.Callable[["Context"], t.Iterator[str]]],
348        depth: int,
349    ) -> None:
350        self.name = name
351        self._context = context
352        self._stack = stack
353        self._depth = depth
354
355    @property
356    def super(self) -> t.Union["BlockReference", "Undefined"]:
357        """Super the block."""
358        if self._depth + 1 >= len(self._stack):
359            return self._context.environment.undefined(
360                f"there is no parent block called {self.name!r}.", name="super"
361            )
362        return BlockReference(self.name, self._context, self._stack, self._depth + 1)
363
364    @internalcode
365    async def _async_call(self) -> str:
366        rv = concat(
367            [x async for x in self._stack[self._depth](self._context)]  # type: ignore
368        )
369
370        if self._context.eval_ctx.autoescape:
371            return Markup(rv)
372
373        return rv
374
375    @internalcode
376    def __call__(self) -> str:
377        if self._context.environment.is_async:
378            return self._async_call()  # type: ignore
379
380        rv = concat(self._stack[self._depth](self._context))
381
382        if self._context.eval_ctx.autoescape:
383            return Markup(rv)
384
385        return rv

One block on a template reference.

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

Super the block.

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

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

index: int
455    @property
456    def index(self) -> int:
457        """Current iteration of the loop, starting at 1."""
458        return self.index0 + 1

Current iteration of the loop, starting at 1.

revindex0: int
460    @property
461    def revindex0(self) -> int:
462        """Number of iterations from the end of the loop, ending at 0.
463
464        Requires calculating :attr:`length`.
465        """
466        return self.length - self.index

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

Requires calculating length.

revindex: int
468    @property
469    def revindex(self) -> int:
470        """Number of iterations from the end of the loop, ending at 1.
471
472        Requires calculating :attr:`length`.
473        """
474        return self.length - self.index0

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

Requires calculating length.

first: bool
476    @property
477    def first(self) -> bool:
478        """Whether this is the first iteration of the loop."""
479        return self.index0 == 0

Whether this is the first iteration of the loop.

last: bool
493    @property
494    def last(self) -> bool:
495        """Whether this is the last iteration of the loop.
496
497        Causes the iterable to advance early. See
498        :func:`itertools.groupby` for issues this can cause.
499        The :func:`groupby` filter avoids that issue.
500        """
501        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]
503    @property
504    def previtem(self) -> t.Union[t.Any, "Undefined"]:
505        """The item in the previous iteration. Undefined during the
506        first iteration.
507        """
508        if self.first:
509            return self._undefined("there is no previous item")
510
511        return self._before

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

nextitem: Union[Any, Undefined]
513    @property
514    def nextitem(self) -> t.Union[t.Any, "Undefined"]:
515        """The item in the next iteration. Undefined during the last
516        iteration.
517
518        Causes the iterable to advance early. See
519        :func:`itertools.groupby` for issues this can cause.
520        The :func:`jinja-filters.groupby` filter avoids that issue.
521        """
522        rv = self._peek_next()
523
524        if rv is missing:
525            return self._undefined("there is no next item")
526
527        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:
529    def cycle(self, *args: V) -> V:
530        """Return a value from the given args, cycling through based on
531        the current :attr:`index0`.
532
533        :param args: One or more values to cycle through.
534        """
535        if not args:
536            raise TypeError("no items for cycling given")
537
538        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:
540    def changed(self, *value: t.Any) -> bool:
541        """Return ``True`` if previously called with a different value
542        (including when called for the first time).
543
544        :param value: One or more values to compare to the last call.
545        """
546        if self._last_changed_value != value:
547            self._last_changed_value = value
548            return True
549
550        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):
585class AsyncLoopContext(LoopContext):
586    _iterator: t.AsyncIterator[t.Any]  # type: ignore
587
588    @staticmethod
589    def _to_iterator(  # type: ignore
590        iterable: t.Union[t.Iterable[V], t.AsyncIterable[V]]
591    ) -> t.AsyncIterator[V]:
592        return auto_aiter(iterable)
593
594    @property
595    async def length(self) -> int:  # type: ignore
596        if self._length is not None:
597            return self._length
598
599        try:
600            self._length = len(self._iterable)  # type: ignore
601        except TypeError:
602            iterable = [x async for x in self._iterator]
603            self._iterator = self._to_iterator(iterable)
604            self._length = len(iterable) + self.index + (self._after is not missing)
605
606        return self._length
607
608    @property
609    async def revindex0(self) -> int:  # type: ignore
610        return await self.length - self.index
611
612    @property
613    async def revindex(self) -> int:  # type: ignore
614        return await self.length - self.index0
615
616    async def _peek_next(self) -> t.Any:
617        if self._after is not missing:
618            return self._after
619
620        try:
621            self._after = await self._iterator.__anext__()
622        except StopAsyncIteration:
623            self._after = missing
624
625        return self._after
626
627    @property
628    async def last(self) -> bool:  # type: ignore
629        return await self._peek_next() is missing
630
631    @property
632    async def nextitem(self) -> t.Union[t.Any, "Undefined"]:
633        rv = await self._peek_next()
634
635        if rv is missing:
636            return self._undefined("there is no next item")
637
638        return rv
639
640    def __aiter__(self) -> "AsyncLoopContext":
641        return self
642
643    async def __anext__(self) -> t.Tuple[t.Any, "AsyncLoopContext"]:
644        if self._after is not missing:
645            rv = self._after
646            self._after = missing
647        else:
648            rv = await self._iterator.__anext__()
649
650        self.index0 += 1
651        self._before = self._current
652        self._current = rv
653        return rv, self

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

length: int
594    @property
595    async def length(self) -> int:  # type: ignore
596        if self._length is not None:
597            return self._length
598
599        try:
600            self._length = len(self._iterable)  # type: ignore
601        except TypeError:
602            iterable = [x async for x in self._iterator]
603            self._iterator = self._to_iterator(iterable)
604            self._length = len(iterable) + self.index + (self._after is not missing)
605
606        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
608    @property
609    async def revindex0(self) -> int:  # type: ignore
610        return await self.length - self.index

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

Requires calculating length.

revindex: int
612    @property
613    async def revindex(self) -> int:  # type: ignore
614        return await self.length - self.index0

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

Requires calculating length.

last: bool
627    @property
628    async def last(self) -> bool:  # type: ignore
629        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]
631    @property
632    async def nextitem(self) -> t.Union[t.Any, "Undefined"]:
633        rv = await self._peek_next()
634
635        if rv is missing:
636            return self._undefined("there is no next item")
637
638        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:
656class Macro:
657    """Wraps a macro function."""
658
659    def __init__(
660        self,
661        environment: "Environment",
662        func: t.Callable[..., str],
663        name: str,
664        arguments: t.List[str],
665        catch_kwargs: bool,
666        catch_varargs: bool,
667        caller: bool,
668        default_autoescape: t.Optional[bool] = None,
669    ):
670        self._environment = environment
671        self._func = func
672        self._argument_count = len(arguments)
673        self.name = name
674        self.arguments = arguments
675        self.catch_kwargs = catch_kwargs
676        self.catch_varargs = catch_varargs
677        self.caller = caller
678        self.explicit_caller = "caller" in arguments
679
680        if default_autoescape is None:
681            if callable(environment.autoescape):
682                default_autoescape = environment.autoescape(None)
683            else:
684                default_autoescape = environment.autoescape
685
686        self._default_autoescape = default_autoescape
687
688    @internalcode
689    @pass_eval_context
690    def __call__(self, *args: t.Any, **kwargs: t.Any) -> str:
691        # This requires a bit of explanation,  In the past we used to
692        # decide largely based on compile-time information if a macro is
693        # safe or unsafe.  While there was a volatile mode it was largely
694        # unused for deciding on escaping.  This turns out to be
695        # problematic for macros because whether a macro is safe depends not
696        # on the escape mode when it was defined, but rather when it was used.
697        #
698        # Because however we export macros from the module system and
699        # there are historic callers that do not pass an eval context (and
700        # will continue to not pass one), we need to perform an instance
701        # check here.
702        #
703        # This is considered safe because an eval context is not a valid
704        # argument to callables otherwise anyway.  Worst case here is
705        # that if no eval context is passed we fall back to the compile
706        # time autoescape flag.
707        if args and isinstance(args[0], EvalContext):
708            autoescape = args[0].autoescape
709            args = args[1:]
710        else:
711            autoescape = self._default_autoescape
712
713        # try to consume the positional arguments
714        arguments = list(args[: self._argument_count])
715        off = len(arguments)
716
717        # For information why this is necessary refer to the handling
718        # of caller in the `macro_body` handler in the compiler.
719        found_caller = False
720
721        # if the number of arguments consumed is not the number of
722        # arguments expected we start filling in keyword arguments
723        # and defaults.
724        if off != self._argument_count:
725            for name in self.arguments[len(arguments) :]:
726                try:
727                    value = kwargs.pop(name)
728                except KeyError:
729                    value = missing
730                if name == "caller":
731                    found_caller = True
732                arguments.append(value)
733        else:
734            found_caller = self.explicit_caller
735
736        # it's important that the order of these arguments does not change
737        # if not also changed in the compiler's `function_scoping` method.
738        # the order is caller, keyword arguments, positional arguments!
739        if self.caller and not found_caller:
740            caller = kwargs.pop("caller", None)
741            if caller is None:
742                caller = self._environment.undefined("No caller defined", name="caller")
743            arguments.append(caller)
744
745        if self.catch_kwargs:
746            arguments.append(kwargs)
747        elif kwargs:
748            if "caller" in kwargs:
749                raise TypeError(
750                    f"macro {self.name!r} was invoked with two values for the special"
751                    " caller argument. This is most likely a bug."
752                )
753            raise TypeError(
754                f"macro {self.name!r} takes no keyword argument {next(iter(kwargs))!r}"
755            )
756        if self.catch_varargs:
757            arguments.append(args[self._argument_count :])
758        elif len(args) > self._argument_count:
759            raise TypeError(
760                f"macro {self.name!r} takes not more than"
761                f" {len(self.arguments)} argument(s)"
762            )
763
764        return self._invoke(arguments, autoescape)
765
766    async def _async_invoke(self, arguments: t.List[t.Any], autoescape: bool) -> str:
767        rv = await self._func(*arguments)  # type: ignore
768
769        if autoescape:
770            return Markup(rv)
771
772        return rv  # type: ignore
773
774    def _invoke(self, arguments: t.List[t.Any], autoescape: bool) -> str:
775        if self._environment.is_async:
776            return self._async_invoke(arguments, autoescape)  # type: ignore
777
778        rv = self._func(*arguments)
779
780        if autoescape:
781            rv = Markup(rv)
782
783        return rv
784
785    def __repr__(self) -> str:
786        name = "anonymous" if self.name is None else repr(self.name)
787        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)
659    def __init__(
660        self,
661        environment: "Environment",
662        func: t.Callable[..., str],
663        name: str,
664        arguments: t.List[str],
665        catch_kwargs: bool,
666        catch_varargs: bool,
667        caller: bool,
668        default_autoescape: t.Optional[bool] = None,
669    ):
670        self._environment = environment
671        self._func = func
672        self._argument_count = len(arguments)
673        self.name = name
674        self.arguments = arguments
675        self.catch_kwargs = catch_kwargs
676        self.catch_varargs = catch_varargs
677        self.caller = caller
678        self.explicit_caller = "caller" in arguments
679
680        if default_autoescape is None:
681            if callable(environment.autoescape):
682                default_autoescape = environment.autoescape(None)
683            else:
684                default_autoescape = environment.autoescape
685
686        self._default_autoescape = default_autoescape
name
arguments
catch_kwargs
catch_varargs
caller
explicit_caller
class Undefined:
790class Undefined:
791    """The default undefined type.  This undefined type can be printed and
792    iterated over, but every other access will raise an :exc:`UndefinedError`:
793
794    >>> foo = Undefined(name='foo')
795    >>> str(foo)
796    ''
797    >>> not foo
798    True
799    >>> foo + 42
800    Traceback (most recent call last):
801      ...
802    jinja2.exceptions.UndefinedError: 'foo' is undefined
803    """
804
805    __slots__ = (
806        "_undefined_hint",
807        "_undefined_obj",
808        "_undefined_name",
809        "_undefined_exception",
810    )
811
812    def __init__(
813        self,
814        hint: t.Optional[str] = None,
815        obj: t.Any = missing,
816        name: t.Optional[str] = None,
817        exc: t.Type[TemplateRuntimeError] = UndefinedError,
818    ) -> None:
819        self._undefined_hint = hint
820        self._undefined_obj = obj
821        self._undefined_name = name
822        self._undefined_exception = exc
823
824    @property
825    def _undefined_message(self) -> str:
826        """Build a message about the undefined value based on how it was
827        accessed.
828        """
829        if self._undefined_hint:
830            return self._undefined_hint
831
832        if self._undefined_obj is missing:
833            return f"{self._undefined_name!r} is undefined"
834
835        if not isinstance(self._undefined_name, str):
836            return (
837                f"{object_type_repr(self._undefined_obj)} has no"
838                f" element {self._undefined_name!r}"
839            )
840
841        return (
842            f"{object_type_repr(self._undefined_obj)!r} has no"
843            f" attribute {self._undefined_name!r}"
844        )
845
846    @internalcode
847    def _fail_with_undefined_error(
848        self, *args: t.Any, **kwargs: t.Any
849    ) -> "te.NoReturn":
850        """Raise an :exc:`UndefinedError` when operations are performed
851        on the undefined value.
852        """
853        raise self._undefined_exception(self._undefined_message)
854
855    @internalcode
856    def __getattr__(self, name: str) -> t.Any:
857        if name[:2] == "__":
858            raise AttributeError(name)
859
860        return self._fail_with_undefined_error()
861
862    __add__ = __radd__ = __sub__ = __rsub__ = _fail_with_undefined_error
863    __mul__ = __rmul__ = __div__ = __rdiv__ = _fail_with_undefined_error
864    __truediv__ = __rtruediv__ = _fail_with_undefined_error
865    __floordiv__ = __rfloordiv__ = _fail_with_undefined_error
866    __mod__ = __rmod__ = _fail_with_undefined_error
867    __pos__ = __neg__ = _fail_with_undefined_error
868    __call__ = __getitem__ = _fail_with_undefined_error
869    __lt__ = __le__ = __gt__ = __ge__ = _fail_with_undefined_error
870    __int__ = __float__ = __complex__ = _fail_with_undefined_error
871    __pow__ = __rpow__ = _fail_with_undefined_error
872
873    def __eq__(self, other: t.Any) -> bool:
874        return type(self) is type(other)
875
876    def __ne__(self, other: t.Any) -> bool:
877        return not self.__eq__(other)
878
879    def __hash__(self) -> int:
880        return id(type(self))
881
882    def __str__(self) -> str:
883        return ""
884
885    def __len__(self) -> int:
886        return 0
887
888    def __iter__(self) -> t.Iterator[t.Any]:
889        yield from ()
890
891    async def __aiter__(self) -> t.AsyncIterator[t.Any]:
892        for _ in ():
893            yield
894
895    def __bool__(self) -> bool:
896        return False
897
898    def __repr__(self) -> str:
899        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'>)
812    def __init__(
813        self,
814        hint: t.Optional[str] = None,
815        obj: t.Any = missing,
816        name: t.Optional[str] = None,
817        exc: t.Type[TemplateRuntimeError] = UndefinedError,
818    ) -> None:
819        self._undefined_hint = hint
820        self._undefined_obj = obj
821        self._undefined_name = name
822        self._undefined_exception = exc
def make_logging_undefined( logger: Optional[logging.Logger] = None, base: Type[Undefined] = <class 'Undefined'>) -> Type[Undefined]:
902def make_logging_undefined(
903    logger: t.Optional["logging.Logger"] = None, base: t.Type[Undefined] = Undefined
904) -> t.Type[Undefined]:
905    """Given a logger object this returns a new undefined class that will
906    log certain failures.  It will log iterations and printing.  If no
907    logger is given a default logger is created.
908
909    Example::
910
911        logger = logging.getLogger(__name__)
912        LoggingUndefined = make_logging_undefined(
913            logger=logger,
914            base=Undefined
915        )
916
917    .. versionadded:: 2.8
918
919    :param logger: the logger to use.  If not provided, a default logger
920                   is created.
921    :param base: the base class to add logging functionality to.  This
922                 defaults to :class:`Undefined`.
923    """
924    if logger is None:
925        import logging
926
927        logger = logging.getLogger(__name__)
928        logger.addHandler(logging.StreamHandler(sys.stderr))
929
930    def _log_message(undef: Undefined) -> None:
931        logger.warning("Template variable warning: %s", undef._undefined_message)
932
933    class LoggingUndefined(base):  # type: ignore
934        __slots__ = ()
935
936        def _fail_with_undefined_error(  # type: ignore
937            self, *args: t.Any, **kwargs: t.Any
938        ) -> "te.NoReturn":
939            try:
940                super()._fail_with_undefined_error(*args, **kwargs)
941            except self._undefined_exception as e:
942                logger.error("Template variable error: %s", e)  # type: ignore
943                raise e
944
945        def __str__(self) -> str:
946            _log_message(self)
947            return super().__str__()  # type: ignore
948
949        def __iter__(self) -> t.Iterator[t.Any]:
950            _log_message(self)
951            return super().__iter__()  # type: ignore
952
953        def __bool__(self) -> bool:
954            _log_message(self)
955            return super().__bool__()  # type: ignore
956
957    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):
960class ChainableUndefined(Undefined):
961    """An undefined that is chainable, where both ``__getattr__`` and
962    ``__getitem__`` return itself rather than raising an
963    :exc:`UndefinedError`.
964
965    >>> foo = ChainableUndefined(name='foo')
966    >>> str(foo.bar['baz'])
967    ''
968    >>> foo.bar['baz'] + 42
969    Traceback (most recent call last):
970      ...
971    jinja2.exceptions.UndefinedError: 'foo' is undefined
972
973    .. versionadded:: 2.11.0
974    """
975
976    __slots__ = ()
977
978    def __html__(self) -> str:
979        return str(self)
980
981    def __getattr__(self, _: str) -> "ChainableUndefined":
982        return self
983
984    __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):
 987class DebugUndefined(Undefined):
 988    """An undefined that returns the debug info when printed.
 989
 990    >>> foo = DebugUndefined(name='foo')
 991    >>> str(foo)
 992    '{{ foo }}'
 993    >>> not foo
 994    True
 995    >>> foo + 42
 996    Traceback (most recent call last):
 997      ...
 998    jinja2.exceptions.UndefinedError: 'foo' is undefined
 999    """
1000
1001    __slots__ = ()
1002
1003    def __str__(self) -> str:
1004        if self._undefined_hint:
1005            message = f"undefined value printed: {self._undefined_hint}"
1006
1007        elif self._undefined_obj is missing:
1008            message = self._undefined_name  # type: ignore
1009
1010        else:
1011            message = (
1012                f"no such element: {object_type_repr(self._undefined_obj)}"
1013                f"[{self._undefined_name!r}]"
1014            )
1015
1016        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):
1019class StrictUndefined(Undefined):
1020    """An undefined that barks on print and iteration as well as boolean
1021    tests and all kinds of comparisons.  In other words: you can do nothing
1022    with it except checking if it's defined using the `defined` test.
1023
1024    >>> foo = StrictUndefined(name='foo')
1025    >>> str(foo)
1026    Traceback (most recent call last):
1027      ...
1028    jinja2.exceptions.UndefinedError: 'foo' is undefined
1029    >>> not foo
1030    Traceback (most recent call last):
1031      ...
1032    jinja2.exceptions.UndefinedError: 'foo' is undefined
1033    >>> foo + 42
1034    Traceback (most recent call last):
1035      ...
1036    jinja2.exceptions.UndefinedError: 'foo' is undefined
1037    """
1038
1039    __slots__ = ()
1040    __iter__ = __str__ = __len__ = Undefined._fail_with_undefined_error
1041    __eq__ = __ne__ = __bool__ = __hash__ = Undefined._fail_with_undefined_error
1042    __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