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