11cb0ef41Sopenharmony_ci# -*- coding: utf-8 -*- 21cb0ef41Sopenharmony_ci""" 31cb0ef41Sopenharmony_ci jinja2.runtime 41cb0ef41Sopenharmony_ci ~~~~~~~~~~~~~~ 51cb0ef41Sopenharmony_ci 61cb0ef41Sopenharmony_ci Runtime helpers. 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ci :copyright: (c) 2017 by the Jinja Team. 91cb0ef41Sopenharmony_ci :license: BSD. 101cb0ef41Sopenharmony_ci""" 111cb0ef41Sopenharmony_ciimport sys 121cb0ef41Sopenharmony_ci 131cb0ef41Sopenharmony_cifrom itertools import chain 141cb0ef41Sopenharmony_cifrom types import MethodType 151cb0ef41Sopenharmony_ci 161cb0ef41Sopenharmony_cifrom jinja2.nodes import EvalContext, _context_function_types 171cb0ef41Sopenharmony_cifrom jinja2.utils import Markup, soft_unicode, escape, missing, concat, \ 181cb0ef41Sopenharmony_ci internalcode, object_type_repr, evalcontextfunction, Namespace 191cb0ef41Sopenharmony_cifrom jinja2.exceptions import UndefinedError, TemplateRuntimeError, \ 201cb0ef41Sopenharmony_ci TemplateNotFound 211cb0ef41Sopenharmony_cifrom jinja2._compat import imap, text_type, iteritems, \ 221cb0ef41Sopenharmony_ci implements_iterator, implements_to_string, string_types, PY2, \ 231cb0ef41Sopenharmony_ci with_metaclass 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ci# these variables are exported to the template runtime 271cb0ef41Sopenharmony_ci__all__ = ['LoopContext', 'TemplateReference', 'Macro', 'Markup', 281cb0ef41Sopenharmony_ci 'TemplateRuntimeError', 'missing', 'concat', 'escape', 291cb0ef41Sopenharmony_ci 'markup_join', 'unicode_join', 'to_string', 'identity', 301cb0ef41Sopenharmony_ci 'TemplateNotFound', 'Namespace'] 311cb0ef41Sopenharmony_ci 321cb0ef41Sopenharmony_ci#: the name of the function that is used to convert something into 331cb0ef41Sopenharmony_ci#: a string. We can just use the text type here. 341cb0ef41Sopenharmony_cito_string = text_type 351cb0ef41Sopenharmony_ci 361cb0ef41Sopenharmony_ci#: the identity function. Useful for certain things in the environment 371cb0ef41Sopenharmony_ciidentity = lambda x: x 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_ci_first_iteration = object() 401cb0ef41Sopenharmony_ci_last_iteration = object() 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ci 431cb0ef41Sopenharmony_cidef markup_join(seq): 441cb0ef41Sopenharmony_ci """Concatenation that escapes if necessary and converts to unicode.""" 451cb0ef41Sopenharmony_ci buf = [] 461cb0ef41Sopenharmony_ci iterator = imap(soft_unicode, seq) 471cb0ef41Sopenharmony_ci for arg in iterator: 481cb0ef41Sopenharmony_ci buf.append(arg) 491cb0ef41Sopenharmony_ci if hasattr(arg, '__html__'): 501cb0ef41Sopenharmony_ci return Markup(u'').join(chain(buf, iterator)) 511cb0ef41Sopenharmony_ci return concat(buf) 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_cidef unicode_join(seq): 551cb0ef41Sopenharmony_ci """Simple args to unicode conversion and concatenation.""" 561cb0ef41Sopenharmony_ci return concat(imap(text_type, seq)) 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_cidef new_context(environment, template_name, blocks, vars=None, 601cb0ef41Sopenharmony_ci shared=None, globals=None, locals=None): 611cb0ef41Sopenharmony_ci """Internal helper to for context creation.""" 621cb0ef41Sopenharmony_ci if vars is None: 631cb0ef41Sopenharmony_ci vars = {} 641cb0ef41Sopenharmony_ci if shared: 651cb0ef41Sopenharmony_ci parent = vars 661cb0ef41Sopenharmony_ci else: 671cb0ef41Sopenharmony_ci parent = dict(globals or (), **vars) 681cb0ef41Sopenharmony_ci if locals: 691cb0ef41Sopenharmony_ci # if the parent is shared a copy should be created because 701cb0ef41Sopenharmony_ci # we don't want to modify the dict passed 711cb0ef41Sopenharmony_ci if shared: 721cb0ef41Sopenharmony_ci parent = dict(parent) 731cb0ef41Sopenharmony_ci for key, value in iteritems(locals): 741cb0ef41Sopenharmony_ci if value is not missing: 751cb0ef41Sopenharmony_ci parent[key] = value 761cb0ef41Sopenharmony_ci return environment.context_class(environment, parent, template_name, 771cb0ef41Sopenharmony_ci blocks) 781cb0ef41Sopenharmony_ci 791cb0ef41Sopenharmony_ci 801cb0ef41Sopenharmony_ciclass TemplateReference(object): 811cb0ef41Sopenharmony_ci """The `self` in templates.""" 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_ci def __init__(self, context): 841cb0ef41Sopenharmony_ci self.__context = context 851cb0ef41Sopenharmony_ci 861cb0ef41Sopenharmony_ci def __getitem__(self, name): 871cb0ef41Sopenharmony_ci blocks = self.__context.blocks[name] 881cb0ef41Sopenharmony_ci return BlockReference(name, self.__context, blocks, 0) 891cb0ef41Sopenharmony_ci 901cb0ef41Sopenharmony_ci def __repr__(self): 911cb0ef41Sopenharmony_ci return '<%s %r>' % ( 921cb0ef41Sopenharmony_ci self.__class__.__name__, 931cb0ef41Sopenharmony_ci self.__context.name 941cb0ef41Sopenharmony_ci ) 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_ci 971cb0ef41Sopenharmony_cidef _get_func(x): 981cb0ef41Sopenharmony_ci return getattr(x, '__func__', x) 991cb0ef41Sopenharmony_ci 1001cb0ef41Sopenharmony_ci 1011cb0ef41Sopenharmony_ciclass ContextMeta(type): 1021cb0ef41Sopenharmony_ci 1031cb0ef41Sopenharmony_ci def __new__(cls, name, bases, d): 1041cb0ef41Sopenharmony_ci rv = type.__new__(cls, name, bases, d) 1051cb0ef41Sopenharmony_ci if bases == (): 1061cb0ef41Sopenharmony_ci return rv 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci resolve = _get_func(rv.resolve) 1091cb0ef41Sopenharmony_ci default_resolve = _get_func(Context.resolve) 1101cb0ef41Sopenharmony_ci resolve_or_missing = _get_func(rv.resolve_or_missing) 1111cb0ef41Sopenharmony_ci default_resolve_or_missing = _get_func(Context.resolve_or_missing) 1121cb0ef41Sopenharmony_ci 1131cb0ef41Sopenharmony_ci # If we have a changed resolve but no changed default or missing 1141cb0ef41Sopenharmony_ci # resolve we invert the call logic. 1151cb0ef41Sopenharmony_ci if resolve is not default_resolve and \ 1161cb0ef41Sopenharmony_ci resolve_or_missing is default_resolve_or_missing: 1171cb0ef41Sopenharmony_ci rv._legacy_resolve_mode = True 1181cb0ef41Sopenharmony_ci elif resolve is default_resolve and \ 1191cb0ef41Sopenharmony_ci resolve_or_missing is default_resolve_or_missing: 1201cb0ef41Sopenharmony_ci rv._fast_resolve_mode = True 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci return rv 1231cb0ef41Sopenharmony_ci 1241cb0ef41Sopenharmony_ci 1251cb0ef41Sopenharmony_cidef resolve_or_missing(context, key, missing=missing): 1261cb0ef41Sopenharmony_ci if key in context.vars: 1271cb0ef41Sopenharmony_ci return context.vars[key] 1281cb0ef41Sopenharmony_ci if key in context.parent: 1291cb0ef41Sopenharmony_ci return context.parent[key] 1301cb0ef41Sopenharmony_ci return missing 1311cb0ef41Sopenharmony_ci 1321cb0ef41Sopenharmony_ci 1331cb0ef41Sopenharmony_ciclass Context(with_metaclass(ContextMeta)): 1341cb0ef41Sopenharmony_ci """The template context holds the variables of a template. It stores the 1351cb0ef41Sopenharmony_ci values passed to the template and also the names the template exports. 1361cb0ef41Sopenharmony_ci Creating instances is neither supported nor useful as it's created 1371cb0ef41Sopenharmony_ci automatically at various stages of the template evaluation and should not 1381cb0ef41Sopenharmony_ci be created by hand. 1391cb0ef41Sopenharmony_ci 1401cb0ef41Sopenharmony_ci The context is immutable. Modifications on :attr:`parent` **must not** 1411cb0ef41Sopenharmony_ci happen and modifications on :attr:`vars` are allowed from generated 1421cb0ef41Sopenharmony_ci template code only. Template filters and global functions marked as 1431cb0ef41Sopenharmony_ci :func:`contextfunction`\\s get the active context passed as first argument 1441cb0ef41Sopenharmony_ci and are allowed to access the context read-only. 1451cb0ef41Sopenharmony_ci 1461cb0ef41Sopenharmony_ci The template context supports read only dict operations (`get`, 1471cb0ef41Sopenharmony_ci `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`, 1481cb0ef41Sopenharmony_ci `__getitem__`, `__contains__`). Additionally there is a :meth:`resolve` 1491cb0ef41Sopenharmony_ci method that doesn't fail with a `KeyError` but returns an 1501cb0ef41Sopenharmony_ci :class:`Undefined` object for missing variables. 1511cb0ef41Sopenharmony_ci """ 1521cb0ef41Sopenharmony_ci # XXX: we want to eventually make this be a deprecation warning and 1531cb0ef41Sopenharmony_ci # remove it. 1541cb0ef41Sopenharmony_ci _legacy_resolve_mode = False 1551cb0ef41Sopenharmony_ci _fast_resolve_mode = False 1561cb0ef41Sopenharmony_ci 1571cb0ef41Sopenharmony_ci def __init__(self, environment, parent, name, blocks): 1581cb0ef41Sopenharmony_ci self.parent = parent 1591cb0ef41Sopenharmony_ci self.vars = {} 1601cb0ef41Sopenharmony_ci self.environment = environment 1611cb0ef41Sopenharmony_ci self.eval_ctx = EvalContext(self.environment, name) 1621cb0ef41Sopenharmony_ci self.exported_vars = set() 1631cb0ef41Sopenharmony_ci self.name = name 1641cb0ef41Sopenharmony_ci 1651cb0ef41Sopenharmony_ci # create the initial mapping of blocks. Whenever template inheritance 1661cb0ef41Sopenharmony_ci # takes place the runtime will update this mapping with the new blocks 1671cb0ef41Sopenharmony_ci # from the template. 1681cb0ef41Sopenharmony_ci self.blocks = dict((k, [v]) for k, v in iteritems(blocks)) 1691cb0ef41Sopenharmony_ci 1701cb0ef41Sopenharmony_ci # In case we detect the fast resolve mode we can set up an alias 1711cb0ef41Sopenharmony_ci # here that bypasses the legacy code logic. 1721cb0ef41Sopenharmony_ci if self._fast_resolve_mode: 1731cb0ef41Sopenharmony_ci self.resolve_or_missing = MethodType(resolve_or_missing, self) 1741cb0ef41Sopenharmony_ci 1751cb0ef41Sopenharmony_ci def super(self, name, current): 1761cb0ef41Sopenharmony_ci """Render a parent block.""" 1771cb0ef41Sopenharmony_ci try: 1781cb0ef41Sopenharmony_ci blocks = self.blocks[name] 1791cb0ef41Sopenharmony_ci index = blocks.index(current) + 1 1801cb0ef41Sopenharmony_ci blocks[index] 1811cb0ef41Sopenharmony_ci except LookupError: 1821cb0ef41Sopenharmony_ci return self.environment.undefined('there is no parent block ' 1831cb0ef41Sopenharmony_ci 'called %r.' % name, 1841cb0ef41Sopenharmony_ci name='super') 1851cb0ef41Sopenharmony_ci return BlockReference(name, self, blocks, index) 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_ci def get(self, key, default=None): 1881cb0ef41Sopenharmony_ci """Returns an item from the template context, if it doesn't exist 1891cb0ef41Sopenharmony_ci `default` is returned. 1901cb0ef41Sopenharmony_ci """ 1911cb0ef41Sopenharmony_ci try: 1921cb0ef41Sopenharmony_ci return self[key] 1931cb0ef41Sopenharmony_ci except KeyError: 1941cb0ef41Sopenharmony_ci return default 1951cb0ef41Sopenharmony_ci 1961cb0ef41Sopenharmony_ci def resolve(self, key): 1971cb0ef41Sopenharmony_ci """Looks up a variable like `__getitem__` or `get` but returns an 1981cb0ef41Sopenharmony_ci :class:`Undefined` object with the name of the name looked up. 1991cb0ef41Sopenharmony_ci """ 2001cb0ef41Sopenharmony_ci if self._legacy_resolve_mode: 2011cb0ef41Sopenharmony_ci rv = resolve_or_missing(self, key) 2021cb0ef41Sopenharmony_ci else: 2031cb0ef41Sopenharmony_ci rv = self.resolve_or_missing(key) 2041cb0ef41Sopenharmony_ci if rv is missing: 2051cb0ef41Sopenharmony_ci return self.environment.undefined(name=key) 2061cb0ef41Sopenharmony_ci return rv 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_ci def resolve_or_missing(self, key): 2091cb0ef41Sopenharmony_ci """Resolves a variable like :meth:`resolve` but returns the 2101cb0ef41Sopenharmony_ci special `missing` value if it cannot be found. 2111cb0ef41Sopenharmony_ci """ 2121cb0ef41Sopenharmony_ci if self._legacy_resolve_mode: 2131cb0ef41Sopenharmony_ci rv = self.resolve(key) 2141cb0ef41Sopenharmony_ci if isinstance(rv, Undefined): 2151cb0ef41Sopenharmony_ci rv = missing 2161cb0ef41Sopenharmony_ci return rv 2171cb0ef41Sopenharmony_ci return resolve_or_missing(self, key) 2181cb0ef41Sopenharmony_ci 2191cb0ef41Sopenharmony_ci def get_exported(self): 2201cb0ef41Sopenharmony_ci """Get a new dict with the exported variables.""" 2211cb0ef41Sopenharmony_ci return dict((k, self.vars[k]) for k in self.exported_vars) 2221cb0ef41Sopenharmony_ci 2231cb0ef41Sopenharmony_ci def get_all(self): 2241cb0ef41Sopenharmony_ci """Return the complete context as dict including the exported 2251cb0ef41Sopenharmony_ci variables. For optimizations reasons this might not return an 2261cb0ef41Sopenharmony_ci actual copy so be careful with using it. 2271cb0ef41Sopenharmony_ci """ 2281cb0ef41Sopenharmony_ci if not self.vars: 2291cb0ef41Sopenharmony_ci return self.parent 2301cb0ef41Sopenharmony_ci if not self.parent: 2311cb0ef41Sopenharmony_ci return self.vars 2321cb0ef41Sopenharmony_ci return dict(self.parent, **self.vars) 2331cb0ef41Sopenharmony_ci 2341cb0ef41Sopenharmony_ci @internalcode 2351cb0ef41Sopenharmony_ci def call(__self, __obj, *args, **kwargs): 2361cb0ef41Sopenharmony_ci """Call the callable with the arguments and keyword arguments 2371cb0ef41Sopenharmony_ci provided but inject the active context or environment as first 2381cb0ef41Sopenharmony_ci argument if the callable is a :func:`contextfunction` or 2391cb0ef41Sopenharmony_ci :func:`environmentfunction`. 2401cb0ef41Sopenharmony_ci """ 2411cb0ef41Sopenharmony_ci if __debug__: 2421cb0ef41Sopenharmony_ci __traceback_hide__ = True # noqa 2431cb0ef41Sopenharmony_ci 2441cb0ef41Sopenharmony_ci # Allow callable classes to take a context 2451cb0ef41Sopenharmony_ci if hasattr(__obj, '__call__'): 2461cb0ef41Sopenharmony_ci fn = __obj.__call__ 2471cb0ef41Sopenharmony_ci for fn_type in ('contextfunction', 2481cb0ef41Sopenharmony_ci 'evalcontextfunction', 2491cb0ef41Sopenharmony_ci 'environmentfunction'): 2501cb0ef41Sopenharmony_ci if hasattr(fn, fn_type): 2511cb0ef41Sopenharmony_ci __obj = fn 2521cb0ef41Sopenharmony_ci break 2531cb0ef41Sopenharmony_ci 2541cb0ef41Sopenharmony_ci if isinstance(__obj, _context_function_types): 2551cb0ef41Sopenharmony_ci if getattr(__obj, 'contextfunction', 0): 2561cb0ef41Sopenharmony_ci args = (__self,) + args 2571cb0ef41Sopenharmony_ci elif getattr(__obj, 'evalcontextfunction', 0): 2581cb0ef41Sopenharmony_ci args = (__self.eval_ctx,) + args 2591cb0ef41Sopenharmony_ci elif getattr(__obj, 'environmentfunction', 0): 2601cb0ef41Sopenharmony_ci args = (__self.environment,) + args 2611cb0ef41Sopenharmony_ci try: 2621cb0ef41Sopenharmony_ci return __obj(*args, **kwargs) 2631cb0ef41Sopenharmony_ci except StopIteration: 2641cb0ef41Sopenharmony_ci return __self.environment.undefined('value was undefined because ' 2651cb0ef41Sopenharmony_ci 'a callable raised a ' 2661cb0ef41Sopenharmony_ci 'StopIteration exception') 2671cb0ef41Sopenharmony_ci 2681cb0ef41Sopenharmony_ci def derived(self, locals=None): 2691cb0ef41Sopenharmony_ci """Internal helper function to create a derived context. This is 2701cb0ef41Sopenharmony_ci used in situations where the system needs a new context in the same 2711cb0ef41Sopenharmony_ci template that is independent. 2721cb0ef41Sopenharmony_ci """ 2731cb0ef41Sopenharmony_ci context = new_context(self.environment, self.name, {}, 2741cb0ef41Sopenharmony_ci self.get_all(), True, None, locals) 2751cb0ef41Sopenharmony_ci context.eval_ctx = self.eval_ctx 2761cb0ef41Sopenharmony_ci context.blocks.update((k, list(v)) for k, v in iteritems(self.blocks)) 2771cb0ef41Sopenharmony_ci return context 2781cb0ef41Sopenharmony_ci 2791cb0ef41Sopenharmony_ci def _all(meth): 2801cb0ef41Sopenharmony_ci proxy = lambda self: getattr(self.get_all(), meth)() 2811cb0ef41Sopenharmony_ci proxy.__doc__ = getattr(dict, meth).__doc__ 2821cb0ef41Sopenharmony_ci proxy.__name__ = meth 2831cb0ef41Sopenharmony_ci return proxy 2841cb0ef41Sopenharmony_ci 2851cb0ef41Sopenharmony_ci keys = _all('keys') 2861cb0ef41Sopenharmony_ci values = _all('values') 2871cb0ef41Sopenharmony_ci items = _all('items') 2881cb0ef41Sopenharmony_ci 2891cb0ef41Sopenharmony_ci # not available on python 3 2901cb0ef41Sopenharmony_ci if PY2: 2911cb0ef41Sopenharmony_ci iterkeys = _all('iterkeys') 2921cb0ef41Sopenharmony_ci itervalues = _all('itervalues') 2931cb0ef41Sopenharmony_ci iteritems = _all('iteritems') 2941cb0ef41Sopenharmony_ci del _all 2951cb0ef41Sopenharmony_ci 2961cb0ef41Sopenharmony_ci def __contains__(self, name): 2971cb0ef41Sopenharmony_ci return name in self.vars or name in self.parent 2981cb0ef41Sopenharmony_ci 2991cb0ef41Sopenharmony_ci def __getitem__(self, key): 3001cb0ef41Sopenharmony_ci """Lookup a variable or raise `KeyError` if the variable is 3011cb0ef41Sopenharmony_ci undefined. 3021cb0ef41Sopenharmony_ci """ 3031cb0ef41Sopenharmony_ci item = self.resolve_or_missing(key) 3041cb0ef41Sopenharmony_ci if item is missing: 3051cb0ef41Sopenharmony_ci raise KeyError(key) 3061cb0ef41Sopenharmony_ci return item 3071cb0ef41Sopenharmony_ci 3081cb0ef41Sopenharmony_ci def __repr__(self): 3091cb0ef41Sopenharmony_ci return '<%s %s of %r>' % ( 3101cb0ef41Sopenharmony_ci self.__class__.__name__, 3111cb0ef41Sopenharmony_ci repr(self.get_all()), 3121cb0ef41Sopenharmony_ci self.name 3131cb0ef41Sopenharmony_ci ) 3141cb0ef41Sopenharmony_ci 3151cb0ef41Sopenharmony_ci 3161cb0ef41Sopenharmony_ci# register the context as mapping if possible 3171cb0ef41Sopenharmony_citry: 3181cb0ef41Sopenharmony_ci from collections import Mapping 3191cb0ef41Sopenharmony_ci Mapping.register(Context) 3201cb0ef41Sopenharmony_ciexcept ImportError: 3211cb0ef41Sopenharmony_ci pass 3221cb0ef41Sopenharmony_ci 3231cb0ef41Sopenharmony_ci 3241cb0ef41Sopenharmony_ciclass BlockReference(object): 3251cb0ef41Sopenharmony_ci """One block on a template reference.""" 3261cb0ef41Sopenharmony_ci 3271cb0ef41Sopenharmony_ci def __init__(self, name, context, stack, depth): 3281cb0ef41Sopenharmony_ci self.name = name 3291cb0ef41Sopenharmony_ci self._context = context 3301cb0ef41Sopenharmony_ci self._stack = stack 3311cb0ef41Sopenharmony_ci self._depth = depth 3321cb0ef41Sopenharmony_ci 3331cb0ef41Sopenharmony_ci @property 3341cb0ef41Sopenharmony_ci def super(self): 3351cb0ef41Sopenharmony_ci """Super the block.""" 3361cb0ef41Sopenharmony_ci if self._depth + 1 >= len(self._stack): 3371cb0ef41Sopenharmony_ci return self._context.environment. \ 3381cb0ef41Sopenharmony_ci undefined('there is no parent block called %r.' % 3391cb0ef41Sopenharmony_ci self.name, name='super') 3401cb0ef41Sopenharmony_ci return BlockReference(self.name, self._context, self._stack, 3411cb0ef41Sopenharmony_ci self._depth + 1) 3421cb0ef41Sopenharmony_ci 3431cb0ef41Sopenharmony_ci @internalcode 3441cb0ef41Sopenharmony_ci def __call__(self): 3451cb0ef41Sopenharmony_ci rv = concat(self._stack[self._depth](self._context)) 3461cb0ef41Sopenharmony_ci if self._context.eval_ctx.autoescape: 3471cb0ef41Sopenharmony_ci rv = Markup(rv) 3481cb0ef41Sopenharmony_ci return rv 3491cb0ef41Sopenharmony_ci 3501cb0ef41Sopenharmony_ci 3511cb0ef41Sopenharmony_ciclass LoopContextBase(object): 3521cb0ef41Sopenharmony_ci """A loop context for dynamic iteration.""" 3531cb0ef41Sopenharmony_ci 3541cb0ef41Sopenharmony_ci _before = _first_iteration 3551cb0ef41Sopenharmony_ci _current = _first_iteration 3561cb0ef41Sopenharmony_ci _after = _last_iteration 3571cb0ef41Sopenharmony_ci _length = None 3581cb0ef41Sopenharmony_ci 3591cb0ef41Sopenharmony_ci def __init__(self, undefined, recurse=None, depth0=0): 3601cb0ef41Sopenharmony_ci self._undefined = undefined 3611cb0ef41Sopenharmony_ci self._recurse = recurse 3621cb0ef41Sopenharmony_ci self.index0 = -1 3631cb0ef41Sopenharmony_ci self.depth0 = depth0 3641cb0ef41Sopenharmony_ci self._last_checked_value = missing 3651cb0ef41Sopenharmony_ci 3661cb0ef41Sopenharmony_ci def cycle(self, *args): 3671cb0ef41Sopenharmony_ci """Cycles among the arguments with the current loop index.""" 3681cb0ef41Sopenharmony_ci if not args: 3691cb0ef41Sopenharmony_ci raise TypeError('no items for cycling given') 3701cb0ef41Sopenharmony_ci return args[self.index0 % len(args)] 3711cb0ef41Sopenharmony_ci 3721cb0ef41Sopenharmony_ci def changed(self, *value): 3731cb0ef41Sopenharmony_ci """Checks whether the value has changed since the last call.""" 3741cb0ef41Sopenharmony_ci if self._last_checked_value != value: 3751cb0ef41Sopenharmony_ci self._last_checked_value = value 3761cb0ef41Sopenharmony_ci return True 3771cb0ef41Sopenharmony_ci return False 3781cb0ef41Sopenharmony_ci 3791cb0ef41Sopenharmony_ci first = property(lambda x: x.index0 == 0) 3801cb0ef41Sopenharmony_ci last = property(lambda x: x._after is _last_iteration) 3811cb0ef41Sopenharmony_ci index = property(lambda x: x.index0 + 1) 3821cb0ef41Sopenharmony_ci revindex = property(lambda x: x.length - x.index0) 3831cb0ef41Sopenharmony_ci revindex0 = property(lambda x: x.length - x.index) 3841cb0ef41Sopenharmony_ci depth = property(lambda x: x.depth0 + 1) 3851cb0ef41Sopenharmony_ci 3861cb0ef41Sopenharmony_ci @property 3871cb0ef41Sopenharmony_ci def previtem(self): 3881cb0ef41Sopenharmony_ci if self._before is _first_iteration: 3891cb0ef41Sopenharmony_ci return self._undefined('there is no previous item') 3901cb0ef41Sopenharmony_ci return self._before 3911cb0ef41Sopenharmony_ci 3921cb0ef41Sopenharmony_ci @property 3931cb0ef41Sopenharmony_ci def nextitem(self): 3941cb0ef41Sopenharmony_ci if self._after is _last_iteration: 3951cb0ef41Sopenharmony_ci return self._undefined('there is no next item') 3961cb0ef41Sopenharmony_ci return self._after 3971cb0ef41Sopenharmony_ci 3981cb0ef41Sopenharmony_ci def __len__(self): 3991cb0ef41Sopenharmony_ci return self.length 4001cb0ef41Sopenharmony_ci 4011cb0ef41Sopenharmony_ci @internalcode 4021cb0ef41Sopenharmony_ci def loop(self, iterable): 4031cb0ef41Sopenharmony_ci if self._recurse is None: 4041cb0ef41Sopenharmony_ci raise TypeError('Tried to call non recursive loop. Maybe you ' 4051cb0ef41Sopenharmony_ci "forgot the 'recursive' modifier.") 4061cb0ef41Sopenharmony_ci return self._recurse(iterable, self._recurse, self.depth0 + 1) 4071cb0ef41Sopenharmony_ci 4081cb0ef41Sopenharmony_ci # a nifty trick to enhance the error message if someone tried to call 4091cb0ef41Sopenharmony_ci # the the loop without or with too many arguments. 4101cb0ef41Sopenharmony_ci __call__ = loop 4111cb0ef41Sopenharmony_ci del loop 4121cb0ef41Sopenharmony_ci 4131cb0ef41Sopenharmony_ci def __repr__(self): 4141cb0ef41Sopenharmony_ci return '<%s %r/%r>' % ( 4151cb0ef41Sopenharmony_ci self.__class__.__name__, 4161cb0ef41Sopenharmony_ci self.index, 4171cb0ef41Sopenharmony_ci self.length 4181cb0ef41Sopenharmony_ci ) 4191cb0ef41Sopenharmony_ci 4201cb0ef41Sopenharmony_ci 4211cb0ef41Sopenharmony_ciclass LoopContext(LoopContextBase): 4221cb0ef41Sopenharmony_ci 4231cb0ef41Sopenharmony_ci def __init__(self, iterable, undefined, recurse=None, depth0=0): 4241cb0ef41Sopenharmony_ci LoopContextBase.__init__(self, undefined, recurse, depth0) 4251cb0ef41Sopenharmony_ci self._iterator = iter(iterable) 4261cb0ef41Sopenharmony_ci 4271cb0ef41Sopenharmony_ci # try to get the length of the iterable early. This must be done 4281cb0ef41Sopenharmony_ci # here because there are some broken iterators around where there 4291cb0ef41Sopenharmony_ci # __len__ is the number of iterations left (i'm looking at your 4301cb0ef41Sopenharmony_ci # listreverseiterator!). 4311cb0ef41Sopenharmony_ci try: 4321cb0ef41Sopenharmony_ci self._length = len(iterable) 4331cb0ef41Sopenharmony_ci except (TypeError, AttributeError): 4341cb0ef41Sopenharmony_ci self._length = None 4351cb0ef41Sopenharmony_ci self._after = self._safe_next() 4361cb0ef41Sopenharmony_ci 4371cb0ef41Sopenharmony_ci @property 4381cb0ef41Sopenharmony_ci def length(self): 4391cb0ef41Sopenharmony_ci if self._length is None: 4401cb0ef41Sopenharmony_ci # if was not possible to get the length of the iterator when 4411cb0ef41Sopenharmony_ci # the loop context was created (ie: iterating over a generator) 4421cb0ef41Sopenharmony_ci # we have to convert the iterable into a sequence and use the 4431cb0ef41Sopenharmony_ci # length of that + the number of iterations so far. 4441cb0ef41Sopenharmony_ci iterable = tuple(self._iterator) 4451cb0ef41Sopenharmony_ci self._iterator = iter(iterable) 4461cb0ef41Sopenharmony_ci iterations_done = self.index0 + 2 4471cb0ef41Sopenharmony_ci self._length = len(iterable) + iterations_done 4481cb0ef41Sopenharmony_ci return self._length 4491cb0ef41Sopenharmony_ci 4501cb0ef41Sopenharmony_ci def __iter__(self): 4511cb0ef41Sopenharmony_ci return LoopContextIterator(self) 4521cb0ef41Sopenharmony_ci 4531cb0ef41Sopenharmony_ci def _safe_next(self): 4541cb0ef41Sopenharmony_ci try: 4551cb0ef41Sopenharmony_ci return next(self._iterator) 4561cb0ef41Sopenharmony_ci except StopIteration: 4571cb0ef41Sopenharmony_ci return _last_iteration 4581cb0ef41Sopenharmony_ci 4591cb0ef41Sopenharmony_ci 4601cb0ef41Sopenharmony_ci@implements_iterator 4611cb0ef41Sopenharmony_ciclass LoopContextIterator(object): 4621cb0ef41Sopenharmony_ci """The iterator for a loop context.""" 4631cb0ef41Sopenharmony_ci __slots__ = ('context',) 4641cb0ef41Sopenharmony_ci 4651cb0ef41Sopenharmony_ci def __init__(self, context): 4661cb0ef41Sopenharmony_ci self.context = context 4671cb0ef41Sopenharmony_ci 4681cb0ef41Sopenharmony_ci def __iter__(self): 4691cb0ef41Sopenharmony_ci return self 4701cb0ef41Sopenharmony_ci 4711cb0ef41Sopenharmony_ci def __next__(self): 4721cb0ef41Sopenharmony_ci ctx = self.context 4731cb0ef41Sopenharmony_ci ctx.index0 += 1 4741cb0ef41Sopenharmony_ci if ctx._after is _last_iteration: 4751cb0ef41Sopenharmony_ci raise StopIteration() 4761cb0ef41Sopenharmony_ci ctx._before = ctx._current 4771cb0ef41Sopenharmony_ci ctx._current = ctx._after 4781cb0ef41Sopenharmony_ci ctx._after = ctx._safe_next() 4791cb0ef41Sopenharmony_ci return ctx._current, ctx 4801cb0ef41Sopenharmony_ci 4811cb0ef41Sopenharmony_ci 4821cb0ef41Sopenharmony_ciclass Macro(object): 4831cb0ef41Sopenharmony_ci """Wraps a macro function.""" 4841cb0ef41Sopenharmony_ci 4851cb0ef41Sopenharmony_ci def __init__(self, environment, func, name, arguments, 4861cb0ef41Sopenharmony_ci catch_kwargs, catch_varargs, caller, 4871cb0ef41Sopenharmony_ci default_autoescape=None): 4881cb0ef41Sopenharmony_ci self._environment = environment 4891cb0ef41Sopenharmony_ci self._func = func 4901cb0ef41Sopenharmony_ci self._argument_count = len(arguments) 4911cb0ef41Sopenharmony_ci self.name = name 4921cb0ef41Sopenharmony_ci self.arguments = arguments 4931cb0ef41Sopenharmony_ci self.catch_kwargs = catch_kwargs 4941cb0ef41Sopenharmony_ci self.catch_varargs = catch_varargs 4951cb0ef41Sopenharmony_ci self.caller = caller 4961cb0ef41Sopenharmony_ci self.explicit_caller = 'caller' in arguments 4971cb0ef41Sopenharmony_ci if default_autoescape is None: 4981cb0ef41Sopenharmony_ci default_autoescape = environment.autoescape 4991cb0ef41Sopenharmony_ci self._default_autoescape = default_autoescape 5001cb0ef41Sopenharmony_ci 5011cb0ef41Sopenharmony_ci @internalcode 5021cb0ef41Sopenharmony_ci @evalcontextfunction 5031cb0ef41Sopenharmony_ci def __call__(self, *args, **kwargs): 5041cb0ef41Sopenharmony_ci # This requires a bit of explanation, In the past we used to 5051cb0ef41Sopenharmony_ci # decide largely based on compile-time information if a macro is 5061cb0ef41Sopenharmony_ci # safe or unsafe. While there was a volatile mode it was largely 5071cb0ef41Sopenharmony_ci # unused for deciding on escaping. This turns out to be 5081cb0ef41Sopenharmony_ci # problemtic for macros because if a macro is safe or not not so 5091cb0ef41Sopenharmony_ci # much depends on the escape mode when it was defined but when it 5101cb0ef41Sopenharmony_ci # was used. 5111cb0ef41Sopenharmony_ci # 5121cb0ef41Sopenharmony_ci # Because however we export macros from the module system and 5131cb0ef41Sopenharmony_ci # there are historic callers that do not pass an eval context (and 5141cb0ef41Sopenharmony_ci # will continue to not pass one), we need to perform an instance 5151cb0ef41Sopenharmony_ci # check here. 5161cb0ef41Sopenharmony_ci # 5171cb0ef41Sopenharmony_ci # This is considered safe because an eval context is not a valid 5181cb0ef41Sopenharmony_ci # argument to callables otherwise anwyays. Worst case here is 5191cb0ef41Sopenharmony_ci # that if no eval context is passed we fall back to the compile 5201cb0ef41Sopenharmony_ci # time autoescape flag. 5211cb0ef41Sopenharmony_ci if args and isinstance(args[0], EvalContext): 5221cb0ef41Sopenharmony_ci autoescape = args[0].autoescape 5231cb0ef41Sopenharmony_ci args = args[1:] 5241cb0ef41Sopenharmony_ci else: 5251cb0ef41Sopenharmony_ci autoescape = self._default_autoescape 5261cb0ef41Sopenharmony_ci 5271cb0ef41Sopenharmony_ci # try to consume the positional arguments 5281cb0ef41Sopenharmony_ci arguments = list(args[:self._argument_count]) 5291cb0ef41Sopenharmony_ci off = len(arguments) 5301cb0ef41Sopenharmony_ci 5311cb0ef41Sopenharmony_ci # For information why this is necessary refer to the handling 5321cb0ef41Sopenharmony_ci # of caller in the `macro_body` handler in the compiler. 5331cb0ef41Sopenharmony_ci found_caller = False 5341cb0ef41Sopenharmony_ci 5351cb0ef41Sopenharmony_ci # if the number of arguments consumed is not the number of 5361cb0ef41Sopenharmony_ci # arguments expected we start filling in keyword arguments 5371cb0ef41Sopenharmony_ci # and defaults. 5381cb0ef41Sopenharmony_ci if off != self._argument_count: 5391cb0ef41Sopenharmony_ci for idx, name in enumerate(self.arguments[len(arguments):]): 5401cb0ef41Sopenharmony_ci try: 5411cb0ef41Sopenharmony_ci value = kwargs.pop(name) 5421cb0ef41Sopenharmony_ci except KeyError: 5431cb0ef41Sopenharmony_ci value = missing 5441cb0ef41Sopenharmony_ci if name == 'caller': 5451cb0ef41Sopenharmony_ci found_caller = True 5461cb0ef41Sopenharmony_ci arguments.append(value) 5471cb0ef41Sopenharmony_ci else: 5481cb0ef41Sopenharmony_ci found_caller = self.explicit_caller 5491cb0ef41Sopenharmony_ci 5501cb0ef41Sopenharmony_ci # it's important that the order of these arguments does not change 5511cb0ef41Sopenharmony_ci # if not also changed in the compiler's `function_scoping` method. 5521cb0ef41Sopenharmony_ci # the order is caller, keyword arguments, positional arguments! 5531cb0ef41Sopenharmony_ci if self.caller and not found_caller: 5541cb0ef41Sopenharmony_ci caller = kwargs.pop('caller', None) 5551cb0ef41Sopenharmony_ci if caller is None: 5561cb0ef41Sopenharmony_ci caller = self._environment.undefined('No caller defined', 5571cb0ef41Sopenharmony_ci name='caller') 5581cb0ef41Sopenharmony_ci arguments.append(caller) 5591cb0ef41Sopenharmony_ci 5601cb0ef41Sopenharmony_ci if self.catch_kwargs: 5611cb0ef41Sopenharmony_ci arguments.append(kwargs) 5621cb0ef41Sopenharmony_ci elif kwargs: 5631cb0ef41Sopenharmony_ci if 'caller' in kwargs: 5641cb0ef41Sopenharmony_ci raise TypeError('macro %r was invoked with two values for ' 5651cb0ef41Sopenharmony_ci 'the special caller argument. This is ' 5661cb0ef41Sopenharmony_ci 'most likely a bug.' % self.name) 5671cb0ef41Sopenharmony_ci raise TypeError('macro %r takes no keyword argument %r' % 5681cb0ef41Sopenharmony_ci (self.name, next(iter(kwargs)))) 5691cb0ef41Sopenharmony_ci if self.catch_varargs: 5701cb0ef41Sopenharmony_ci arguments.append(args[self._argument_count:]) 5711cb0ef41Sopenharmony_ci elif len(args) > self._argument_count: 5721cb0ef41Sopenharmony_ci raise TypeError('macro %r takes not more than %d argument(s)' % 5731cb0ef41Sopenharmony_ci (self.name, len(self.arguments))) 5741cb0ef41Sopenharmony_ci 5751cb0ef41Sopenharmony_ci return self._invoke(arguments, autoescape) 5761cb0ef41Sopenharmony_ci 5771cb0ef41Sopenharmony_ci def _invoke(self, arguments, autoescape): 5781cb0ef41Sopenharmony_ci """This method is being swapped out by the async implementation.""" 5791cb0ef41Sopenharmony_ci rv = self._func(*arguments) 5801cb0ef41Sopenharmony_ci if autoescape: 5811cb0ef41Sopenharmony_ci rv = Markup(rv) 5821cb0ef41Sopenharmony_ci return rv 5831cb0ef41Sopenharmony_ci 5841cb0ef41Sopenharmony_ci def __repr__(self): 5851cb0ef41Sopenharmony_ci return '<%s %s>' % ( 5861cb0ef41Sopenharmony_ci self.__class__.__name__, 5871cb0ef41Sopenharmony_ci self.name is None and 'anonymous' or repr(self.name) 5881cb0ef41Sopenharmony_ci ) 5891cb0ef41Sopenharmony_ci 5901cb0ef41Sopenharmony_ci 5911cb0ef41Sopenharmony_ci@implements_to_string 5921cb0ef41Sopenharmony_ciclass Undefined(object): 5931cb0ef41Sopenharmony_ci """The default undefined type. This undefined type can be printed and 5941cb0ef41Sopenharmony_ci iterated over, but every other access will raise an :exc:`jinja2.exceptions.UndefinedError`: 5951cb0ef41Sopenharmony_ci 5961cb0ef41Sopenharmony_ci >>> foo = Undefined(name='foo') 5971cb0ef41Sopenharmony_ci >>> str(foo) 5981cb0ef41Sopenharmony_ci '' 5991cb0ef41Sopenharmony_ci >>> not foo 6001cb0ef41Sopenharmony_ci True 6011cb0ef41Sopenharmony_ci >>> foo + 42 6021cb0ef41Sopenharmony_ci Traceback (most recent call last): 6031cb0ef41Sopenharmony_ci ... 6041cb0ef41Sopenharmony_ci jinja2.exceptions.UndefinedError: 'foo' is undefined 6051cb0ef41Sopenharmony_ci """ 6061cb0ef41Sopenharmony_ci __slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name', 6071cb0ef41Sopenharmony_ci '_undefined_exception') 6081cb0ef41Sopenharmony_ci 6091cb0ef41Sopenharmony_ci def __init__(self, hint=None, obj=missing, name=None, exc=UndefinedError): 6101cb0ef41Sopenharmony_ci self._undefined_hint = hint 6111cb0ef41Sopenharmony_ci self._undefined_obj = obj 6121cb0ef41Sopenharmony_ci self._undefined_name = name 6131cb0ef41Sopenharmony_ci self._undefined_exception = exc 6141cb0ef41Sopenharmony_ci 6151cb0ef41Sopenharmony_ci @internalcode 6161cb0ef41Sopenharmony_ci def _fail_with_undefined_error(self, *args, **kwargs): 6171cb0ef41Sopenharmony_ci """Regular callback function for undefined objects that raises an 6181cb0ef41Sopenharmony_ci `jinja2.exceptions.UndefinedError` on call. 6191cb0ef41Sopenharmony_ci """ 6201cb0ef41Sopenharmony_ci if self._undefined_hint is None: 6211cb0ef41Sopenharmony_ci if self._undefined_obj is missing: 6221cb0ef41Sopenharmony_ci hint = '%r is undefined' % self._undefined_name 6231cb0ef41Sopenharmony_ci elif not isinstance(self._undefined_name, string_types): 6241cb0ef41Sopenharmony_ci hint = '%s has no element %r' % ( 6251cb0ef41Sopenharmony_ci object_type_repr(self._undefined_obj), 6261cb0ef41Sopenharmony_ci self._undefined_name 6271cb0ef41Sopenharmony_ci ) 6281cb0ef41Sopenharmony_ci else: 6291cb0ef41Sopenharmony_ci hint = '%r has no attribute %r' % ( 6301cb0ef41Sopenharmony_ci object_type_repr(self._undefined_obj), 6311cb0ef41Sopenharmony_ci self._undefined_name 6321cb0ef41Sopenharmony_ci ) 6331cb0ef41Sopenharmony_ci else: 6341cb0ef41Sopenharmony_ci hint = self._undefined_hint 6351cb0ef41Sopenharmony_ci raise self._undefined_exception(hint) 6361cb0ef41Sopenharmony_ci 6371cb0ef41Sopenharmony_ci @internalcode 6381cb0ef41Sopenharmony_ci def __getattr__(self, name): 6391cb0ef41Sopenharmony_ci if name[:2] == '__': 6401cb0ef41Sopenharmony_ci raise AttributeError(name) 6411cb0ef41Sopenharmony_ci return self._fail_with_undefined_error() 6421cb0ef41Sopenharmony_ci 6431cb0ef41Sopenharmony_ci __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \ 6441cb0ef41Sopenharmony_ci __truediv__ = __rtruediv__ = __floordiv__ = __rfloordiv__ = \ 6451cb0ef41Sopenharmony_ci __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \ 6461cb0ef41Sopenharmony_ci __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = __int__ = \ 6471cb0ef41Sopenharmony_ci __float__ = __complex__ = __pow__ = __rpow__ = __sub__ = \ 6481cb0ef41Sopenharmony_ci __rsub__ = _fail_with_undefined_error 6491cb0ef41Sopenharmony_ci 6501cb0ef41Sopenharmony_ci def __eq__(self, other): 6511cb0ef41Sopenharmony_ci return type(self) is type(other) 6521cb0ef41Sopenharmony_ci 6531cb0ef41Sopenharmony_ci def __ne__(self, other): 6541cb0ef41Sopenharmony_ci return not self.__eq__(other) 6551cb0ef41Sopenharmony_ci 6561cb0ef41Sopenharmony_ci def __hash__(self): 6571cb0ef41Sopenharmony_ci return id(type(self)) 6581cb0ef41Sopenharmony_ci 6591cb0ef41Sopenharmony_ci def __str__(self): 6601cb0ef41Sopenharmony_ci return u'' 6611cb0ef41Sopenharmony_ci 6621cb0ef41Sopenharmony_ci def __len__(self): 6631cb0ef41Sopenharmony_ci return 0 6641cb0ef41Sopenharmony_ci 6651cb0ef41Sopenharmony_ci def __iter__(self): 6661cb0ef41Sopenharmony_ci if 0: 6671cb0ef41Sopenharmony_ci yield None 6681cb0ef41Sopenharmony_ci 6691cb0ef41Sopenharmony_ci def __nonzero__(self): 6701cb0ef41Sopenharmony_ci return False 6711cb0ef41Sopenharmony_ci __bool__ = __nonzero__ 6721cb0ef41Sopenharmony_ci 6731cb0ef41Sopenharmony_ci def __repr__(self): 6741cb0ef41Sopenharmony_ci return 'Undefined' 6751cb0ef41Sopenharmony_ci 6761cb0ef41Sopenharmony_ci 6771cb0ef41Sopenharmony_cidef make_logging_undefined(logger=None, base=None): 6781cb0ef41Sopenharmony_ci """Given a logger object this returns a new undefined class that will 6791cb0ef41Sopenharmony_ci log certain failures. It will log iterations and printing. If no 6801cb0ef41Sopenharmony_ci logger is given a default logger is created. 6811cb0ef41Sopenharmony_ci 6821cb0ef41Sopenharmony_ci Example:: 6831cb0ef41Sopenharmony_ci 6841cb0ef41Sopenharmony_ci logger = logging.getLogger(__name__) 6851cb0ef41Sopenharmony_ci LoggingUndefined = make_logging_undefined( 6861cb0ef41Sopenharmony_ci logger=logger, 6871cb0ef41Sopenharmony_ci base=Undefined 6881cb0ef41Sopenharmony_ci ) 6891cb0ef41Sopenharmony_ci 6901cb0ef41Sopenharmony_ci .. versionadded:: 2.8 6911cb0ef41Sopenharmony_ci 6921cb0ef41Sopenharmony_ci :param logger: the logger to use. If not provided, a default logger 6931cb0ef41Sopenharmony_ci is created. 6941cb0ef41Sopenharmony_ci :param base: the base class to add logging functionality to. This 6951cb0ef41Sopenharmony_ci defaults to :class:`Undefined`. 6961cb0ef41Sopenharmony_ci """ 6971cb0ef41Sopenharmony_ci if logger is None: 6981cb0ef41Sopenharmony_ci import logging 6991cb0ef41Sopenharmony_ci logger = logging.getLogger(__name__) 7001cb0ef41Sopenharmony_ci logger.addHandler(logging.StreamHandler(sys.stderr)) 7011cb0ef41Sopenharmony_ci if base is None: 7021cb0ef41Sopenharmony_ci base = Undefined 7031cb0ef41Sopenharmony_ci 7041cb0ef41Sopenharmony_ci def _log_message(undef): 7051cb0ef41Sopenharmony_ci if undef._undefined_hint is None: 7061cb0ef41Sopenharmony_ci if undef._undefined_obj is missing: 7071cb0ef41Sopenharmony_ci hint = '%s is undefined' % undef._undefined_name 7081cb0ef41Sopenharmony_ci elif not isinstance(undef._undefined_name, string_types): 7091cb0ef41Sopenharmony_ci hint = '%s has no element %s' % ( 7101cb0ef41Sopenharmony_ci object_type_repr(undef._undefined_obj), 7111cb0ef41Sopenharmony_ci undef._undefined_name) 7121cb0ef41Sopenharmony_ci else: 7131cb0ef41Sopenharmony_ci hint = '%s has no attribute %s' % ( 7141cb0ef41Sopenharmony_ci object_type_repr(undef._undefined_obj), 7151cb0ef41Sopenharmony_ci undef._undefined_name) 7161cb0ef41Sopenharmony_ci else: 7171cb0ef41Sopenharmony_ci hint = undef._undefined_hint 7181cb0ef41Sopenharmony_ci logger.warning('Template variable warning: %s', hint) 7191cb0ef41Sopenharmony_ci 7201cb0ef41Sopenharmony_ci class LoggingUndefined(base): 7211cb0ef41Sopenharmony_ci 7221cb0ef41Sopenharmony_ci def _fail_with_undefined_error(self, *args, **kwargs): 7231cb0ef41Sopenharmony_ci try: 7241cb0ef41Sopenharmony_ci return base._fail_with_undefined_error(self, *args, **kwargs) 7251cb0ef41Sopenharmony_ci except self._undefined_exception as e: 7261cb0ef41Sopenharmony_ci logger.error('Template variable error: %s', str(e)) 7271cb0ef41Sopenharmony_ci raise e 7281cb0ef41Sopenharmony_ci 7291cb0ef41Sopenharmony_ci def __str__(self): 7301cb0ef41Sopenharmony_ci rv = base.__str__(self) 7311cb0ef41Sopenharmony_ci _log_message(self) 7321cb0ef41Sopenharmony_ci return rv 7331cb0ef41Sopenharmony_ci 7341cb0ef41Sopenharmony_ci def __iter__(self): 7351cb0ef41Sopenharmony_ci rv = base.__iter__(self) 7361cb0ef41Sopenharmony_ci _log_message(self) 7371cb0ef41Sopenharmony_ci return rv 7381cb0ef41Sopenharmony_ci 7391cb0ef41Sopenharmony_ci if PY2: 7401cb0ef41Sopenharmony_ci def __nonzero__(self): 7411cb0ef41Sopenharmony_ci rv = base.__nonzero__(self) 7421cb0ef41Sopenharmony_ci _log_message(self) 7431cb0ef41Sopenharmony_ci return rv 7441cb0ef41Sopenharmony_ci 7451cb0ef41Sopenharmony_ci def __unicode__(self): 7461cb0ef41Sopenharmony_ci rv = base.__unicode__(self) 7471cb0ef41Sopenharmony_ci _log_message(self) 7481cb0ef41Sopenharmony_ci return rv 7491cb0ef41Sopenharmony_ci else: 7501cb0ef41Sopenharmony_ci def __bool__(self): 7511cb0ef41Sopenharmony_ci rv = base.__bool__(self) 7521cb0ef41Sopenharmony_ci _log_message(self) 7531cb0ef41Sopenharmony_ci return rv 7541cb0ef41Sopenharmony_ci 7551cb0ef41Sopenharmony_ci return LoggingUndefined 7561cb0ef41Sopenharmony_ci 7571cb0ef41Sopenharmony_ci 7581cb0ef41Sopenharmony_ci@implements_to_string 7591cb0ef41Sopenharmony_ciclass DebugUndefined(Undefined): 7601cb0ef41Sopenharmony_ci """An undefined that returns the debug info when printed. 7611cb0ef41Sopenharmony_ci 7621cb0ef41Sopenharmony_ci >>> foo = DebugUndefined(name='foo') 7631cb0ef41Sopenharmony_ci >>> str(foo) 7641cb0ef41Sopenharmony_ci '{{ foo }}' 7651cb0ef41Sopenharmony_ci >>> not foo 7661cb0ef41Sopenharmony_ci True 7671cb0ef41Sopenharmony_ci >>> foo + 42 7681cb0ef41Sopenharmony_ci Traceback (most recent call last): 7691cb0ef41Sopenharmony_ci ... 7701cb0ef41Sopenharmony_ci jinja2.exceptions.UndefinedError: 'foo' is undefined 7711cb0ef41Sopenharmony_ci """ 7721cb0ef41Sopenharmony_ci __slots__ = () 7731cb0ef41Sopenharmony_ci 7741cb0ef41Sopenharmony_ci def __str__(self): 7751cb0ef41Sopenharmony_ci if self._undefined_hint is None: 7761cb0ef41Sopenharmony_ci if self._undefined_obj is missing: 7771cb0ef41Sopenharmony_ci return u'{{ %s }}' % self._undefined_name 7781cb0ef41Sopenharmony_ci return '{{ no such element: %s[%r] }}' % ( 7791cb0ef41Sopenharmony_ci object_type_repr(self._undefined_obj), 7801cb0ef41Sopenharmony_ci self._undefined_name 7811cb0ef41Sopenharmony_ci ) 7821cb0ef41Sopenharmony_ci return u'{{ undefined value printed: %s }}' % self._undefined_hint 7831cb0ef41Sopenharmony_ci 7841cb0ef41Sopenharmony_ci 7851cb0ef41Sopenharmony_ci@implements_to_string 7861cb0ef41Sopenharmony_ciclass StrictUndefined(Undefined): 7871cb0ef41Sopenharmony_ci """An undefined that barks on print and iteration as well as boolean 7881cb0ef41Sopenharmony_ci tests and all kinds of comparisons. In other words: you can do nothing 7891cb0ef41Sopenharmony_ci with it except checking if it's defined using the `defined` test. 7901cb0ef41Sopenharmony_ci 7911cb0ef41Sopenharmony_ci >>> foo = StrictUndefined(name='foo') 7921cb0ef41Sopenharmony_ci >>> str(foo) 7931cb0ef41Sopenharmony_ci Traceback (most recent call last): 7941cb0ef41Sopenharmony_ci ... 7951cb0ef41Sopenharmony_ci jinja2.exceptions.UndefinedError: 'foo' is undefined 7961cb0ef41Sopenharmony_ci >>> not foo 7971cb0ef41Sopenharmony_ci Traceback (most recent call last): 7981cb0ef41Sopenharmony_ci ... 7991cb0ef41Sopenharmony_ci jinja2.exceptions.UndefinedError: 'foo' is undefined 8001cb0ef41Sopenharmony_ci >>> foo + 42 8011cb0ef41Sopenharmony_ci Traceback (most recent call last): 8021cb0ef41Sopenharmony_ci ... 8031cb0ef41Sopenharmony_ci jinja2.exceptions.UndefinedError: 'foo' is undefined 8041cb0ef41Sopenharmony_ci """ 8051cb0ef41Sopenharmony_ci __slots__ = () 8061cb0ef41Sopenharmony_ci __iter__ = __str__ = __len__ = __nonzero__ = __eq__ = \ 8071cb0ef41Sopenharmony_ci __ne__ = __bool__ = __hash__ = \ 8081cb0ef41Sopenharmony_ci Undefined._fail_with_undefined_error 8091cb0ef41Sopenharmony_ci 8101cb0ef41Sopenharmony_ci 8111cb0ef41Sopenharmony_ci# remove remaining slots attributes, after the metaclass did the magic they 8121cb0ef41Sopenharmony_ci# are unneeded and irritating as they contain wrong data for the subclasses. 8131cb0ef41Sopenharmony_cidel Undefined.__slots__, DebugUndefined.__slots__, StrictUndefined.__slots__ 814