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