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 = self._context.environment.concat( # type: ignore 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 = self._context.environment.concat( # type: ignore 385 self._stack[self._depth](self._context) 386 ) 387 388 if self._context.eval_ctx.autoescape: 389 return Markup(rv) 390 391 return rv 392 393 394class LoopContext: 395 """A wrapper iterable for dynamic ``for`` loops, with information 396 about the loop and iteration. 397 """ 398 399 #: Current iteration of the loop, starting at 0. 400 index0 = -1 401 402 _length: t.Optional[int] = None 403 _after: t.Any = missing 404 _current: t.Any = missing 405 _before: t.Any = missing 406 _last_changed_value: t.Any = missing 407 408 def __init__( 409 self, 410 iterable: t.Iterable[V], 411 undefined: t.Type["Undefined"], 412 recurse: t.Optional["LoopRenderFunc"] = None, 413 depth0: int = 0, 414 ) -> None: 415 """ 416 :param iterable: Iterable to wrap. 417 :param undefined: :class:`Undefined` class to use for next and 418 previous items. 419 :param recurse: The function to render the loop body when the 420 loop is marked recursive. 421 :param depth0: Incremented when looping recursively. 422 """ 423 self._iterable = iterable 424 self._iterator = self._to_iterator(iterable) 425 self._undefined = undefined 426 self._recurse = recurse 427 #: How many levels deep a recursive loop currently is, starting at 0. 428 self.depth0 = depth0 429 430 @staticmethod 431 def _to_iterator(iterable: t.Iterable[V]) -> t.Iterator[V]: 432 return iter(iterable) 433 434 @property 435 def length(self) -> int: 436 """Length of the iterable. 437 438 If the iterable is a generator or otherwise does not have a 439 size, it is eagerly evaluated to get a size. 440 """ 441 if self._length is not None: 442 return self._length 443 444 try: 445 self._length = len(self._iterable) # type: ignore 446 except TypeError: 447 iterable = list(self._iterator) 448 self._iterator = self._to_iterator(iterable) 449 self._length = len(iterable) + self.index + (self._after is not missing) 450 451 return self._length 452 453 def __len__(self) -> int: 454 return self.length 455 456 @property 457 def depth(self) -> int: 458 """How many levels deep a recursive loop currently is, starting at 1.""" 459 return self.depth0 + 1 460 461 @property 462 def index(self) -> int: 463 """Current iteration of the loop, starting at 1.""" 464 return self.index0 + 1 465 466 @property 467 def revindex0(self) -> int: 468 """Number of iterations from the end of the loop, ending at 0. 469 470 Requires calculating :attr:`length`. 471 """ 472 return self.length - self.index 473 474 @property 475 def revindex(self) -> int: 476 """Number of iterations from the end of the loop, ending at 1. 477 478 Requires calculating :attr:`length`. 479 """ 480 return self.length - self.index0 481 482 @property 483 def first(self) -> bool: 484 """Whether this is the first iteration of the loop.""" 485 return self.index0 == 0 486 487 def _peek_next(self) -> t.Any: 488 """Return the next element in the iterable, or :data:`missing` 489 if the iterable is exhausted. Only peeks one item ahead, caching 490 the result in :attr:`_last` for use in subsequent checks. The 491 cache is reset when :meth:`__next__` is called. 492 """ 493 if self._after is not missing: 494 return self._after 495 496 self._after = next(self._iterator, missing) 497 return self._after 498 499 @property 500 def last(self) -> bool: 501 """Whether this is the last iteration of the loop. 502 503 Causes the iterable to advance early. See 504 :func:`itertools.groupby` for issues this can cause. 505 The :func:`groupby` filter avoids that issue. 506 """ 507 return self._peek_next() is missing 508 509 @property 510 def previtem(self) -> t.Union[t.Any, "Undefined"]: 511 """The item in the previous iteration. Undefined during the 512 first iteration. 513 """ 514 if self.first: 515 return self._undefined("there is no previous item") 516 517 return self._before 518 519 @property 520 def nextitem(self) -> t.Union[t.Any, "Undefined"]: 521 """The item in the next iteration. Undefined during the last 522 iteration. 523 524 Causes the iterable to advance early. See 525 :func:`itertools.groupby` for issues this can cause. 526 The :func:`jinja-filters.groupby` filter avoids that issue. 527 """ 528 rv = self._peek_next() 529 530 if rv is missing: 531 return self._undefined("there is no next item") 532 533 return rv 534 535 def cycle(self, *args: V) -> V: 536 """Return a value from the given args, cycling through based on 537 the current :attr:`index0`. 538 539 :param args: One or more values to cycle through. 540 """ 541 if not args: 542 raise TypeError("no items for cycling given") 543 544 return args[self.index0 % len(args)] 545 546 def changed(self, *value: t.Any) -> bool: 547 """Return ``True`` if previously called with a different value 548 (including when called for the first time). 549 550 :param value: One or more values to compare to the last call. 551 """ 552 if self._last_changed_value != value: 553 self._last_changed_value = value 554 return True 555 556 return False 557 558 def __iter__(self) -> "LoopContext": 559 return self 560 561 def __next__(self) -> t.Tuple[t.Any, "LoopContext"]: 562 if self._after is not missing: 563 rv = self._after 564 self._after = missing 565 else: 566 rv = next(self._iterator) 567 568 self.index0 += 1 569 self._before = self._current 570 self._current = rv 571 return rv, self 572 573 @internalcode 574 def __call__(self, iterable: t.Iterable[V]) -> str: 575 """When iterating over nested data, render the body of the loop 576 recursively with the given inner iterable data. 577 578 The loop must have the ``recursive`` marker for this to work. 579 """ 580 if self._recurse is None: 581 raise TypeError( 582 "The loop must have the 'recursive' marker to be called recursively." 583 ) 584 585 return self._recurse(iterable, self._recurse, depth=self.depth) 586 587 def __repr__(self) -> str: 588 return f"<{type(self).__name__} {self.index}/{self.length}>" 589 590 591class AsyncLoopContext(LoopContext): 592 _iterator: t.AsyncIterator[t.Any] # type: ignore 593 594 @staticmethod 595 def _to_iterator( # type: ignore 596 iterable: t.Union[t.Iterable[V], t.AsyncIterable[V]], 597 ) -> t.AsyncIterator[V]: 598 return auto_aiter(iterable) 599 600 @property 601 async def length(self) -> int: # type: ignore 602 if self._length is not None: 603 return self._length 604 605 try: 606 self._length = len(self._iterable) # type: ignore 607 except TypeError: 608 iterable = [x async for x in self._iterator] 609 self._iterator = self._to_iterator(iterable) 610 self._length = len(iterable) + self.index + (self._after is not missing) 611 612 return self._length 613 614 @property 615 async def revindex0(self) -> int: # type: ignore 616 return await self.length - self.index 617 618 @property 619 async def revindex(self) -> int: # type: ignore 620 return await self.length - self.index0 621 622 async def _peek_next(self) -> t.Any: 623 if self._after is not missing: 624 return self._after 625 626 try: 627 self._after = await self._iterator.__anext__() 628 except StopAsyncIteration: 629 self._after = missing 630 631 return self._after 632 633 @property 634 async def last(self) -> bool: # type: ignore 635 return await self._peek_next() is missing 636 637 @property 638 async def nextitem(self) -> t.Union[t.Any, "Undefined"]: 639 rv = await self._peek_next() 640 641 if rv is missing: 642 return self._undefined("there is no next item") 643 644 return rv 645 646 def __aiter__(self) -> "AsyncLoopContext": 647 return self 648 649 async def __anext__(self) -> t.Tuple[t.Any, "AsyncLoopContext"]: 650 if self._after is not missing: 651 rv = self._after 652 self._after = missing 653 else: 654 rv = await self._iterator.__anext__() 655 656 self.index0 += 1 657 self._before = self._current 658 self._current = rv 659 return rv, self 660 661 662class Macro: 663 """Wraps a macro function.""" 664 665 def __init__( 666 self, 667 environment: "Environment", 668 func: t.Callable[..., str], 669 name: str, 670 arguments: t.List[str], 671 catch_kwargs: bool, 672 catch_varargs: bool, 673 caller: bool, 674 default_autoescape: t.Optional[bool] = None, 675 ): 676 self._environment = environment 677 self._func = func 678 self._argument_count = len(arguments) 679 self.name = name 680 self.arguments = arguments 681 self.catch_kwargs = catch_kwargs 682 self.catch_varargs = catch_varargs 683 self.caller = caller 684 self.explicit_caller = "caller" in arguments 685 686 if default_autoescape is None: 687 if callable(environment.autoescape): 688 default_autoescape = environment.autoescape(None) 689 else: 690 default_autoescape = environment.autoescape 691 692 self._default_autoescape = default_autoescape 693 694 @internalcode 695 @pass_eval_context 696 def __call__(self, *args: t.Any, **kwargs: t.Any) -> str: 697 # This requires a bit of explanation, In the past we used to 698 # decide largely based on compile-time information if a macro is 699 # safe or unsafe. While there was a volatile mode it was largely 700 # unused for deciding on escaping. This turns out to be 701 # problematic for macros because whether a macro is safe depends not 702 # on the escape mode when it was defined, but rather when it was used. 703 # 704 # Because however we export macros from the module system and 705 # there are historic callers that do not pass an eval context (and 706 # will continue to not pass one), we need to perform an instance 707 # check here. 708 # 709 # This is considered safe because an eval context is not a valid 710 # argument to callables otherwise anyway. Worst case here is 711 # that if no eval context is passed we fall back to the compile 712 # time autoescape flag. 713 if args and isinstance(args[0], EvalContext): 714 autoescape = args[0].autoescape 715 args = args[1:] 716 else: 717 autoescape = self._default_autoescape 718 719 # try to consume the positional arguments 720 arguments = list(args[: self._argument_count]) 721 off = len(arguments) 722 723 # For information why this is necessary refer to the handling 724 # of caller in the `macro_body` handler in the compiler. 725 found_caller = False 726 727 # if the number of arguments consumed is not the number of 728 # arguments expected we start filling in keyword arguments 729 # and defaults. 730 if off != self._argument_count: 731 for name in self.arguments[len(arguments) :]: 732 try: 733 value = kwargs.pop(name) 734 except KeyError: 735 value = missing 736 if name == "caller": 737 found_caller = True 738 arguments.append(value) 739 else: 740 found_caller = self.explicit_caller 741 742 # it's important that the order of these arguments does not change 743 # if not also changed in the compiler's `function_scoping` method. 744 # the order is caller, keyword arguments, positional arguments! 745 if self.caller and not found_caller: 746 caller = kwargs.pop("caller", None) 747 if caller is None: 748 caller = self._environment.undefined("No caller defined", name="caller") 749 arguments.append(caller) 750 751 if self.catch_kwargs: 752 arguments.append(kwargs) 753 elif kwargs: 754 if "caller" in kwargs: 755 raise TypeError( 756 f"macro {self.name!r} was invoked with two values for the special" 757 " caller argument. This is most likely a bug." 758 ) 759 raise TypeError( 760 f"macro {self.name!r} takes no keyword argument {next(iter(kwargs))!r}" 761 ) 762 if self.catch_varargs: 763 arguments.append(args[self._argument_count :]) 764 elif len(args) > self._argument_count: 765 raise TypeError( 766 f"macro {self.name!r} takes not more than" 767 f" {len(self.arguments)} argument(s)" 768 ) 769 770 return self._invoke(arguments, autoescape) 771 772 async def _async_invoke(self, arguments: t.List[t.Any], autoescape: bool) -> str: 773 rv = await self._func(*arguments) # type: ignore 774 775 if autoescape: 776 return Markup(rv) 777 778 return rv # type: ignore 779 780 def _invoke(self, arguments: t.List[t.Any], autoescape: bool) -> str: 781 if self._environment.is_async: 782 return self._async_invoke(arguments, autoescape) # type: ignore 783 784 rv = self._func(*arguments) 785 786 if autoescape: 787 rv = Markup(rv) 788 789 return rv 790 791 def __repr__(self) -> str: 792 name = "anonymous" if self.name is None else repr(self.name) 793 return f"<{type(self).__name__} {name}>" 794 795 796class Undefined: 797 """The default undefined type. This can be printed, iterated, and treated as 798 a boolean. Any other operation will raise an :exc:`UndefinedError`. 799 800 >>> foo = Undefined(name='foo') 801 >>> str(foo) 802 '' 803 >>> not foo 804 True 805 >>> foo + 42 806 Traceback (most recent call last): 807 ... 808 jinja2.exceptions.UndefinedError: 'foo' is undefined 809 """ 810 811 __slots__ = ( 812 "_undefined_hint", 813 "_undefined_obj", 814 "_undefined_name", 815 "_undefined_exception", 816 ) 817 818 def __init__( 819 self, 820 hint: t.Optional[str] = None, 821 obj: t.Any = missing, 822 name: t.Optional[str] = None, 823 exc: t.Type[TemplateRuntimeError] = UndefinedError, 824 ) -> None: 825 self._undefined_hint = hint 826 self._undefined_obj = obj 827 self._undefined_name = name 828 self._undefined_exception = exc 829 830 @property 831 def _undefined_message(self) -> str: 832 """Build a message about the undefined value based on how it was 833 accessed. 834 """ 835 if self._undefined_hint: 836 return self._undefined_hint 837 838 if self._undefined_obj is missing: 839 return f"{self._undefined_name!r} is undefined" 840 841 if not isinstance(self._undefined_name, str): 842 return ( 843 f"{object_type_repr(self._undefined_obj)} has no" 844 f" element {self._undefined_name!r}" 845 ) 846 847 return ( 848 f"{object_type_repr(self._undefined_obj)!r} has no" 849 f" attribute {self._undefined_name!r}" 850 ) 851 852 @internalcode 853 def _fail_with_undefined_error( 854 self, *args: t.Any, **kwargs: t.Any 855 ) -> "te.NoReturn": 856 """Raise an :exc:`UndefinedError` when operations are performed 857 on the undefined value. 858 """ 859 raise self._undefined_exception(self._undefined_message) 860 861 @internalcode 862 def __getattr__(self, name: str) -> t.Any: 863 # Raise AttributeError on requests for names that appear to be unimplemented 864 # dunder methods to keep Python's internal protocol probing behaviors working 865 # properly in cases where another exception type could cause unexpected or 866 # difficult-to-diagnose failures. 867 if name[:2] == "__" and name[-2:] == "__": 868 raise AttributeError(name) 869 870 return self._fail_with_undefined_error() 871 872 __add__ = __radd__ = __sub__ = __rsub__ = _fail_with_undefined_error 873 __mul__ = __rmul__ = __div__ = __rdiv__ = _fail_with_undefined_error 874 __truediv__ = __rtruediv__ = _fail_with_undefined_error 875 __floordiv__ = __rfloordiv__ = _fail_with_undefined_error 876 __mod__ = __rmod__ = _fail_with_undefined_error 877 __pos__ = __neg__ = _fail_with_undefined_error 878 __call__ = __getitem__ = _fail_with_undefined_error 879 __lt__ = __le__ = __gt__ = __ge__ = _fail_with_undefined_error 880 __int__ = __float__ = __complex__ = _fail_with_undefined_error 881 __pow__ = __rpow__ = _fail_with_undefined_error 882 883 def __eq__(self, other: t.Any) -> bool: 884 return type(self) is type(other) 885 886 def __ne__(self, other: t.Any) -> bool: 887 return not self.__eq__(other) 888 889 def __hash__(self) -> int: 890 return id(type(self)) 891 892 def __str__(self) -> str: 893 return "" 894 895 def __len__(self) -> int: 896 return 0 897 898 def __iter__(self) -> t.Iterator[t.Any]: 899 yield from () 900 901 async def __aiter__(self) -> t.AsyncIterator[t.Any]: 902 for _ in (): 903 yield 904 905 def __bool__(self) -> bool: 906 return False 907 908 def __repr__(self) -> str: 909 return "Undefined" 910 911 912def make_logging_undefined( 913 logger: t.Optional["logging.Logger"] = None, base: t.Type[Undefined] = Undefined 914) -> t.Type[Undefined]: 915 """Given a logger object this returns a new undefined class that will 916 log certain failures. It will log iterations and printing. If no 917 logger is given a default logger is created. 918 919 Example:: 920 921 logger = logging.getLogger(__name__) 922 LoggingUndefined = make_logging_undefined( 923 logger=logger, 924 base=Undefined 925 ) 926 927 .. versionadded:: 2.8 928 929 :param logger: the logger to use. If not provided, a default logger 930 is created. 931 :param base: the base class to add logging functionality to. This 932 defaults to :class:`Undefined`. 933 """ 934 if logger is None: 935 import logging 936 937 logger = logging.getLogger(__name__) 938 logger.addHandler(logging.StreamHandler(sys.stderr)) 939 940 def _log_message(undef: Undefined) -> None: 941 logger.warning("Template variable warning: %s", undef._undefined_message) 942 943 class LoggingUndefined(base): # type: ignore 944 __slots__ = () 945 946 def _fail_with_undefined_error( # type: ignore 947 self, *args: t.Any, **kwargs: t.Any 948 ) -> "te.NoReturn": 949 try: 950 super()._fail_with_undefined_error(*args, **kwargs) 951 except self._undefined_exception as e: 952 logger.error("Template variable error: %s", e) # type: ignore 953 raise e 954 955 def __str__(self) -> str: 956 _log_message(self) 957 return super().__str__() # type: ignore 958 959 def __iter__(self) -> t.Iterator[t.Any]: 960 _log_message(self) 961 return super().__iter__() # type: ignore 962 963 def __bool__(self) -> bool: 964 _log_message(self) 965 return super().__bool__() # type: ignore 966 967 return LoggingUndefined 968 969 970class ChainableUndefined(Undefined): 971 """An undefined that is chainable, where both ``__getattr__`` and 972 ``__getitem__`` return itself rather than raising an 973 :exc:`UndefinedError`. 974 975 >>> foo = ChainableUndefined(name='foo') 976 >>> str(foo.bar['baz']) 977 '' 978 >>> foo.bar['baz'] + 42 979 Traceback (most recent call last): 980 ... 981 jinja2.exceptions.UndefinedError: 'foo' is undefined 982 983 .. versionadded:: 2.11.0 984 """ 985 986 __slots__ = () 987 988 def __html__(self) -> str: 989 return str(self) 990 991 def __getattr__(self, name: str) -> "ChainableUndefined": 992 # Raise AttributeError on requests for names that appear to be unimplemented 993 # dunder methods to avoid confusing Python with truthy non-method objects that 994 # do not implement the protocol being probed for. e.g., copy.copy(Undefined()) 995 # fails spectacularly if getattr(Undefined(), '__setstate__') returns an 996 # Undefined object instead of raising AttributeError to signal that it does not 997 # support that style of object initialization. 998 if name[:2] == "__" and name[-2:] == "__": 999 raise AttributeError(name) 1000 1001 return self 1002 1003 def __getitem__(self, _name: str) -> "ChainableUndefined": # type: ignore[override] 1004 return self 1005 1006 1007class DebugUndefined(Undefined): 1008 """An undefined that returns the debug info when printed. 1009 1010 >>> foo = DebugUndefined(name='foo') 1011 >>> str(foo) 1012 '{{ foo }}' 1013 >>> not foo 1014 True 1015 >>> foo + 42 1016 Traceback (most recent call last): 1017 ... 1018 jinja2.exceptions.UndefinedError: 'foo' is undefined 1019 """ 1020 1021 __slots__ = () 1022 1023 def __str__(self) -> str: 1024 if self._undefined_hint: 1025 message = f"undefined value printed: {self._undefined_hint}" 1026 1027 elif self._undefined_obj is missing: 1028 message = self._undefined_name # type: ignore 1029 1030 else: 1031 message = ( 1032 f"no such element: {object_type_repr(self._undefined_obj)}" 1033 f"[{self._undefined_name!r}]" 1034 ) 1035 1036 return f"{{{{ {message} }}}}" 1037 1038 1039class StrictUndefined(Undefined): 1040 """An undefined that barks on print and iteration as well as boolean 1041 tests and all kinds of comparisons. In other words: you can do nothing 1042 with it except checking if it's defined using the `defined` test. 1043 1044 >>> foo = StrictUndefined(name='foo') 1045 >>> str(foo) 1046 Traceback (most recent call last): 1047 ... 1048 jinja2.exceptions.UndefinedError: 'foo' is undefined 1049 >>> not foo 1050 Traceback (most recent call last): 1051 ... 1052 jinja2.exceptions.UndefinedError: 'foo' is undefined 1053 >>> foo + 42 1054 Traceback (most recent call last): 1055 ... 1056 jinja2.exceptions.UndefinedError: 'foo' is undefined 1057 """ 1058 1059 __slots__ = () 1060 __iter__ = __str__ = __len__ = Undefined._fail_with_undefined_error 1061 __eq__ = __ne__ = __bool__ = __hash__ = Undefined._fail_with_undefined_error 1062 __contains__ = Undefined._fail_with_undefined_error
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 = self._context.environment.concat( # type: ignore 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 = self._context.environment.concat( # type: ignore 386 self._stack[self._depth](self._context) 387 ) 388 389 if self._context.eval_ctx.autoescape: 390 return Markup(rv) 391 392 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.
395class LoopContext: 396 """A wrapper iterable for dynamic ``for`` loops, with information 397 about the loop and iteration. 398 """ 399 400 #: Current iteration of the loop, starting at 0. 401 index0 = -1 402 403 _length: t.Optional[int] = None 404 _after: t.Any = missing 405 _current: t.Any = missing 406 _before: t.Any = missing 407 _last_changed_value: t.Any = missing 408 409 def __init__( 410 self, 411 iterable: t.Iterable[V], 412 undefined: t.Type["Undefined"], 413 recurse: t.Optional["LoopRenderFunc"] = None, 414 depth0: int = 0, 415 ) -> None: 416 """ 417 :param iterable: Iterable to wrap. 418 :param undefined: :class:`Undefined` class to use for next and 419 previous items. 420 :param recurse: The function to render the loop body when the 421 loop is marked recursive. 422 :param depth0: Incremented when looping recursively. 423 """ 424 self._iterable = iterable 425 self._iterator = self._to_iterator(iterable) 426 self._undefined = undefined 427 self._recurse = recurse 428 #: How many levels deep a recursive loop currently is, starting at 0. 429 self.depth0 = depth0 430 431 @staticmethod 432 def _to_iterator(iterable: t.Iterable[V]) -> t.Iterator[V]: 433 return iter(iterable) 434 435 @property 436 def length(self) -> int: 437 """Length of the iterable. 438 439 If the iterable is a generator or otherwise does not have a 440 size, it is eagerly evaluated to get a size. 441 """ 442 if self._length is not None: 443 return self._length 444 445 try: 446 self._length = len(self._iterable) # type: ignore 447 except TypeError: 448 iterable = list(self._iterator) 449 self._iterator = self._to_iterator(iterable) 450 self._length = len(iterable) + self.index + (self._after is not missing) 451 452 return self._length 453 454 def __len__(self) -> int: 455 return self.length 456 457 @property 458 def depth(self) -> int: 459 """How many levels deep a recursive loop currently is, starting at 1.""" 460 return self.depth0 + 1 461 462 @property 463 def index(self) -> int: 464 """Current iteration of the loop, starting at 1.""" 465 return self.index0 + 1 466 467 @property 468 def revindex0(self) -> int: 469 """Number of iterations from the end of the loop, ending at 0. 470 471 Requires calculating :attr:`length`. 472 """ 473 return self.length - self.index 474 475 @property 476 def revindex(self) -> int: 477 """Number of iterations from the end of the loop, ending at 1. 478 479 Requires calculating :attr:`length`. 480 """ 481 return self.length - self.index0 482 483 @property 484 def first(self) -> bool: 485 """Whether this is the first iteration of the loop.""" 486 return self.index0 == 0 487 488 def _peek_next(self) -> t.Any: 489 """Return the next element in the iterable, or :data:`missing` 490 if the iterable is exhausted. Only peeks one item ahead, caching 491 the result in :attr:`_last` for use in subsequent checks. The 492 cache is reset when :meth:`__next__` is called. 493 """ 494 if self._after is not missing: 495 return self._after 496 497 self._after = next(self._iterator, missing) 498 return self._after 499 500 @property 501 def last(self) -> bool: 502 """Whether this is the last iteration of the loop. 503 504 Causes the iterable to advance early. See 505 :func:`itertools.groupby` for issues this can cause. 506 The :func:`groupby` filter avoids that issue. 507 """ 508 return self._peek_next() is missing 509 510 @property 511 def previtem(self) -> t.Union[t.Any, "Undefined"]: 512 """The item in the previous iteration. Undefined during the 513 first iteration. 514 """ 515 if self.first: 516 return self._undefined("there is no previous item") 517 518 return self._before 519 520 @property 521 def nextitem(self) -> t.Union[t.Any, "Undefined"]: 522 """The item in the next iteration. Undefined during the last 523 iteration. 524 525 Causes the iterable to advance early. See 526 :func:`itertools.groupby` for issues this can cause. 527 The :func:`jinja-filters.groupby` filter avoids that issue. 528 """ 529 rv = self._peek_next() 530 531 if rv is missing: 532 return self._undefined("there is no next item") 533 534 return rv 535 536 def cycle(self, *args: V) -> V: 537 """Return a value from the given args, cycling through based on 538 the current :attr:`index0`. 539 540 :param args: One or more values to cycle through. 541 """ 542 if not args: 543 raise TypeError("no items for cycling given") 544 545 return args[self.index0 % len(args)] 546 547 def changed(self, *value: t.Any) -> bool: 548 """Return ``True`` if previously called with a different value 549 (including when called for the first time). 550 551 :param value: One or more values to compare to the last call. 552 """ 553 if self._last_changed_value != value: 554 self._last_changed_value = value 555 return True 556 557 return False 558 559 def __iter__(self) -> "LoopContext": 560 return self 561 562 def __next__(self) -> t.Tuple[t.Any, "LoopContext"]: 563 if self._after is not missing: 564 rv = self._after 565 self._after = missing 566 else: 567 rv = next(self._iterator) 568 569 self.index0 += 1 570 self._before = self._current 571 self._current = rv 572 return rv, self 573 574 @internalcode 575 def __call__(self, iterable: t.Iterable[V]) -> str: 576 """When iterating over nested data, render the body of the loop 577 recursively with the given inner iterable data. 578 579 The loop must have the ``recursive`` marker for this to work. 580 """ 581 if self._recurse is None: 582 raise TypeError( 583 "The loop must have the 'recursive' marker to be called recursively." 584 ) 585 586 return self._recurse(iterable, self._recurse, depth=self.depth) 587 588 def __repr__(self) -> str: 589 return f"<{type(self).__name__} {self.index}/{self.length}>"
A wrapper iterable for dynamic for
loops, with information
about the loop and iteration.
409 def __init__( 410 self, 411 iterable: t.Iterable[V], 412 undefined: t.Type["Undefined"], 413 recurse: t.Optional["LoopRenderFunc"] = None, 414 depth0: int = 0, 415 ) -> None: 416 """ 417 :param iterable: Iterable to wrap. 418 :param undefined: :class:`Undefined` class to use for next and 419 previous items. 420 :param recurse: The function to render the loop body when the 421 loop is marked recursive. 422 :param depth0: Incremented when looping recursively. 423 """ 424 self._iterable = iterable 425 self._iterator = self._to_iterator(iterable) 426 self._undefined = undefined 427 self._recurse = recurse 428 #: How many levels deep a recursive loop currently is, starting at 0. 429 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.
435 @property 436 def length(self) -> int: 437 """Length of the iterable. 438 439 If the iterable is a generator or otherwise does not have a 440 size, it is eagerly evaluated to get a size. 441 """ 442 if self._length is not None: 443 return self._length 444 445 try: 446 self._length = len(self._iterable) # type: ignore 447 except TypeError: 448 iterable = list(self._iterator) 449 self._iterator = self._to_iterator(iterable) 450 self._length = len(iterable) + self.index + (self._after is not missing) 451 452 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.
457 @property 458 def depth(self) -> int: 459 """How many levels deep a recursive loop currently is, starting at 1.""" 460 return self.depth0 + 1
How many levels deep a recursive loop currently is, starting at 1.
462 @property 463 def index(self) -> int: 464 """Current iteration of the loop, starting at 1.""" 465 return self.index0 + 1
Current iteration of the loop, starting at 1.
467 @property 468 def revindex0(self) -> int: 469 """Number of iterations from the end of the loop, ending at 0. 470 471 Requires calculating :attr:`length`. 472 """ 473 return self.length - self.index
Number of iterations from the end of the loop, ending at 0.
Requires calculating length
.
475 @property 476 def revindex(self) -> int: 477 """Number of iterations from the end of the loop, ending at 1. 478 479 Requires calculating :attr:`length`. 480 """ 481 return self.length - self.index0
Number of iterations from the end of the loop, ending at 1.
Requires calculating length
.
483 @property 484 def first(self) -> bool: 485 """Whether this is the first iteration of the loop.""" 486 return self.index0 == 0
Whether this is the first iteration of the loop.
500 @property 501 def last(self) -> bool: 502 """Whether this is the last iteration of the loop. 503 504 Causes the iterable to advance early. See 505 :func:`itertools.groupby` for issues this can cause. 506 The :func:`groupby` filter avoids that issue. 507 """ 508 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.
510 @property 511 def previtem(self) -> t.Union[t.Any, "Undefined"]: 512 """The item in the previous iteration. Undefined during the 513 first iteration. 514 """ 515 if self.first: 516 return self._undefined("there is no previous item") 517 518 return self._before
The item in the previous iteration. Undefined during the first iteration.
520 @property 521 def nextitem(self) -> t.Union[t.Any, "Undefined"]: 522 """The item in the next iteration. Undefined during the last 523 iteration. 524 525 Causes the iterable to advance early. See 526 :func:`itertools.groupby` for issues this can cause. 527 The :func:`jinja-filters.groupby` filter avoids that issue. 528 """ 529 rv = self._peek_next() 530 531 if rv is missing: 532 return self._undefined("there is no next item") 533 534 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.
536 def cycle(self, *args: V) -> V: 537 """Return a value from the given args, cycling through based on 538 the current :attr:`index0`. 539 540 :param args: One or more values to cycle through. 541 """ 542 if not args: 543 raise TypeError("no items for cycling given") 544 545 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.
547 def changed(self, *value: t.Any) -> bool: 548 """Return ``True`` if previously called with a different value 549 (including when called for the first time). 550 551 :param value: One or more values to compare to the last call. 552 """ 553 if self._last_changed_value != value: 554 self._last_changed_value = value 555 return True 556 557 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.
592class AsyncLoopContext(LoopContext): 593 _iterator: t.AsyncIterator[t.Any] # type: ignore 594 595 @staticmethod 596 def _to_iterator( # type: ignore 597 iterable: t.Union[t.Iterable[V], t.AsyncIterable[V]], 598 ) -> t.AsyncIterator[V]: 599 return auto_aiter(iterable) 600 601 @property 602 async def length(self) -> int: # type: ignore 603 if self._length is not None: 604 return self._length 605 606 try: 607 self._length = len(self._iterable) # type: ignore 608 except TypeError: 609 iterable = [x async for x in self._iterator] 610 self._iterator = self._to_iterator(iterable) 611 self._length = len(iterable) + self.index + (self._after is not missing) 612 613 return self._length 614 615 @property 616 async def revindex0(self) -> int: # type: ignore 617 return await self.length - self.index 618 619 @property 620 async def revindex(self) -> int: # type: ignore 621 return await self.length - self.index0 622 623 async def _peek_next(self) -> t.Any: 624 if self._after is not missing: 625 return self._after 626 627 try: 628 self._after = await self._iterator.__anext__() 629 except StopAsyncIteration: 630 self._after = missing 631 632 return self._after 633 634 @property 635 async def last(self) -> bool: # type: ignore 636 return await self._peek_next() is missing 637 638 @property 639 async def nextitem(self) -> t.Union[t.Any, "Undefined"]: 640 rv = await self._peek_next() 641 642 if rv is missing: 643 return self._undefined("there is no next item") 644 645 return rv 646 647 def __aiter__(self) -> "AsyncLoopContext": 648 return self 649 650 async def __anext__(self) -> t.Tuple[t.Any, "AsyncLoopContext"]: 651 if self._after is not missing: 652 rv = self._after 653 self._after = missing 654 else: 655 rv = await self._iterator.__anext__() 656 657 self.index0 += 1 658 self._before = self._current 659 self._current = rv 660 return rv, self
A wrapper iterable for dynamic for
loops, with information
about the loop and iteration.
601 @property 602 async def length(self) -> int: # type: ignore 603 if self._length is not None: 604 return self._length 605 606 try: 607 self._length = len(self._iterable) # type: ignore 608 except TypeError: 609 iterable = [x async for x in self._iterator] 610 self._iterator = self._to_iterator(iterable) 611 self._length = len(iterable) + self.index + (self._after is not missing) 612 613 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.
615 @property 616 async def revindex0(self) -> int: # type: ignore 617 return await self.length - self.index
Number of iterations from the end of the loop, ending at 0.
Requires calculating length
.
619 @property 620 async def revindex(self) -> int: # type: ignore 621 return await self.length - self.index0
Number of iterations from the end of the loop, ending at 1.
Requires calculating length
.
634 @property 635 async def last(self) -> bool: # type: ignore 636 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.
638 @property 639 async def nextitem(self) -> t.Union[t.Any, "Undefined"]: 640 rv = await self._peek_next() 641 642 if rv is missing: 643 return self._undefined("there is no next item") 644 645 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
663class Macro: 664 """Wraps a macro function.""" 665 666 def __init__( 667 self, 668 environment: "Environment", 669 func: t.Callable[..., str], 670 name: str, 671 arguments: t.List[str], 672 catch_kwargs: bool, 673 catch_varargs: bool, 674 caller: bool, 675 default_autoescape: t.Optional[bool] = None, 676 ): 677 self._environment = environment 678 self._func = func 679 self._argument_count = len(arguments) 680 self.name = name 681 self.arguments = arguments 682 self.catch_kwargs = catch_kwargs 683 self.catch_varargs = catch_varargs 684 self.caller = caller 685 self.explicit_caller = "caller" in arguments 686 687 if default_autoescape is None: 688 if callable(environment.autoescape): 689 default_autoescape = environment.autoescape(None) 690 else: 691 default_autoescape = environment.autoescape 692 693 self._default_autoescape = default_autoescape 694 695 @internalcode 696 @pass_eval_context 697 def __call__(self, *args: t.Any, **kwargs: t.Any) -> str: 698 # This requires a bit of explanation, In the past we used to 699 # decide largely based on compile-time information if a macro is 700 # safe or unsafe. While there was a volatile mode it was largely 701 # unused for deciding on escaping. This turns out to be 702 # problematic for macros because whether a macro is safe depends not 703 # on the escape mode when it was defined, but rather when it was used. 704 # 705 # Because however we export macros from the module system and 706 # there are historic callers that do not pass an eval context (and 707 # will continue to not pass one), we need to perform an instance 708 # check here. 709 # 710 # This is considered safe because an eval context is not a valid 711 # argument to callables otherwise anyway. Worst case here is 712 # that if no eval context is passed we fall back to the compile 713 # time autoescape flag. 714 if args and isinstance(args[0], EvalContext): 715 autoescape = args[0].autoescape 716 args = args[1:] 717 else: 718 autoescape = self._default_autoescape 719 720 # try to consume the positional arguments 721 arguments = list(args[: self._argument_count]) 722 off = len(arguments) 723 724 # For information why this is necessary refer to the handling 725 # of caller in the `macro_body` handler in the compiler. 726 found_caller = False 727 728 # if the number of arguments consumed is not the number of 729 # arguments expected we start filling in keyword arguments 730 # and defaults. 731 if off != self._argument_count: 732 for name in self.arguments[len(arguments) :]: 733 try: 734 value = kwargs.pop(name) 735 except KeyError: 736 value = missing 737 if name == "caller": 738 found_caller = True 739 arguments.append(value) 740 else: 741 found_caller = self.explicit_caller 742 743 # it's important that the order of these arguments does not change 744 # if not also changed in the compiler's `function_scoping` method. 745 # the order is caller, keyword arguments, positional arguments! 746 if self.caller and not found_caller: 747 caller = kwargs.pop("caller", None) 748 if caller is None: 749 caller = self._environment.undefined("No caller defined", name="caller") 750 arguments.append(caller) 751 752 if self.catch_kwargs: 753 arguments.append(kwargs) 754 elif kwargs: 755 if "caller" in kwargs: 756 raise TypeError( 757 f"macro {self.name!r} was invoked with two values for the special" 758 " caller argument. This is most likely a bug." 759 ) 760 raise TypeError( 761 f"macro {self.name!r} takes no keyword argument {next(iter(kwargs))!r}" 762 ) 763 if self.catch_varargs: 764 arguments.append(args[self._argument_count :]) 765 elif len(args) > self._argument_count: 766 raise TypeError( 767 f"macro {self.name!r} takes not more than" 768 f" {len(self.arguments)} argument(s)" 769 ) 770 771 return self._invoke(arguments, autoescape) 772 773 async def _async_invoke(self, arguments: t.List[t.Any], autoescape: bool) -> str: 774 rv = await self._func(*arguments) # type: ignore 775 776 if autoescape: 777 return Markup(rv) 778 779 return rv # type: ignore 780 781 def _invoke(self, arguments: t.List[t.Any], autoescape: bool) -> str: 782 if self._environment.is_async: 783 return self._async_invoke(arguments, autoescape) # type: ignore 784 785 rv = self._func(*arguments) 786 787 if autoescape: 788 rv = Markup(rv) 789 790 return rv 791 792 def __repr__(self) -> str: 793 name = "anonymous" if self.name is None else repr(self.name) 794 return f"<{type(self).__name__} {name}>"
Wraps a macro function.
666 def __init__( 667 self, 668 environment: "Environment", 669 func: t.Callable[..., str], 670 name: str, 671 arguments: t.List[str], 672 catch_kwargs: bool, 673 catch_varargs: bool, 674 caller: bool, 675 default_autoescape: t.Optional[bool] = None, 676 ): 677 self._environment = environment 678 self._func = func 679 self._argument_count = len(arguments) 680 self.name = name 681 self.arguments = arguments 682 self.catch_kwargs = catch_kwargs 683 self.catch_varargs = catch_varargs 684 self.caller = caller 685 self.explicit_caller = "caller" in arguments 686 687 if default_autoescape is None: 688 if callable(environment.autoescape): 689 default_autoescape = environment.autoescape(None) 690 else: 691 default_autoescape = environment.autoescape 692 693 self._default_autoescape = default_autoescape
797class Undefined: 798 """The default undefined type. This can be printed, iterated, and treated as 799 a boolean. Any other operation will raise an :exc:`UndefinedError`. 800 801 >>> foo = Undefined(name='foo') 802 >>> str(foo) 803 '' 804 >>> not foo 805 True 806 >>> foo + 42 807 Traceback (most recent call last): 808 ... 809 jinja2.exceptions.UndefinedError: 'foo' is undefined 810 """ 811 812 __slots__ = ( 813 "_undefined_hint", 814 "_undefined_obj", 815 "_undefined_name", 816 "_undefined_exception", 817 ) 818 819 def __init__( 820 self, 821 hint: t.Optional[str] = None, 822 obj: t.Any = missing, 823 name: t.Optional[str] = None, 824 exc: t.Type[TemplateRuntimeError] = UndefinedError, 825 ) -> None: 826 self._undefined_hint = hint 827 self._undefined_obj = obj 828 self._undefined_name = name 829 self._undefined_exception = exc 830 831 @property 832 def _undefined_message(self) -> str: 833 """Build a message about the undefined value based on how it was 834 accessed. 835 """ 836 if self._undefined_hint: 837 return self._undefined_hint 838 839 if self._undefined_obj is missing: 840 return f"{self._undefined_name!r} is undefined" 841 842 if not isinstance(self._undefined_name, str): 843 return ( 844 f"{object_type_repr(self._undefined_obj)} has no" 845 f" element {self._undefined_name!r}" 846 ) 847 848 return ( 849 f"{object_type_repr(self._undefined_obj)!r} has no" 850 f" attribute {self._undefined_name!r}" 851 ) 852 853 @internalcode 854 def _fail_with_undefined_error( 855 self, *args: t.Any, **kwargs: t.Any 856 ) -> "te.NoReturn": 857 """Raise an :exc:`UndefinedError` when operations are performed 858 on the undefined value. 859 """ 860 raise self._undefined_exception(self._undefined_message) 861 862 @internalcode 863 def __getattr__(self, name: str) -> t.Any: 864 # Raise AttributeError on requests for names that appear to be unimplemented 865 # dunder methods to keep Python's internal protocol probing behaviors working 866 # properly in cases where another exception type could cause unexpected or 867 # difficult-to-diagnose failures. 868 if name[:2] == "__" and name[-2:] == "__": 869 raise AttributeError(name) 870 871 return self._fail_with_undefined_error() 872 873 __add__ = __radd__ = __sub__ = __rsub__ = _fail_with_undefined_error 874 __mul__ = __rmul__ = __div__ = __rdiv__ = _fail_with_undefined_error 875 __truediv__ = __rtruediv__ = _fail_with_undefined_error 876 __floordiv__ = __rfloordiv__ = _fail_with_undefined_error 877 __mod__ = __rmod__ = _fail_with_undefined_error 878 __pos__ = __neg__ = _fail_with_undefined_error 879 __call__ = __getitem__ = _fail_with_undefined_error 880 __lt__ = __le__ = __gt__ = __ge__ = _fail_with_undefined_error 881 __int__ = __float__ = __complex__ = _fail_with_undefined_error 882 __pow__ = __rpow__ = _fail_with_undefined_error 883 884 def __eq__(self, other: t.Any) -> bool: 885 return type(self) is type(other) 886 887 def __ne__(self, other: t.Any) -> bool: 888 return not self.__eq__(other) 889 890 def __hash__(self) -> int: 891 return id(type(self)) 892 893 def __str__(self) -> str: 894 return "" 895 896 def __len__(self) -> int: 897 return 0 898 899 def __iter__(self) -> t.Iterator[t.Any]: 900 yield from () 901 902 async def __aiter__(self) -> t.AsyncIterator[t.Any]: 903 for _ in (): 904 yield 905 906 def __bool__(self) -> bool: 907 return False 908 909 def __repr__(self) -> str: 910 return "Undefined"
The default undefined type. This can be printed, iterated, and treated as
a boolean. Any other operation 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
819 def __init__( 820 self, 821 hint: t.Optional[str] = None, 822 obj: t.Any = missing, 823 name: t.Optional[str] = None, 824 exc: t.Type[TemplateRuntimeError] = UndefinedError, 825 ) -> None: 826 self._undefined_hint = hint 827 self._undefined_obj = obj 828 self._undefined_name = name 829 self._undefined_exception = exc
913def make_logging_undefined( 914 logger: t.Optional["logging.Logger"] = None, base: t.Type[Undefined] = Undefined 915) -> t.Type[Undefined]: 916 """Given a logger object this returns a new undefined class that will 917 log certain failures. It will log iterations and printing. If no 918 logger is given a default logger is created. 919 920 Example:: 921 922 logger = logging.getLogger(__name__) 923 LoggingUndefined = make_logging_undefined( 924 logger=logger, 925 base=Undefined 926 ) 927 928 .. versionadded:: 2.8 929 930 :param logger: the logger to use. If not provided, a default logger 931 is created. 932 :param base: the base class to add logging functionality to. This 933 defaults to :class:`Undefined`. 934 """ 935 if logger is None: 936 import logging 937 938 logger = logging.getLogger(__name__) 939 logger.addHandler(logging.StreamHandler(sys.stderr)) 940 941 def _log_message(undef: Undefined) -> None: 942 logger.warning("Template variable warning: %s", undef._undefined_message) 943 944 class LoggingUndefined(base): # type: ignore 945 __slots__ = () 946 947 def _fail_with_undefined_error( # type: ignore 948 self, *args: t.Any, **kwargs: t.Any 949 ) -> "te.NoReturn": 950 try: 951 super()._fail_with_undefined_error(*args, **kwargs) 952 except self._undefined_exception as e: 953 logger.error("Template variable error: %s", e) # type: ignore 954 raise e 955 956 def __str__(self) -> str: 957 _log_message(self) 958 return super().__str__() # type: ignore 959 960 def __iter__(self) -> t.Iterator[t.Any]: 961 _log_message(self) 962 return super().__iter__() # type: ignore 963 964 def __bool__(self) -> bool: 965 _log_message(self) 966 return super().__bool__() # type: ignore 967 968 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
.
971class ChainableUndefined(Undefined): 972 """An undefined that is chainable, where both ``__getattr__`` and 973 ``__getitem__`` return itself rather than raising an 974 :exc:`UndefinedError`. 975 976 >>> foo = ChainableUndefined(name='foo') 977 >>> str(foo.bar['baz']) 978 '' 979 >>> foo.bar['baz'] + 42 980 Traceback (most recent call last): 981 ... 982 jinja2.exceptions.UndefinedError: 'foo' is undefined 983 984 .. versionadded:: 2.11.0 985 """ 986 987 __slots__ = () 988 989 def __html__(self) -> str: 990 return str(self) 991 992 def __getattr__(self, name: str) -> "ChainableUndefined": 993 # Raise AttributeError on requests for names that appear to be unimplemented 994 # dunder methods to avoid confusing Python with truthy non-method objects that 995 # do not implement the protocol being probed for. e.g., copy.copy(Undefined()) 996 # fails spectacularly if getattr(Undefined(), '__setstate__') returns an 997 # Undefined object instead of raising AttributeError to signal that it does not 998 # support that style of object initialization. 999 if name[:2] == "__" and name[-2:] == "__": 1000 raise AttributeError(name) 1001 1002 return self 1003 1004 def __getitem__(self, _name: str) -> "ChainableUndefined": # type: ignore[override] 1005 return self
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.
1008class DebugUndefined(Undefined): 1009 """An undefined that returns the debug info when printed. 1010 1011 >>> foo = DebugUndefined(name='foo') 1012 >>> str(foo) 1013 '{{ foo }}' 1014 >>> not foo 1015 True 1016 >>> foo + 42 1017 Traceback (most recent call last): 1018 ... 1019 jinja2.exceptions.UndefinedError: 'foo' is undefined 1020 """ 1021 1022 __slots__ = () 1023 1024 def __str__(self) -> str: 1025 if self._undefined_hint: 1026 message = f"undefined value printed: {self._undefined_hint}" 1027 1028 elif self._undefined_obj is missing: 1029 message = self._undefined_name # type: ignore 1030 1031 else: 1032 message = ( 1033 f"no such element: {object_type_repr(self._undefined_obj)}" 1034 f"[{self._undefined_name!r}]" 1035 ) 1036 1037 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
1040class StrictUndefined(Undefined): 1041 """An undefined that barks on print and iteration as well as boolean 1042 tests and all kinds of comparisons. In other words: you can do nothing 1043 with it except checking if it's defined using the `defined` test. 1044 1045 >>> foo = StrictUndefined(name='foo') 1046 >>> str(foo) 1047 Traceback (most recent call last): 1048 ... 1049 jinja2.exceptions.UndefinedError: 'foo' is undefined 1050 >>> not foo 1051 Traceback (most recent call last): 1052 ... 1053 jinja2.exceptions.UndefinedError: 'foo' is undefined 1054 >>> foo + 42 1055 Traceback (most recent call last): 1056 ... 1057 jinja2.exceptions.UndefinedError: 'foo' is undefined 1058 """ 1059 1060 __slots__ = () 1061 __iter__ = __str__ = __len__ = Undefined._fail_with_undefined_error 1062 __eq__ = __ne__ = __bool__ = __hash__ = Undefined._fail_with_undefined_error 1063 __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