Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/jinja2/runtime.py @ 0:26e78fe6e8c4 draft
"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
author | shellac |
---|---|
date | Sat, 02 May 2020 07:14:21 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:26e78fe6e8c4 |
---|---|
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 ) |