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