comparison env/lib/python3.9/site-packages/jinja2/runtime.py @ 0:4f3585e2f14b draft default tip

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