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