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