xref: /aosp_15_r20/external/libchrome/third_party/jinja2/utils.py (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker# -*- coding: utf-8 -*-
2*635a8641SAndroid Build Coastguard Worker"""
3*635a8641SAndroid Build Coastguard Worker    jinja2.utils
4*635a8641SAndroid Build Coastguard Worker    ~~~~~~~~~~~~
5*635a8641SAndroid Build Coastguard Worker
6*635a8641SAndroid Build Coastguard Worker    Utility functions.
7*635a8641SAndroid Build Coastguard Worker
8*635a8641SAndroid Build Coastguard Worker    :copyright: (c) 2017 by the Jinja Team.
9*635a8641SAndroid Build Coastguard Worker    :license: BSD, see LICENSE for more details.
10*635a8641SAndroid Build Coastguard Worker"""
11*635a8641SAndroid Build Coastguard Workerimport re
12*635a8641SAndroid Build Coastguard Workerimport json
13*635a8641SAndroid Build Coastguard Workerimport errno
14*635a8641SAndroid Build Coastguard Workerfrom collections import deque
15*635a8641SAndroid Build Coastguard Workerfrom threading import Lock
16*635a8641SAndroid Build Coastguard Workerfrom jinja2._compat import text_type, string_types, implements_iterator, \
17*635a8641SAndroid Build Coastguard Worker     url_quote
18*635a8641SAndroid Build Coastguard Worker
19*635a8641SAndroid Build Coastguard Worker
20*635a8641SAndroid Build Coastguard Worker_word_split_re = re.compile(r'(\s+)')
21*635a8641SAndroid Build Coastguard Worker_punctuation_re = re.compile(
22*635a8641SAndroid Build Coastguard Worker    '^(?P<lead>(?:%s)*)(?P<middle>.*?)(?P<trail>(?:%s)*)$' % (
23*635a8641SAndroid Build Coastguard Worker        '|'.join(map(re.escape, ('(', '<', '&lt;'))),
24*635a8641SAndroid Build Coastguard Worker        '|'.join(map(re.escape, ('.', ',', ')', '>', '\n', '&gt;')))
25*635a8641SAndroid Build Coastguard Worker    )
26*635a8641SAndroid Build Coastguard Worker)
27*635a8641SAndroid Build Coastguard Worker_simple_email_re = re.compile(r'^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$')
28*635a8641SAndroid Build Coastguard Worker_striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
29*635a8641SAndroid Build Coastguard Worker_entity_re = re.compile(r'&([^;]+);')
30*635a8641SAndroid Build Coastguard Worker_letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
31*635a8641SAndroid Build Coastguard Worker_digits = '0123456789'
32*635a8641SAndroid Build Coastguard Worker
33*635a8641SAndroid Build Coastguard Worker# special singleton representing missing values for the runtime
34*635a8641SAndroid Build Coastguard Workermissing = type('MissingType', (), {'__repr__': lambda x: 'missing'})()
35*635a8641SAndroid Build Coastguard Worker
36*635a8641SAndroid Build Coastguard Worker# internal code
37*635a8641SAndroid Build Coastguard Workerinternal_code = set()
38*635a8641SAndroid Build Coastguard Worker
39*635a8641SAndroid Build Coastguard Workerconcat = u''.join
40*635a8641SAndroid Build Coastguard Worker
41*635a8641SAndroid Build Coastguard Worker_slash_escape = '\\/' not in json.dumps('/')
42*635a8641SAndroid Build Coastguard Worker
43*635a8641SAndroid Build Coastguard Worker
44*635a8641SAndroid Build Coastguard Workerdef contextfunction(f):
45*635a8641SAndroid Build Coastguard Worker    """This decorator can be used to mark a function or method context callable.
46*635a8641SAndroid Build Coastguard Worker    A context callable is passed the active :class:`Context` as first argument when
47*635a8641SAndroid Build Coastguard Worker    called from the template.  This is useful if a function wants to get access
48*635a8641SAndroid Build Coastguard Worker    to the context or functions provided on the context object.  For example
49*635a8641SAndroid Build Coastguard Worker    a function that returns a sorted list of template variables the current
50*635a8641SAndroid Build Coastguard Worker    template exports could look like this::
51*635a8641SAndroid Build Coastguard Worker
52*635a8641SAndroid Build Coastguard Worker        @contextfunction
53*635a8641SAndroid Build Coastguard Worker        def get_exported_names(context):
54*635a8641SAndroid Build Coastguard Worker            return sorted(context.exported_vars)
55*635a8641SAndroid Build Coastguard Worker    """
56*635a8641SAndroid Build Coastguard Worker    f.contextfunction = True
57*635a8641SAndroid Build Coastguard Worker    return f
58*635a8641SAndroid Build Coastguard Worker
59*635a8641SAndroid Build Coastguard Worker
60*635a8641SAndroid Build Coastguard Workerdef evalcontextfunction(f):
61*635a8641SAndroid Build Coastguard Worker    """This decorator can be used to mark a function or method as an eval
62*635a8641SAndroid Build Coastguard Worker    context callable.  This is similar to the :func:`contextfunction`
63*635a8641SAndroid Build Coastguard Worker    but instead of passing the context, an evaluation context object is
64*635a8641SAndroid Build Coastguard Worker    passed.  For more information about the eval context, see
65*635a8641SAndroid Build Coastguard Worker    :ref:`eval-context`.
66*635a8641SAndroid Build Coastguard Worker
67*635a8641SAndroid Build Coastguard Worker    .. versionadded:: 2.4
68*635a8641SAndroid Build Coastguard Worker    """
69*635a8641SAndroid Build Coastguard Worker    f.evalcontextfunction = True
70*635a8641SAndroid Build Coastguard Worker    return f
71*635a8641SAndroid Build Coastguard Worker
72*635a8641SAndroid Build Coastguard Worker
73*635a8641SAndroid Build Coastguard Workerdef environmentfunction(f):
74*635a8641SAndroid Build Coastguard Worker    """This decorator can be used to mark a function or method as environment
75*635a8641SAndroid Build Coastguard Worker    callable.  This decorator works exactly like the :func:`contextfunction`
76*635a8641SAndroid Build Coastguard Worker    decorator just that the first argument is the active :class:`Environment`
77*635a8641SAndroid Build Coastguard Worker    and not context.
78*635a8641SAndroid Build Coastguard Worker    """
79*635a8641SAndroid Build Coastguard Worker    f.environmentfunction = True
80*635a8641SAndroid Build Coastguard Worker    return f
81*635a8641SAndroid Build Coastguard Worker
82*635a8641SAndroid Build Coastguard Worker
83*635a8641SAndroid Build Coastguard Workerdef internalcode(f):
84*635a8641SAndroid Build Coastguard Worker    """Marks the function as internally used"""
85*635a8641SAndroid Build Coastguard Worker    internal_code.add(f.__code__)
86*635a8641SAndroid Build Coastguard Worker    return f
87*635a8641SAndroid Build Coastguard Worker
88*635a8641SAndroid Build Coastguard Worker
89*635a8641SAndroid Build Coastguard Workerdef is_undefined(obj):
90*635a8641SAndroid Build Coastguard Worker    """Check if the object passed is undefined.  This does nothing more than
91*635a8641SAndroid Build Coastguard Worker    performing an instance check against :class:`Undefined` but looks nicer.
92*635a8641SAndroid Build Coastguard Worker    This can be used for custom filters or tests that want to react to
93*635a8641SAndroid Build Coastguard Worker    undefined variables.  For example a custom default filter can look like
94*635a8641SAndroid Build Coastguard Worker    this::
95*635a8641SAndroid Build Coastguard Worker
96*635a8641SAndroid Build Coastguard Worker        def default(var, default=''):
97*635a8641SAndroid Build Coastguard Worker            if is_undefined(var):
98*635a8641SAndroid Build Coastguard Worker                return default
99*635a8641SAndroid Build Coastguard Worker            return var
100*635a8641SAndroid Build Coastguard Worker    """
101*635a8641SAndroid Build Coastguard Worker    from jinja2.runtime import Undefined
102*635a8641SAndroid Build Coastguard Worker    return isinstance(obj, Undefined)
103*635a8641SAndroid Build Coastguard Worker
104*635a8641SAndroid Build Coastguard Worker
105*635a8641SAndroid Build Coastguard Workerdef consume(iterable):
106*635a8641SAndroid Build Coastguard Worker    """Consumes an iterable without doing anything with it."""
107*635a8641SAndroid Build Coastguard Worker    for event in iterable:
108*635a8641SAndroid Build Coastguard Worker        pass
109*635a8641SAndroid Build Coastguard Worker
110*635a8641SAndroid Build Coastguard Worker
111*635a8641SAndroid Build Coastguard Workerdef clear_caches():
112*635a8641SAndroid Build Coastguard Worker    """Jinja2 keeps internal caches for environments and lexers.  These are
113*635a8641SAndroid Build Coastguard Worker    used so that Jinja2 doesn't have to recreate environments and lexers all
114*635a8641SAndroid Build Coastguard Worker    the time.  Normally you don't have to care about that but if you are
115*635a8641SAndroid Build Coastguard Worker    measuring memory consumption you may want to clean the caches.
116*635a8641SAndroid Build Coastguard Worker    """
117*635a8641SAndroid Build Coastguard Worker    from jinja2.environment import _spontaneous_environments
118*635a8641SAndroid Build Coastguard Worker    from jinja2.lexer import _lexer_cache
119*635a8641SAndroid Build Coastguard Worker    _spontaneous_environments.clear()
120*635a8641SAndroid Build Coastguard Worker    _lexer_cache.clear()
121*635a8641SAndroid Build Coastguard Worker
122*635a8641SAndroid Build Coastguard Worker
123*635a8641SAndroid Build Coastguard Workerdef import_string(import_name, silent=False):
124*635a8641SAndroid Build Coastguard Worker    """Imports an object based on a string.  This is useful if you want to
125*635a8641SAndroid Build Coastguard Worker    use import paths as endpoints or something similar.  An import path can
126*635a8641SAndroid Build Coastguard Worker    be specified either in dotted notation (``xml.sax.saxutils.escape``)
127*635a8641SAndroid Build Coastguard Worker    or with a colon as object delimiter (``xml.sax.saxutils:escape``).
128*635a8641SAndroid Build Coastguard Worker
129*635a8641SAndroid Build Coastguard Worker    If the `silent` is True the return value will be `None` if the import
130*635a8641SAndroid Build Coastguard Worker    fails.
131*635a8641SAndroid Build Coastguard Worker
132*635a8641SAndroid Build Coastguard Worker    :return: imported object
133*635a8641SAndroid Build Coastguard Worker    """
134*635a8641SAndroid Build Coastguard Worker    try:
135*635a8641SAndroid Build Coastguard Worker        if ':' in import_name:
136*635a8641SAndroid Build Coastguard Worker            module, obj = import_name.split(':', 1)
137*635a8641SAndroid Build Coastguard Worker        elif '.' in import_name:
138*635a8641SAndroid Build Coastguard Worker            items = import_name.split('.')
139*635a8641SAndroid Build Coastguard Worker            module = '.'.join(items[:-1])
140*635a8641SAndroid Build Coastguard Worker            obj = items[-1]
141*635a8641SAndroid Build Coastguard Worker        else:
142*635a8641SAndroid Build Coastguard Worker            return __import__(import_name)
143*635a8641SAndroid Build Coastguard Worker        return getattr(__import__(module, None, None, [obj]), obj)
144*635a8641SAndroid Build Coastguard Worker    except (ImportError, AttributeError):
145*635a8641SAndroid Build Coastguard Worker        if not silent:
146*635a8641SAndroid Build Coastguard Worker            raise
147*635a8641SAndroid Build Coastguard Worker
148*635a8641SAndroid Build Coastguard Worker
149*635a8641SAndroid Build Coastguard Workerdef open_if_exists(filename, mode='rb'):
150*635a8641SAndroid Build Coastguard Worker    """Returns a file descriptor for the filename if that file exists,
151*635a8641SAndroid Build Coastguard Worker    otherwise `None`.
152*635a8641SAndroid Build Coastguard Worker    """
153*635a8641SAndroid Build Coastguard Worker    try:
154*635a8641SAndroid Build Coastguard Worker        return open(filename, mode)
155*635a8641SAndroid Build Coastguard Worker    except IOError as e:
156*635a8641SAndroid Build Coastguard Worker        if e.errno not in (errno.ENOENT, errno.EISDIR, errno.EINVAL):
157*635a8641SAndroid Build Coastguard Worker            raise
158*635a8641SAndroid Build Coastguard Worker
159*635a8641SAndroid Build Coastguard Worker
160*635a8641SAndroid Build Coastguard Workerdef object_type_repr(obj):
161*635a8641SAndroid Build Coastguard Worker    """Returns the name of the object's type.  For some recognized
162*635a8641SAndroid Build Coastguard Worker    singletons the name of the object is returned instead. (For
163*635a8641SAndroid Build Coastguard Worker    example for `None` and `Ellipsis`).
164*635a8641SAndroid Build Coastguard Worker    """
165*635a8641SAndroid Build Coastguard Worker    if obj is None:
166*635a8641SAndroid Build Coastguard Worker        return 'None'
167*635a8641SAndroid Build Coastguard Worker    elif obj is Ellipsis:
168*635a8641SAndroid Build Coastguard Worker        return 'Ellipsis'
169*635a8641SAndroid Build Coastguard Worker    # __builtin__ in 2.x, builtins in 3.x
170*635a8641SAndroid Build Coastguard Worker    if obj.__class__.__module__ in ('__builtin__', 'builtins'):
171*635a8641SAndroid Build Coastguard Worker        name = obj.__class__.__name__
172*635a8641SAndroid Build Coastguard Worker    else:
173*635a8641SAndroid Build Coastguard Worker        name = obj.__class__.__module__ + '.' + obj.__class__.__name__
174*635a8641SAndroid Build Coastguard Worker    return '%s object' % name
175*635a8641SAndroid Build Coastguard Worker
176*635a8641SAndroid Build Coastguard Worker
177*635a8641SAndroid Build Coastguard Workerdef pformat(obj, verbose=False):
178*635a8641SAndroid Build Coastguard Worker    """Prettyprint an object.  Either use the `pretty` library or the
179*635a8641SAndroid Build Coastguard Worker    builtin `pprint`.
180*635a8641SAndroid Build Coastguard Worker    """
181*635a8641SAndroid Build Coastguard Worker    try:
182*635a8641SAndroid Build Coastguard Worker        from pretty import pretty
183*635a8641SAndroid Build Coastguard Worker        return pretty(obj, verbose=verbose)
184*635a8641SAndroid Build Coastguard Worker    except ImportError:
185*635a8641SAndroid Build Coastguard Worker        from pprint import pformat
186*635a8641SAndroid Build Coastguard Worker        return pformat(obj)
187*635a8641SAndroid Build Coastguard Worker
188*635a8641SAndroid Build Coastguard Worker
189*635a8641SAndroid Build Coastguard Workerdef urlize(text, trim_url_limit=None, rel=None, target=None):
190*635a8641SAndroid Build Coastguard Worker    """Converts any URLs in text into clickable links. Works on http://,
191*635a8641SAndroid Build Coastguard Worker    https:// and www. links. Links can have trailing punctuation (periods,
192*635a8641SAndroid Build Coastguard Worker    commas, close-parens) and leading punctuation (opening parens) and
193*635a8641SAndroid Build Coastguard Worker    it'll still do the right thing.
194*635a8641SAndroid Build Coastguard Worker
195*635a8641SAndroid Build Coastguard Worker    If trim_url_limit is not None, the URLs in link text will be limited
196*635a8641SAndroid Build Coastguard Worker    to trim_url_limit characters.
197*635a8641SAndroid Build Coastguard Worker
198*635a8641SAndroid Build Coastguard Worker    If nofollow is True, the URLs in link text will get a rel="nofollow"
199*635a8641SAndroid Build Coastguard Worker    attribute.
200*635a8641SAndroid Build Coastguard Worker
201*635a8641SAndroid Build Coastguard Worker    If target is not None, a target attribute will be added to the link.
202*635a8641SAndroid Build Coastguard Worker    """
203*635a8641SAndroid Build Coastguard Worker    trim_url = lambda x, limit=trim_url_limit: limit is not None \
204*635a8641SAndroid Build Coastguard Worker                         and (x[:limit] + (len(x) >=limit and '...'
205*635a8641SAndroid Build Coastguard Worker                         or '')) or x
206*635a8641SAndroid Build Coastguard Worker    words = _word_split_re.split(text_type(escape(text)))
207*635a8641SAndroid Build Coastguard Worker    rel_attr = rel and ' rel="%s"' % text_type(escape(rel)) or ''
208*635a8641SAndroid Build Coastguard Worker    target_attr = target and ' target="%s"' % escape(target) or ''
209*635a8641SAndroid Build Coastguard Worker
210*635a8641SAndroid Build Coastguard Worker    for i, word in enumerate(words):
211*635a8641SAndroid Build Coastguard Worker        match = _punctuation_re.match(word)
212*635a8641SAndroid Build Coastguard Worker        if match:
213*635a8641SAndroid Build Coastguard Worker            lead, middle, trail = match.groups()
214*635a8641SAndroid Build Coastguard Worker            if middle.startswith('www.') or (
215*635a8641SAndroid Build Coastguard Worker                '@' not in middle and
216*635a8641SAndroid Build Coastguard Worker                not middle.startswith('http://') and
217*635a8641SAndroid Build Coastguard Worker                not middle.startswith('https://') and
218*635a8641SAndroid Build Coastguard Worker                len(middle) > 0 and
219*635a8641SAndroid Build Coastguard Worker                middle[0] in _letters + _digits and (
220*635a8641SAndroid Build Coastguard Worker                    middle.endswith('.org') or
221*635a8641SAndroid Build Coastguard Worker                    middle.endswith('.net') or
222*635a8641SAndroid Build Coastguard Worker                    middle.endswith('.com')
223*635a8641SAndroid Build Coastguard Worker                )):
224*635a8641SAndroid Build Coastguard Worker                middle = '<a href="http://%s"%s%s>%s</a>' % (middle,
225*635a8641SAndroid Build Coastguard Worker                    rel_attr, target_attr, trim_url(middle))
226*635a8641SAndroid Build Coastguard Worker            if middle.startswith('http://') or \
227*635a8641SAndroid Build Coastguard Worker               middle.startswith('https://'):
228*635a8641SAndroid Build Coastguard Worker                middle = '<a href="%s"%s%s>%s</a>' % (middle,
229*635a8641SAndroid Build Coastguard Worker                    rel_attr, target_attr, trim_url(middle))
230*635a8641SAndroid Build Coastguard Worker            if '@' in middle and not middle.startswith('www.') and \
231*635a8641SAndroid Build Coastguard Worker               not ':' in middle and _simple_email_re.match(middle):
232*635a8641SAndroid Build Coastguard Worker                middle = '<a href="mailto:%s">%s</a>' % (middle, middle)
233*635a8641SAndroid Build Coastguard Worker            if lead + middle + trail != word:
234*635a8641SAndroid Build Coastguard Worker                words[i] = lead + middle + trail
235*635a8641SAndroid Build Coastguard Worker    return u''.join(words)
236*635a8641SAndroid Build Coastguard Worker
237*635a8641SAndroid Build Coastguard Worker
238*635a8641SAndroid Build Coastguard Workerdef generate_lorem_ipsum(n=5, html=True, min=20, max=100):
239*635a8641SAndroid Build Coastguard Worker    """Generate some lorem ipsum for the template."""
240*635a8641SAndroid Build Coastguard Worker    from jinja2.constants import LOREM_IPSUM_WORDS
241*635a8641SAndroid Build Coastguard Worker    from random import choice, randrange
242*635a8641SAndroid Build Coastguard Worker    words = LOREM_IPSUM_WORDS.split()
243*635a8641SAndroid Build Coastguard Worker    result = []
244*635a8641SAndroid Build Coastguard Worker
245*635a8641SAndroid Build Coastguard Worker    for _ in range(n):
246*635a8641SAndroid Build Coastguard Worker        next_capitalized = True
247*635a8641SAndroid Build Coastguard Worker        last_comma = last_fullstop = 0
248*635a8641SAndroid Build Coastguard Worker        word = None
249*635a8641SAndroid Build Coastguard Worker        last = None
250*635a8641SAndroid Build Coastguard Worker        p = []
251*635a8641SAndroid Build Coastguard Worker
252*635a8641SAndroid Build Coastguard Worker        # each paragraph contains out of 20 to 100 words.
253*635a8641SAndroid Build Coastguard Worker        for idx, _ in enumerate(range(randrange(min, max))):
254*635a8641SAndroid Build Coastguard Worker            while True:
255*635a8641SAndroid Build Coastguard Worker                word = choice(words)
256*635a8641SAndroid Build Coastguard Worker                if word != last:
257*635a8641SAndroid Build Coastguard Worker                    last = word
258*635a8641SAndroid Build Coastguard Worker                    break
259*635a8641SAndroid Build Coastguard Worker            if next_capitalized:
260*635a8641SAndroid Build Coastguard Worker                word = word.capitalize()
261*635a8641SAndroid Build Coastguard Worker                next_capitalized = False
262*635a8641SAndroid Build Coastguard Worker            # add commas
263*635a8641SAndroid Build Coastguard Worker            if idx - randrange(3, 8) > last_comma:
264*635a8641SAndroid Build Coastguard Worker                last_comma = idx
265*635a8641SAndroid Build Coastguard Worker                last_fullstop += 2
266*635a8641SAndroid Build Coastguard Worker                word += ','
267*635a8641SAndroid Build Coastguard Worker            # add end of sentences
268*635a8641SAndroid Build Coastguard Worker            if idx - randrange(10, 20) > last_fullstop:
269*635a8641SAndroid Build Coastguard Worker                last_comma = last_fullstop = idx
270*635a8641SAndroid Build Coastguard Worker                word += '.'
271*635a8641SAndroid Build Coastguard Worker                next_capitalized = True
272*635a8641SAndroid Build Coastguard Worker            p.append(word)
273*635a8641SAndroid Build Coastguard Worker
274*635a8641SAndroid Build Coastguard Worker        # ensure that the paragraph ends with a dot.
275*635a8641SAndroid Build Coastguard Worker        p = u' '.join(p)
276*635a8641SAndroid Build Coastguard Worker        if p.endswith(','):
277*635a8641SAndroid Build Coastguard Worker            p = p[:-1] + '.'
278*635a8641SAndroid Build Coastguard Worker        elif not p.endswith('.'):
279*635a8641SAndroid Build Coastguard Worker            p += '.'
280*635a8641SAndroid Build Coastguard Worker        result.append(p)
281*635a8641SAndroid Build Coastguard Worker
282*635a8641SAndroid Build Coastguard Worker    if not html:
283*635a8641SAndroid Build Coastguard Worker        return u'\n\n'.join(result)
284*635a8641SAndroid Build Coastguard Worker    return Markup(u'\n'.join(u'<p>%s</p>' % escape(x) for x in result))
285*635a8641SAndroid Build Coastguard Worker
286*635a8641SAndroid Build Coastguard Worker
287*635a8641SAndroid Build Coastguard Workerdef unicode_urlencode(obj, charset='utf-8', for_qs=False):
288*635a8641SAndroid Build Coastguard Worker    """URL escapes a single bytestring or unicode string with the
289*635a8641SAndroid Build Coastguard Worker    given charset if applicable to URL safe quoting under all rules
290*635a8641SAndroid Build Coastguard Worker    that need to be considered under all supported Python versions.
291*635a8641SAndroid Build Coastguard Worker
292*635a8641SAndroid Build Coastguard Worker    If non strings are provided they are converted to their unicode
293*635a8641SAndroid Build Coastguard Worker    representation first.
294*635a8641SAndroid Build Coastguard Worker    """
295*635a8641SAndroid Build Coastguard Worker    if not isinstance(obj, string_types):
296*635a8641SAndroid Build Coastguard Worker        obj = text_type(obj)
297*635a8641SAndroid Build Coastguard Worker    if isinstance(obj, text_type):
298*635a8641SAndroid Build Coastguard Worker        obj = obj.encode(charset)
299*635a8641SAndroid Build Coastguard Worker    safe = not for_qs and b'/' or b''
300*635a8641SAndroid Build Coastguard Worker    rv = text_type(url_quote(obj, safe))
301*635a8641SAndroid Build Coastguard Worker    if for_qs:
302*635a8641SAndroid Build Coastguard Worker        rv = rv.replace('%20', '+')
303*635a8641SAndroid Build Coastguard Worker    return rv
304*635a8641SAndroid Build Coastguard Worker
305*635a8641SAndroid Build Coastguard Worker
306*635a8641SAndroid Build Coastguard Workerclass LRUCache(object):
307*635a8641SAndroid Build Coastguard Worker    """A simple LRU Cache implementation."""
308*635a8641SAndroid Build Coastguard Worker
309*635a8641SAndroid Build Coastguard Worker    # this is fast for small capacities (something below 1000) but doesn't
310*635a8641SAndroid Build Coastguard Worker    # scale.  But as long as it's only used as storage for templates this
311*635a8641SAndroid Build Coastguard Worker    # won't do any harm.
312*635a8641SAndroid Build Coastguard Worker
313*635a8641SAndroid Build Coastguard Worker    def __init__(self, capacity):
314*635a8641SAndroid Build Coastguard Worker        self.capacity = capacity
315*635a8641SAndroid Build Coastguard Worker        self._mapping = {}
316*635a8641SAndroid Build Coastguard Worker        self._queue = deque()
317*635a8641SAndroid Build Coastguard Worker        self._postinit()
318*635a8641SAndroid Build Coastguard Worker
319*635a8641SAndroid Build Coastguard Worker    def _postinit(self):
320*635a8641SAndroid Build Coastguard Worker        # alias all queue methods for faster lookup
321*635a8641SAndroid Build Coastguard Worker        self._popleft = self._queue.popleft
322*635a8641SAndroid Build Coastguard Worker        self._pop = self._queue.pop
323*635a8641SAndroid Build Coastguard Worker        self._remove = self._queue.remove
324*635a8641SAndroid Build Coastguard Worker        self._wlock = Lock()
325*635a8641SAndroid Build Coastguard Worker        self._append = self._queue.append
326*635a8641SAndroid Build Coastguard Worker
327*635a8641SAndroid Build Coastguard Worker    def __getstate__(self):
328*635a8641SAndroid Build Coastguard Worker        return {
329*635a8641SAndroid Build Coastguard Worker            'capacity':     self.capacity,
330*635a8641SAndroid Build Coastguard Worker            '_mapping':     self._mapping,
331*635a8641SAndroid Build Coastguard Worker            '_queue':       self._queue
332*635a8641SAndroid Build Coastguard Worker        }
333*635a8641SAndroid Build Coastguard Worker
334*635a8641SAndroid Build Coastguard Worker    def __setstate__(self, d):
335*635a8641SAndroid Build Coastguard Worker        self.__dict__.update(d)
336*635a8641SAndroid Build Coastguard Worker        self._postinit()
337*635a8641SAndroid Build Coastguard Worker
338*635a8641SAndroid Build Coastguard Worker    def __getnewargs__(self):
339*635a8641SAndroid Build Coastguard Worker        return (self.capacity,)
340*635a8641SAndroid Build Coastguard Worker
341*635a8641SAndroid Build Coastguard Worker    def copy(self):
342*635a8641SAndroid Build Coastguard Worker        """Return a shallow copy of the instance."""
343*635a8641SAndroid Build Coastguard Worker        rv = self.__class__(self.capacity)
344*635a8641SAndroid Build Coastguard Worker        rv._mapping.update(self._mapping)
345*635a8641SAndroid Build Coastguard Worker        rv._queue = deque(self._queue)
346*635a8641SAndroid Build Coastguard Worker        return rv
347*635a8641SAndroid Build Coastguard Worker
348*635a8641SAndroid Build Coastguard Worker    def get(self, key, default=None):
349*635a8641SAndroid Build Coastguard Worker        """Return an item from the cache dict or `default`"""
350*635a8641SAndroid Build Coastguard Worker        try:
351*635a8641SAndroid Build Coastguard Worker            return self[key]
352*635a8641SAndroid Build Coastguard Worker        except KeyError:
353*635a8641SAndroid Build Coastguard Worker            return default
354*635a8641SAndroid Build Coastguard Worker
355*635a8641SAndroid Build Coastguard Worker    def setdefault(self, key, default=None):
356*635a8641SAndroid Build Coastguard Worker        """Set `default` if the key is not in the cache otherwise
357*635a8641SAndroid Build Coastguard Worker        leave unchanged. Return the value of this key.
358*635a8641SAndroid Build Coastguard Worker        """
359*635a8641SAndroid Build Coastguard Worker        self._wlock.acquire()
360*635a8641SAndroid Build Coastguard Worker        try:
361*635a8641SAndroid Build Coastguard Worker            try:
362*635a8641SAndroid Build Coastguard Worker                return self[key]
363*635a8641SAndroid Build Coastguard Worker            except KeyError:
364*635a8641SAndroid Build Coastguard Worker                self[key] = default
365*635a8641SAndroid Build Coastguard Worker                return default
366*635a8641SAndroid Build Coastguard Worker        finally:
367*635a8641SAndroid Build Coastguard Worker            self._wlock.release()
368*635a8641SAndroid Build Coastguard Worker
369*635a8641SAndroid Build Coastguard Worker    def clear(self):
370*635a8641SAndroid Build Coastguard Worker        """Clear the cache."""
371*635a8641SAndroid Build Coastguard Worker        self._wlock.acquire()
372*635a8641SAndroid Build Coastguard Worker        try:
373*635a8641SAndroid Build Coastguard Worker            self._mapping.clear()
374*635a8641SAndroid Build Coastguard Worker            self._queue.clear()
375*635a8641SAndroid Build Coastguard Worker        finally:
376*635a8641SAndroid Build Coastguard Worker            self._wlock.release()
377*635a8641SAndroid Build Coastguard Worker
378*635a8641SAndroid Build Coastguard Worker    def __contains__(self, key):
379*635a8641SAndroid Build Coastguard Worker        """Check if a key exists in this cache."""
380*635a8641SAndroid Build Coastguard Worker        return key in self._mapping
381*635a8641SAndroid Build Coastguard Worker
382*635a8641SAndroid Build Coastguard Worker    def __len__(self):
383*635a8641SAndroid Build Coastguard Worker        """Return the current size of the cache."""
384*635a8641SAndroid Build Coastguard Worker        return len(self._mapping)
385*635a8641SAndroid Build Coastguard Worker
386*635a8641SAndroid Build Coastguard Worker    def __repr__(self):
387*635a8641SAndroid Build Coastguard Worker        return '<%s %r>' % (
388*635a8641SAndroid Build Coastguard Worker            self.__class__.__name__,
389*635a8641SAndroid Build Coastguard Worker            self._mapping
390*635a8641SAndroid Build Coastguard Worker        )
391*635a8641SAndroid Build Coastguard Worker
392*635a8641SAndroid Build Coastguard Worker    def __getitem__(self, key):
393*635a8641SAndroid Build Coastguard Worker        """Get an item from the cache. Moves the item up so that it has the
394*635a8641SAndroid Build Coastguard Worker        highest priority then.
395*635a8641SAndroid Build Coastguard Worker
396*635a8641SAndroid Build Coastguard Worker        Raise a `KeyError` if it does not exist.
397*635a8641SAndroid Build Coastguard Worker        """
398*635a8641SAndroid Build Coastguard Worker        self._wlock.acquire()
399*635a8641SAndroid Build Coastguard Worker        try:
400*635a8641SAndroid Build Coastguard Worker            rv = self._mapping[key]
401*635a8641SAndroid Build Coastguard Worker            if self._queue[-1] != key:
402*635a8641SAndroid Build Coastguard Worker                try:
403*635a8641SAndroid Build Coastguard Worker                    self._remove(key)
404*635a8641SAndroid Build Coastguard Worker                except ValueError:
405*635a8641SAndroid Build Coastguard Worker                    # if something removed the key from the container
406*635a8641SAndroid Build Coastguard Worker                    # when we read, ignore the ValueError that we would
407*635a8641SAndroid Build Coastguard Worker                    # get otherwise.
408*635a8641SAndroid Build Coastguard Worker                    pass
409*635a8641SAndroid Build Coastguard Worker                self._append(key)
410*635a8641SAndroid Build Coastguard Worker            return rv
411*635a8641SAndroid Build Coastguard Worker        finally:
412*635a8641SAndroid Build Coastguard Worker            self._wlock.release()
413*635a8641SAndroid Build Coastguard Worker
414*635a8641SAndroid Build Coastguard Worker    def __setitem__(self, key, value):
415*635a8641SAndroid Build Coastguard Worker        """Sets the value for an item. Moves the item up so that it
416*635a8641SAndroid Build Coastguard Worker        has the highest priority then.
417*635a8641SAndroid Build Coastguard Worker        """
418*635a8641SAndroid Build Coastguard Worker        self._wlock.acquire()
419*635a8641SAndroid Build Coastguard Worker        try:
420*635a8641SAndroid Build Coastguard Worker            if key in self._mapping:
421*635a8641SAndroid Build Coastguard Worker                self._remove(key)
422*635a8641SAndroid Build Coastguard Worker            elif len(self._mapping) == self.capacity:
423*635a8641SAndroid Build Coastguard Worker                del self._mapping[self._popleft()]
424*635a8641SAndroid Build Coastguard Worker            self._append(key)
425*635a8641SAndroid Build Coastguard Worker            self._mapping[key] = value
426*635a8641SAndroid Build Coastguard Worker        finally:
427*635a8641SAndroid Build Coastguard Worker            self._wlock.release()
428*635a8641SAndroid Build Coastguard Worker
429*635a8641SAndroid Build Coastguard Worker    def __delitem__(self, key):
430*635a8641SAndroid Build Coastguard Worker        """Remove an item from the cache dict.
431*635a8641SAndroid Build Coastguard Worker        Raise a `KeyError` if it does not exist.
432*635a8641SAndroid Build Coastguard Worker        """
433*635a8641SAndroid Build Coastguard Worker        self._wlock.acquire()
434*635a8641SAndroid Build Coastguard Worker        try:
435*635a8641SAndroid Build Coastguard Worker            del self._mapping[key]
436*635a8641SAndroid Build Coastguard Worker            try:
437*635a8641SAndroid Build Coastguard Worker                self._remove(key)
438*635a8641SAndroid Build Coastguard Worker            except ValueError:
439*635a8641SAndroid Build Coastguard Worker                # __getitem__ is not locked, it might happen
440*635a8641SAndroid Build Coastguard Worker                pass
441*635a8641SAndroid Build Coastguard Worker        finally:
442*635a8641SAndroid Build Coastguard Worker            self._wlock.release()
443*635a8641SAndroid Build Coastguard Worker
444*635a8641SAndroid Build Coastguard Worker    def items(self):
445*635a8641SAndroid Build Coastguard Worker        """Return a list of items."""
446*635a8641SAndroid Build Coastguard Worker        result = [(key, self._mapping[key]) for key in list(self._queue)]
447*635a8641SAndroid Build Coastguard Worker        result.reverse()
448*635a8641SAndroid Build Coastguard Worker        return result
449*635a8641SAndroid Build Coastguard Worker
450*635a8641SAndroid Build Coastguard Worker    def iteritems(self):
451*635a8641SAndroid Build Coastguard Worker        """Iterate over all items."""
452*635a8641SAndroid Build Coastguard Worker        return iter(self.items())
453*635a8641SAndroid Build Coastguard Worker
454*635a8641SAndroid Build Coastguard Worker    def values(self):
455*635a8641SAndroid Build Coastguard Worker        """Return a list of all values."""
456*635a8641SAndroid Build Coastguard Worker        return [x[1] for x in self.items()]
457*635a8641SAndroid Build Coastguard Worker
458*635a8641SAndroid Build Coastguard Worker    def itervalue(self):
459*635a8641SAndroid Build Coastguard Worker        """Iterate over all values."""
460*635a8641SAndroid Build Coastguard Worker        return iter(self.values())
461*635a8641SAndroid Build Coastguard Worker
462*635a8641SAndroid Build Coastguard Worker    def keys(self):
463*635a8641SAndroid Build Coastguard Worker        """Return a list of all keys ordered by most recent usage."""
464*635a8641SAndroid Build Coastguard Worker        return list(self)
465*635a8641SAndroid Build Coastguard Worker
466*635a8641SAndroid Build Coastguard Worker    def iterkeys(self):
467*635a8641SAndroid Build Coastguard Worker        """Iterate over all keys in the cache dict, ordered by
468*635a8641SAndroid Build Coastguard Worker        the most recent usage.
469*635a8641SAndroid Build Coastguard Worker        """
470*635a8641SAndroid Build Coastguard Worker        return reversed(tuple(self._queue))
471*635a8641SAndroid Build Coastguard Worker
472*635a8641SAndroid Build Coastguard Worker    __iter__ = iterkeys
473*635a8641SAndroid Build Coastguard Worker
474*635a8641SAndroid Build Coastguard Worker    def __reversed__(self):
475*635a8641SAndroid Build Coastguard Worker        """Iterate over the values in the cache dict, oldest items
476*635a8641SAndroid Build Coastguard Worker        coming first.
477*635a8641SAndroid Build Coastguard Worker        """
478*635a8641SAndroid Build Coastguard Worker        return iter(tuple(self._queue))
479*635a8641SAndroid Build Coastguard Worker
480*635a8641SAndroid Build Coastguard Worker    __copy__ = copy
481*635a8641SAndroid Build Coastguard Worker
482*635a8641SAndroid Build Coastguard Worker
483*635a8641SAndroid Build Coastguard Worker# register the LRU cache as mutable mapping if possible
484*635a8641SAndroid Build Coastguard Workertry:
485*635a8641SAndroid Build Coastguard Worker    from collections import MutableMapping
486*635a8641SAndroid Build Coastguard Worker    MutableMapping.register(LRUCache)
487*635a8641SAndroid Build Coastguard Workerexcept ImportError:
488*635a8641SAndroid Build Coastguard Worker    pass
489*635a8641SAndroid Build Coastguard Worker
490*635a8641SAndroid Build Coastguard Worker
491*635a8641SAndroid Build Coastguard Workerdef select_autoescape(enabled_extensions=('html', 'htm', 'xml'),
492*635a8641SAndroid Build Coastguard Worker                      disabled_extensions=(),
493*635a8641SAndroid Build Coastguard Worker                      default_for_string=True,
494*635a8641SAndroid Build Coastguard Worker                      default=False):
495*635a8641SAndroid Build Coastguard Worker    """Intelligently sets the initial value of autoescaping based on the
496*635a8641SAndroid Build Coastguard Worker    filename of the template.  This is the recommended way to configure
497*635a8641SAndroid Build Coastguard Worker    autoescaping if you do not want to write a custom function yourself.
498*635a8641SAndroid Build Coastguard Worker
499*635a8641SAndroid Build Coastguard Worker    If you want to enable it for all templates created from strings or
500*635a8641SAndroid Build Coastguard Worker    for all templates with `.html` and `.xml` extensions::
501*635a8641SAndroid Build Coastguard Worker
502*635a8641SAndroid Build Coastguard Worker        from jinja2 import Environment, select_autoescape
503*635a8641SAndroid Build Coastguard Worker        env = Environment(autoescape=select_autoescape(
504*635a8641SAndroid Build Coastguard Worker            enabled_extensions=('html', 'xml'),
505*635a8641SAndroid Build Coastguard Worker            default_for_string=True,
506*635a8641SAndroid Build Coastguard Worker        ))
507*635a8641SAndroid Build Coastguard Worker
508*635a8641SAndroid Build Coastguard Worker    Example configuration to turn it on at all times except if the template
509*635a8641SAndroid Build Coastguard Worker    ends with `.txt`::
510*635a8641SAndroid Build Coastguard Worker
511*635a8641SAndroid Build Coastguard Worker        from jinja2 import Environment, select_autoescape
512*635a8641SAndroid Build Coastguard Worker        env = Environment(autoescape=select_autoescape(
513*635a8641SAndroid Build Coastguard Worker            disabled_extensions=('txt',),
514*635a8641SAndroid Build Coastguard Worker            default_for_string=True,
515*635a8641SAndroid Build Coastguard Worker            default=True,
516*635a8641SAndroid Build Coastguard Worker        ))
517*635a8641SAndroid Build Coastguard Worker
518*635a8641SAndroid Build Coastguard Worker    The `enabled_extensions` is an iterable of all the extensions that
519*635a8641SAndroid Build Coastguard Worker    autoescaping should be enabled for.  Likewise `disabled_extensions` is
520*635a8641SAndroid Build Coastguard Worker    a list of all templates it should be disabled for.  If a template is
521*635a8641SAndroid Build Coastguard Worker    loaded from a string then the default from `default_for_string` is used.
522*635a8641SAndroid Build Coastguard Worker    If nothing matches then the initial value of autoescaping is set to the
523*635a8641SAndroid Build Coastguard Worker    value of `default`.
524*635a8641SAndroid Build Coastguard Worker
525*635a8641SAndroid Build Coastguard Worker    For security reasons this function operates case insensitive.
526*635a8641SAndroid Build Coastguard Worker
527*635a8641SAndroid Build Coastguard Worker    .. versionadded:: 2.9
528*635a8641SAndroid Build Coastguard Worker    """
529*635a8641SAndroid Build Coastguard Worker    enabled_patterns = tuple('.' + x.lstrip('.').lower()
530*635a8641SAndroid Build Coastguard Worker                             for x in enabled_extensions)
531*635a8641SAndroid Build Coastguard Worker    disabled_patterns = tuple('.' + x.lstrip('.').lower()
532*635a8641SAndroid Build Coastguard Worker                              for x in disabled_extensions)
533*635a8641SAndroid Build Coastguard Worker    def autoescape(template_name):
534*635a8641SAndroid Build Coastguard Worker        if template_name is None:
535*635a8641SAndroid Build Coastguard Worker            return default_for_string
536*635a8641SAndroid Build Coastguard Worker        template_name = template_name.lower()
537*635a8641SAndroid Build Coastguard Worker        if template_name.endswith(enabled_patterns):
538*635a8641SAndroid Build Coastguard Worker            return True
539*635a8641SAndroid Build Coastguard Worker        if template_name.endswith(disabled_patterns):
540*635a8641SAndroid Build Coastguard Worker            return False
541*635a8641SAndroid Build Coastguard Worker        return default
542*635a8641SAndroid Build Coastguard Worker    return autoescape
543*635a8641SAndroid Build Coastguard Worker
544*635a8641SAndroid Build Coastguard Worker
545*635a8641SAndroid Build Coastguard Workerdef htmlsafe_json_dumps(obj, dumper=None, **kwargs):
546*635a8641SAndroid Build Coastguard Worker    """Works exactly like :func:`dumps` but is safe for use in ``<script>``
547*635a8641SAndroid Build Coastguard Worker    tags.  It accepts the same arguments and returns a JSON string.  Note that
548*635a8641SAndroid Build Coastguard Worker    this is available in templates through the ``|tojson`` filter which will
549*635a8641SAndroid Build Coastguard Worker    also mark the result as safe.  Due to how this function escapes certain
550*635a8641SAndroid Build Coastguard Worker    characters this is safe even if used outside of ``<script>`` tags.
551*635a8641SAndroid Build Coastguard Worker
552*635a8641SAndroid Build Coastguard Worker    The following characters are escaped in strings:
553*635a8641SAndroid Build Coastguard Worker
554*635a8641SAndroid Build Coastguard Worker    -   ``<``
555*635a8641SAndroid Build Coastguard Worker    -   ``>``
556*635a8641SAndroid Build Coastguard Worker    -   ``&``
557*635a8641SAndroid Build Coastguard Worker    -   ``'``
558*635a8641SAndroid Build Coastguard Worker
559*635a8641SAndroid Build Coastguard Worker    This makes it safe to embed such strings in any place in HTML with the
560*635a8641SAndroid Build Coastguard Worker    notable exception of double quoted attributes.  In that case single
561*635a8641SAndroid Build Coastguard Worker    quote your attributes or HTML escape it in addition.
562*635a8641SAndroid Build Coastguard Worker    """
563*635a8641SAndroid Build Coastguard Worker    if dumper is None:
564*635a8641SAndroid Build Coastguard Worker        dumper = json.dumps
565*635a8641SAndroid Build Coastguard Worker    rv = dumper(obj, **kwargs) \
566*635a8641SAndroid Build Coastguard Worker        .replace(u'<', u'\\u003c') \
567*635a8641SAndroid Build Coastguard Worker        .replace(u'>', u'\\u003e') \
568*635a8641SAndroid Build Coastguard Worker        .replace(u'&', u'\\u0026') \
569*635a8641SAndroid Build Coastguard Worker        .replace(u"'", u'\\u0027')
570*635a8641SAndroid Build Coastguard Worker    return Markup(rv)
571*635a8641SAndroid Build Coastguard Worker
572*635a8641SAndroid Build Coastguard Worker
573*635a8641SAndroid Build Coastguard Worker@implements_iterator
574*635a8641SAndroid Build Coastguard Workerclass Cycler(object):
575*635a8641SAndroid Build Coastguard Worker    """A cycle helper for templates."""
576*635a8641SAndroid Build Coastguard Worker
577*635a8641SAndroid Build Coastguard Worker    def __init__(self, *items):
578*635a8641SAndroid Build Coastguard Worker        if not items:
579*635a8641SAndroid Build Coastguard Worker            raise RuntimeError('at least one item has to be provided')
580*635a8641SAndroid Build Coastguard Worker        self.items = items
581*635a8641SAndroid Build Coastguard Worker        self.reset()
582*635a8641SAndroid Build Coastguard Worker
583*635a8641SAndroid Build Coastguard Worker    def reset(self):
584*635a8641SAndroid Build Coastguard Worker        """Resets the cycle."""
585*635a8641SAndroid Build Coastguard Worker        self.pos = 0
586*635a8641SAndroid Build Coastguard Worker
587*635a8641SAndroid Build Coastguard Worker    @property
588*635a8641SAndroid Build Coastguard Worker    def current(self):
589*635a8641SAndroid Build Coastguard Worker        """Returns the current item."""
590*635a8641SAndroid Build Coastguard Worker        return self.items[self.pos]
591*635a8641SAndroid Build Coastguard Worker
592*635a8641SAndroid Build Coastguard Worker    def next(self):
593*635a8641SAndroid Build Coastguard Worker        """Goes one item ahead and returns it."""
594*635a8641SAndroid Build Coastguard Worker        rv = self.current
595*635a8641SAndroid Build Coastguard Worker        self.pos = (self.pos + 1) % len(self.items)
596*635a8641SAndroid Build Coastguard Worker        return rv
597*635a8641SAndroid Build Coastguard Worker
598*635a8641SAndroid Build Coastguard Worker    __next__ = next
599*635a8641SAndroid Build Coastguard Worker
600*635a8641SAndroid Build Coastguard Worker
601*635a8641SAndroid Build Coastguard Workerclass Joiner(object):
602*635a8641SAndroid Build Coastguard Worker    """A joining helper for templates."""
603*635a8641SAndroid Build Coastguard Worker
604*635a8641SAndroid Build Coastguard Worker    def __init__(self, sep=u', '):
605*635a8641SAndroid Build Coastguard Worker        self.sep = sep
606*635a8641SAndroid Build Coastguard Worker        self.used = False
607*635a8641SAndroid Build Coastguard Worker
608*635a8641SAndroid Build Coastguard Worker    def __call__(self):
609*635a8641SAndroid Build Coastguard Worker        if not self.used:
610*635a8641SAndroid Build Coastguard Worker            self.used = True
611*635a8641SAndroid Build Coastguard Worker            return u''
612*635a8641SAndroid Build Coastguard Worker        return self.sep
613*635a8641SAndroid Build Coastguard Worker
614*635a8641SAndroid Build Coastguard Worker
615*635a8641SAndroid Build Coastguard Workerclass Namespace(object):
616*635a8641SAndroid Build Coastguard Worker    """A namespace object that can hold arbitrary attributes.  It may be
617*635a8641SAndroid Build Coastguard Worker    initialized from a dictionary or with keyword argments."""
618*635a8641SAndroid Build Coastguard Worker
619*635a8641SAndroid Build Coastguard Worker    def __init__(*args, **kwargs):
620*635a8641SAndroid Build Coastguard Worker        self, args = args[0], args[1:]
621*635a8641SAndroid Build Coastguard Worker        self.__attrs = dict(*args, **kwargs)
622*635a8641SAndroid Build Coastguard Worker
623*635a8641SAndroid Build Coastguard Worker    def __getattribute__(self, name):
624*635a8641SAndroid Build Coastguard Worker        if name == '_Namespace__attrs':
625*635a8641SAndroid Build Coastguard Worker            return object.__getattribute__(self, name)
626*635a8641SAndroid Build Coastguard Worker        try:
627*635a8641SAndroid Build Coastguard Worker            return self.__attrs[name]
628*635a8641SAndroid Build Coastguard Worker        except KeyError:
629*635a8641SAndroid Build Coastguard Worker            raise AttributeError(name)
630*635a8641SAndroid Build Coastguard Worker
631*635a8641SAndroid Build Coastguard Worker    def __setitem__(self, name, value):
632*635a8641SAndroid Build Coastguard Worker        self.__attrs[name] = value
633*635a8641SAndroid Build Coastguard Worker
634*635a8641SAndroid Build Coastguard Worker    def __repr__(self):
635*635a8641SAndroid Build Coastguard Worker        return '<Namespace %r>' % self.__attrs
636*635a8641SAndroid Build Coastguard Worker
637*635a8641SAndroid Build Coastguard Worker
638*635a8641SAndroid Build Coastguard Worker# does this python version support async for in and async generators?
639*635a8641SAndroid Build Coastguard Workertry:
640*635a8641SAndroid Build Coastguard Worker    exec('async def _():\n async for _ in ():\n  yield _')
641*635a8641SAndroid Build Coastguard Worker    have_async_gen = True
642*635a8641SAndroid Build Coastguard Workerexcept SyntaxError:
643*635a8641SAndroid Build Coastguard Worker    have_async_gen = False
644*635a8641SAndroid Build Coastguard Worker
645*635a8641SAndroid Build Coastguard Worker
646*635a8641SAndroid Build Coastguard Worker# Imported here because that's where it was in the past
647*635a8641SAndroid Build Coastguard Workerfrom markupsafe import Markup, escape, soft_unicode
648