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)
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.
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.
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.
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.
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.
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.
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()}
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.
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.
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.
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
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.
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.
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().
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.
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.
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.
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.
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:
Undefinedclass 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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
Inherited Members
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.
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
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
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
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.
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.
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
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