11cb0ef41Sopenharmony_ci# -*- coding: utf-8 -*-
21cb0ef41Sopenharmony_ci"""
31cb0ef41Sopenharmony_ci    jinja2.utils
41cb0ef41Sopenharmony_ci    ~~~~~~~~~~~~
51cb0ef41Sopenharmony_ci
61cb0ef41Sopenharmony_ci    Utility functions.
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci    :copyright: (c) 2017 by the Jinja Team.
91cb0ef41Sopenharmony_ci    :license: BSD, see LICENSE for more details.
101cb0ef41Sopenharmony_ci"""
111cb0ef41Sopenharmony_ciimport re
121cb0ef41Sopenharmony_ciimport json
131cb0ef41Sopenharmony_ciimport errno
141cb0ef41Sopenharmony_cifrom collections import deque
151cb0ef41Sopenharmony_cifrom threading import Lock
161cb0ef41Sopenharmony_cifrom jinja2._compat import text_type, string_types, implements_iterator, \
171cb0ef41Sopenharmony_ci     url_quote
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_ci_word_split_re = re.compile(r'(\s+)')
211cb0ef41Sopenharmony_ci_punctuation_re = re.compile(
221cb0ef41Sopenharmony_ci    '^(?P<lead>(?:%s)*)(?P<middle>.*?)(?P<trail>(?:%s)*)$' % (
231cb0ef41Sopenharmony_ci        '|'.join(map(re.escape, ('(', '<', '&lt;'))),
241cb0ef41Sopenharmony_ci        '|'.join(map(re.escape, ('.', ',', ')', '>', '\n', '&gt;')))
251cb0ef41Sopenharmony_ci    )
261cb0ef41Sopenharmony_ci)
271cb0ef41Sopenharmony_ci_simple_email_re = re.compile(r'^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$')
281cb0ef41Sopenharmony_ci_striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
291cb0ef41Sopenharmony_ci_entity_re = re.compile(r'&([^;]+);')
301cb0ef41Sopenharmony_ci_letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
311cb0ef41Sopenharmony_ci_digits = '0123456789'
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ci# special singleton representing missing values for the runtime
341cb0ef41Sopenharmony_cimissing = type('MissingType', (), {'__repr__': lambda x: 'missing'})()
351cb0ef41Sopenharmony_ci
361cb0ef41Sopenharmony_ci# internal code
371cb0ef41Sopenharmony_ciinternal_code = set()
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ciconcat = u''.join
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ci_slash_escape = '\\/' not in json.dumps('/')
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_cidef contextfunction(f):
451cb0ef41Sopenharmony_ci    """This decorator can be used to mark a function or method context callable.
461cb0ef41Sopenharmony_ci    A context callable is passed the active :class:`Context` as first argument when
471cb0ef41Sopenharmony_ci    called from the template.  This is useful if a function wants to get access
481cb0ef41Sopenharmony_ci    to the context or functions provided on the context object.  For example
491cb0ef41Sopenharmony_ci    a function that returns a sorted list of template variables the current
501cb0ef41Sopenharmony_ci    template exports could look like this::
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci        @contextfunction
531cb0ef41Sopenharmony_ci        def get_exported_names(context):
541cb0ef41Sopenharmony_ci            return sorted(context.exported_vars)
551cb0ef41Sopenharmony_ci    """
561cb0ef41Sopenharmony_ci    f.contextfunction = True
571cb0ef41Sopenharmony_ci    return f
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_cidef evalcontextfunction(f):
611cb0ef41Sopenharmony_ci    """This decorator can be used to mark a function or method as an eval
621cb0ef41Sopenharmony_ci    context callable.  This is similar to the :func:`contextfunction`
631cb0ef41Sopenharmony_ci    but instead of passing the context, an evaluation context object is
641cb0ef41Sopenharmony_ci    passed.  For more information about the eval context, see
651cb0ef41Sopenharmony_ci    :ref:`eval-context`.
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci    .. versionadded:: 2.4
681cb0ef41Sopenharmony_ci    """
691cb0ef41Sopenharmony_ci    f.evalcontextfunction = True
701cb0ef41Sopenharmony_ci    return f
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_cidef environmentfunction(f):
741cb0ef41Sopenharmony_ci    """This decorator can be used to mark a function or method as environment
751cb0ef41Sopenharmony_ci    callable.  This decorator works exactly like the :func:`contextfunction`
761cb0ef41Sopenharmony_ci    decorator just that the first argument is the active :class:`Environment`
771cb0ef41Sopenharmony_ci    and not context.
781cb0ef41Sopenharmony_ci    """
791cb0ef41Sopenharmony_ci    f.environmentfunction = True
801cb0ef41Sopenharmony_ci    return f
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_cidef internalcode(f):
841cb0ef41Sopenharmony_ci    """Marks the function as internally used"""
851cb0ef41Sopenharmony_ci    internal_code.add(f.__code__)
861cb0ef41Sopenharmony_ci    return f
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_cidef is_undefined(obj):
901cb0ef41Sopenharmony_ci    """Check if the object passed is undefined.  This does nothing more than
911cb0ef41Sopenharmony_ci    performing an instance check against :class:`Undefined` but looks nicer.
921cb0ef41Sopenharmony_ci    This can be used for custom filters or tests that want to react to
931cb0ef41Sopenharmony_ci    undefined variables.  For example a custom default filter can look like
941cb0ef41Sopenharmony_ci    this::
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ci        def default(var, default=''):
971cb0ef41Sopenharmony_ci            if is_undefined(var):
981cb0ef41Sopenharmony_ci                return default
991cb0ef41Sopenharmony_ci            return var
1001cb0ef41Sopenharmony_ci    """
1011cb0ef41Sopenharmony_ci    from jinja2.runtime import Undefined
1021cb0ef41Sopenharmony_ci    return isinstance(obj, Undefined)
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci
1051cb0ef41Sopenharmony_cidef consume(iterable):
1061cb0ef41Sopenharmony_ci    """Consumes an iterable without doing anything with it."""
1071cb0ef41Sopenharmony_ci    for event in iterable:
1081cb0ef41Sopenharmony_ci        pass
1091cb0ef41Sopenharmony_ci
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_cidef clear_caches():
1121cb0ef41Sopenharmony_ci    """Jinja2 keeps internal caches for environments and lexers.  These are
1131cb0ef41Sopenharmony_ci    used so that Jinja2 doesn't have to recreate environments and lexers all
1141cb0ef41Sopenharmony_ci    the time.  Normally you don't have to care about that but if you are
1151cb0ef41Sopenharmony_ci    measuring memory consumption you may want to clean the caches.
1161cb0ef41Sopenharmony_ci    """
1171cb0ef41Sopenharmony_ci    from jinja2.environment import _spontaneous_environments
1181cb0ef41Sopenharmony_ci    from jinja2.lexer import _lexer_cache
1191cb0ef41Sopenharmony_ci    _spontaneous_environments.clear()
1201cb0ef41Sopenharmony_ci    _lexer_cache.clear()
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_cidef import_string(import_name, silent=False):
1241cb0ef41Sopenharmony_ci    """Imports an object based on a string.  This is useful if you want to
1251cb0ef41Sopenharmony_ci    use import paths as endpoints or something similar.  An import path can
1261cb0ef41Sopenharmony_ci    be specified either in dotted notation (``xml.sax.saxutils.escape``)
1271cb0ef41Sopenharmony_ci    or with a colon as object delimiter (``xml.sax.saxutils:escape``).
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci    If the `silent` is True the return value will be `None` if the import
1301cb0ef41Sopenharmony_ci    fails.
1311cb0ef41Sopenharmony_ci
1321cb0ef41Sopenharmony_ci    :return: imported object
1331cb0ef41Sopenharmony_ci    """
1341cb0ef41Sopenharmony_ci    try:
1351cb0ef41Sopenharmony_ci        if ':' in import_name:
1361cb0ef41Sopenharmony_ci            module, obj = import_name.split(':', 1)
1371cb0ef41Sopenharmony_ci        elif '.' in import_name:
1381cb0ef41Sopenharmony_ci            items = import_name.split('.')
1391cb0ef41Sopenharmony_ci            module = '.'.join(items[:-1])
1401cb0ef41Sopenharmony_ci            obj = items[-1]
1411cb0ef41Sopenharmony_ci        else:
1421cb0ef41Sopenharmony_ci            return __import__(import_name)
1431cb0ef41Sopenharmony_ci        return getattr(__import__(module, None, None, [obj]), obj)
1441cb0ef41Sopenharmony_ci    except (ImportError, AttributeError):
1451cb0ef41Sopenharmony_ci        if not silent:
1461cb0ef41Sopenharmony_ci            raise
1471cb0ef41Sopenharmony_ci
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_cidef open_if_exists(filename, mode='rb'):
1501cb0ef41Sopenharmony_ci    """Returns a file descriptor for the filename if that file exists,
1511cb0ef41Sopenharmony_ci    otherwise `None`.
1521cb0ef41Sopenharmony_ci    """
1531cb0ef41Sopenharmony_ci    try:
1541cb0ef41Sopenharmony_ci        return open(filename, mode)
1551cb0ef41Sopenharmony_ci    except IOError as e:
1561cb0ef41Sopenharmony_ci        if e.errno not in (errno.ENOENT, errno.EISDIR, errno.EINVAL):
1571cb0ef41Sopenharmony_ci            raise
1581cb0ef41Sopenharmony_ci
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_cidef object_type_repr(obj):
1611cb0ef41Sopenharmony_ci    """Returns the name of the object's type.  For some recognized
1621cb0ef41Sopenharmony_ci    singletons the name of the object is returned instead. (For
1631cb0ef41Sopenharmony_ci    example for `None` and `Ellipsis`).
1641cb0ef41Sopenharmony_ci    """
1651cb0ef41Sopenharmony_ci    if obj is None:
1661cb0ef41Sopenharmony_ci        return 'None'
1671cb0ef41Sopenharmony_ci    elif obj is Ellipsis:
1681cb0ef41Sopenharmony_ci        return 'Ellipsis'
1691cb0ef41Sopenharmony_ci    # __builtin__ in 2.x, builtins in 3.x
1701cb0ef41Sopenharmony_ci    if obj.__class__.__module__ in ('__builtin__', 'builtins'):
1711cb0ef41Sopenharmony_ci        name = obj.__class__.__name__
1721cb0ef41Sopenharmony_ci    else:
1731cb0ef41Sopenharmony_ci        name = obj.__class__.__module__ + '.' + obj.__class__.__name__
1741cb0ef41Sopenharmony_ci    return '%s object' % name
1751cb0ef41Sopenharmony_ci
1761cb0ef41Sopenharmony_ci
1771cb0ef41Sopenharmony_cidef pformat(obj, verbose=False):
1781cb0ef41Sopenharmony_ci    """Prettyprint an object.  Either use the `pretty` library or the
1791cb0ef41Sopenharmony_ci    builtin `pprint`.
1801cb0ef41Sopenharmony_ci    """
1811cb0ef41Sopenharmony_ci    try:
1821cb0ef41Sopenharmony_ci        from pretty import pretty
1831cb0ef41Sopenharmony_ci        return pretty(obj, verbose=verbose)
1841cb0ef41Sopenharmony_ci    except ImportError:
1851cb0ef41Sopenharmony_ci        from pprint import pformat
1861cb0ef41Sopenharmony_ci        return pformat(obj)
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_ci
1891cb0ef41Sopenharmony_cidef urlize(text, trim_url_limit=None, rel=None, target=None):
1901cb0ef41Sopenharmony_ci    """Converts any URLs in text into clickable links. Works on http://,
1911cb0ef41Sopenharmony_ci    https:// and www. links. Links can have trailing punctuation (periods,
1921cb0ef41Sopenharmony_ci    commas, close-parens) and leading punctuation (opening parens) and
1931cb0ef41Sopenharmony_ci    it'll still do the right thing.
1941cb0ef41Sopenharmony_ci
1951cb0ef41Sopenharmony_ci    If trim_url_limit is not None, the URLs in link text will be limited
1961cb0ef41Sopenharmony_ci    to trim_url_limit characters.
1971cb0ef41Sopenharmony_ci
1981cb0ef41Sopenharmony_ci    If nofollow is True, the URLs in link text will get a rel="nofollow"
1991cb0ef41Sopenharmony_ci    attribute.
2001cb0ef41Sopenharmony_ci
2011cb0ef41Sopenharmony_ci    If target is not None, a target attribute will be added to the link.
2021cb0ef41Sopenharmony_ci    """
2031cb0ef41Sopenharmony_ci    trim_url = lambda x, limit=trim_url_limit: limit is not None \
2041cb0ef41Sopenharmony_ci                         and (x[:limit] + (len(x) >=limit and '...'
2051cb0ef41Sopenharmony_ci                         or '')) or x
2061cb0ef41Sopenharmony_ci    words = _word_split_re.split(text_type(escape(text)))
2071cb0ef41Sopenharmony_ci    rel_attr = rel and ' rel="%s"' % text_type(escape(rel)) or ''
2081cb0ef41Sopenharmony_ci    target_attr = target and ' target="%s"' % escape(target) or ''
2091cb0ef41Sopenharmony_ci
2101cb0ef41Sopenharmony_ci    for i, word in enumerate(words):
2111cb0ef41Sopenharmony_ci        match = _punctuation_re.match(word)
2121cb0ef41Sopenharmony_ci        if match:
2131cb0ef41Sopenharmony_ci            lead, middle, trail = match.groups()
2141cb0ef41Sopenharmony_ci            if middle.startswith('www.') or (
2151cb0ef41Sopenharmony_ci                '@' not in middle and
2161cb0ef41Sopenharmony_ci                not middle.startswith('http://') and
2171cb0ef41Sopenharmony_ci                not middle.startswith('https://') and
2181cb0ef41Sopenharmony_ci                len(middle) > 0 and
2191cb0ef41Sopenharmony_ci                middle[0] in _letters + _digits and (
2201cb0ef41Sopenharmony_ci                    middle.endswith('.org') or
2211cb0ef41Sopenharmony_ci                    middle.endswith('.net') or
2221cb0ef41Sopenharmony_ci                    middle.endswith('.com')
2231cb0ef41Sopenharmony_ci                )):
2241cb0ef41Sopenharmony_ci                middle = '<a href="http://%s"%s%s>%s</a>' % (middle,
2251cb0ef41Sopenharmony_ci                    rel_attr, target_attr, trim_url(middle))
2261cb0ef41Sopenharmony_ci            if middle.startswith('http://') or \
2271cb0ef41Sopenharmony_ci               middle.startswith('https://'):
2281cb0ef41Sopenharmony_ci                middle = '<a href="%s"%s%s>%s</a>' % (middle,
2291cb0ef41Sopenharmony_ci                    rel_attr, target_attr, trim_url(middle))
2301cb0ef41Sopenharmony_ci            if '@' in middle and not middle.startswith('www.') and \
2311cb0ef41Sopenharmony_ci               not ':' in middle and _simple_email_re.match(middle):
2321cb0ef41Sopenharmony_ci                middle = '<a href="mailto:%s">%s</a>' % (middle, middle)
2331cb0ef41Sopenharmony_ci            if lead + middle + trail != word:
2341cb0ef41Sopenharmony_ci                words[i] = lead + middle + trail
2351cb0ef41Sopenharmony_ci    return u''.join(words)
2361cb0ef41Sopenharmony_ci
2371cb0ef41Sopenharmony_ci
2381cb0ef41Sopenharmony_cidef generate_lorem_ipsum(n=5, html=True, min=20, max=100):
2391cb0ef41Sopenharmony_ci    """Generate some lorem ipsum for the template."""
2401cb0ef41Sopenharmony_ci    from jinja2.constants import LOREM_IPSUM_WORDS
2411cb0ef41Sopenharmony_ci    from random import choice, randrange
2421cb0ef41Sopenharmony_ci    words = LOREM_IPSUM_WORDS.split()
2431cb0ef41Sopenharmony_ci    result = []
2441cb0ef41Sopenharmony_ci
2451cb0ef41Sopenharmony_ci    for _ in range(n):
2461cb0ef41Sopenharmony_ci        next_capitalized = True
2471cb0ef41Sopenharmony_ci        last_comma = last_fullstop = 0
2481cb0ef41Sopenharmony_ci        word = None
2491cb0ef41Sopenharmony_ci        last = None
2501cb0ef41Sopenharmony_ci        p = []
2511cb0ef41Sopenharmony_ci
2521cb0ef41Sopenharmony_ci        # each paragraph contains out of 20 to 100 words.
2531cb0ef41Sopenharmony_ci        for idx, _ in enumerate(range(randrange(min, max))):
2541cb0ef41Sopenharmony_ci            while True:
2551cb0ef41Sopenharmony_ci                word = choice(words)
2561cb0ef41Sopenharmony_ci                if word != last:
2571cb0ef41Sopenharmony_ci                    last = word
2581cb0ef41Sopenharmony_ci                    break
2591cb0ef41Sopenharmony_ci            if next_capitalized:
2601cb0ef41Sopenharmony_ci                word = word.capitalize()
2611cb0ef41Sopenharmony_ci                next_capitalized = False
2621cb0ef41Sopenharmony_ci            # add commas
2631cb0ef41Sopenharmony_ci            if idx - randrange(3, 8) > last_comma:
2641cb0ef41Sopenharmony_ci                last_comma = idx
2651cb0ef41Sopenharmony_ci                last_fullstop += 2
2661cb0ef41Sopenharmony_ci                word += ','
2671cb0ef41Sopenharmony_ci            # add end of sentences
2681cb0ef41Sopenharmony_ci            if idx - randrange(10, 20) > last_fullstop:
2691cb0ef41Sopenharmony_ci                last_comma = last_fullstop = idx
2701cb0ef41Sopenharmony_ci                word += '.'
2711cb0ef41Sopenharmony_ci                next_capitalized = True
2721cb0ef41Sopenharmony_ci            p.append(word)
2731cb0ef41Sopenharmony_ci
2741cb0ef41Sopenharmony_ci        # ensure that the paragraph ends with a dot.
2751cb0ef41Sopenharmony_ci        p = u' '.join(p)
2761cb0ef41Sopenharmony_ci        if p.endswith(','):
2771cb0ef41Sopenharmony_ci            p = p[:-1] + '.'
2781cb0ef41Sopenharmony_ci        elif not p.endswith('.'):
2791cb0ef41Sopenharmony_ci            p += '.'
2801cb0ef41Sopenharmony_ci        result.append(p)
2811cb0ef41Sopenharmony_ci
2821cb0ef41Sopenharmony_ci    if not html:
2831cb0ef41Sopenharmony_ci        return u'\n\n'.join(result)
2841cb0ef41Sopenharmony_ci    return Markup(u'\n'.join(u'<p>%s</p>' % escape(x) for x in result))
2851cb0ef41Sopenharmony_ci
2861cb0ef41Sopenharmony_ci
2871cb0ef41Sopenharmony_cidef unicode_urlencode(obj, charset='utf-8', for_qs=False):
2881cb0ef41Sopenharmony_ci    """URL escapes a single bytestring or unicode string with the
2891cb0ef41Sopenharmony_ci    given charset if applicable to URL safe quoting under all rules
2901cb0ef41Sopenharmony_ci    that need to be considered under all supported Python versions.
2911cb0ef41Sopenharmony_ci
2921cb0ef41Sopenharmony_ci    If non strings are provided they are converted to their unicode
2931cb0ef41Sopenharmony_ci    representation first.
2941cb0ef41Sopenharmony_ci    """
2951cb0ef41Sopenharmony_ci    if not isinstance(obj, string_types):
2961cb0ef41Sopenharmony_ci        obj = text_type(obj)
2971cb0ef41Sopenharmony_ci    if isinstance(obj, text_type):
2981cb0ef41Sopenharmony_ci        obj = obj.encode(charset)
2991cb0ef41Sopenharmony_ci    safe = not for_qs and b'/' or b''
3001cb0ef41Sopenharmony_ci    rv = text_type(url_quote(obj, safe))
3011cb0ef41Sopenharmony_ci    if for_qs:
3021cb0ef41Sopenharmony_ci        rv = rv.replace('%20', '+')
3031cb0ef41Sopenharmony_ci    return rv
3041cb0ef41Sopenharmony_ci
3051cb0ef41Sopenharmony_ci
3061cb0ef41Sopenharmony_ciclass LRUCache(object):
3071cb0ef41Sopenharmony_ci    """A simple LRU Cache implementation."""
3081cb0ef41Sopenharmony_ci
3091cb0ef41Sopenharmony_ci    # this is fast for small capacities (something below 1000) but doesn't
3101cb0ef41Sopenharmony_ci    # scale.  But as long as it's only used as storage for templates this
3111cb0ef41Sopenharmony_ci    # won't do any harm.
3121cb0ef41Sopenharmony_ci
3131cb0ef41Sopenharmony_ci    def __init__(self, capacity):
3141cb0ef41Sopenharmony_ci        self.capacity = capacity
3151cb0ef41Sopenharmony_ci        self._mapping = {}
3161cb0ef41Sopenharmony_ci        self._queue = deque()
3171cb0ef41Sopenharmony_ci        self._postinit()
3181cb0ef41Sopenharmony_ci
3191cb0ef41Sopenharmony_ci    def _postinit(self):
3201cb0ef41Sopenharmony_ci        # alias all queue methods for faster lookup
3211cb0ef41Sopenharmony_ci        self._popleft = self._queue.popleft
3221cb0ef41Sopenharmony_ci        self._pop = self._queue.pop
3231cb0ef41Sopenharmony_ci        self._remove = self._queue.remove
3241cb0ef41Sopenharmony_ci        self._wlock = Lock()
3251cb0ef41Sopenharmony_ci        self._append = self._queue.append
3261cb0ef41Sopenharmony_ci
3271cb0ef41Sopenharmony_ci    def __getstate__(self):
3281cb0ef41Sopenharmony_ci        return {
3291cb0ef41Sopenharmony_ci            'capacity':     self.capacity,
3301cb0ef41Sopenharmony_ci            '_mapping':     self._mapping,
3311cb0ef41Sopenharmony_ci            '_queue':       self._queue
3321cb0ef41Sopenharmony_ci        }
3331cb0ef41Sopenharmony_ci
3341cb0ef41Sopenharmony_ci    def __setstate__(self, d):
3351cb0ef41Sopenharmony_ci        self.__dict__.update(d)
3361cb0ef41Sopenharmony_ci        self._postinit()
3371cb0ef41Sopenharmony_ci
3381cb0ef41Sopenharmony_ci    def __getnewargs__(self):
3391cb0ef41Sopenharmony_ci        return (self.capacity,)
3401cb0ef41Sopenharmony_ci
3411cb0ef41Sopenharmony_ci    def copy(self):
3421cb0ef41Sopenharmony_ci        """Return a shallow copy of the instance."""
3431cb0ef41Sopenharmony_ci        rv = self.__class__(self.capacity)
3441cb0ef41Sopenharmony_ci        rv._mapping.update(self._mapping)
3451cb0ef41Sopenharmony_ci        rv._queue = deque(self._queue)
3461cb0ef41Sopenharmony_ci        return rv
3471cb0ef41Sopenharmony_ci
3481cb0ef41Sopenharmony_ci    def get(self, key, default=None):
3491cb0ef41Sopenharmony_ci        """Return an item from the cache dict or `default`"""
3501cb0ef41Sopenharmony_ci        try:
3511cb0ef41Sopenharmony_ci            return self[key]
3521cb0ef41Sopenharmony_ci        except KeyError:
3531cb0ef41Sopenharmony_ci            return default
3541cb0ef41Sopenharmony_ci
3551cb0ef41Sopenharmony_ci    def setdefault(self, key, default=None):
3561cb0ef41Sopenharmony_ci        """Set `default` if the key is not in the cache otherwise
3571cb0ef41Sopenharmony_ci        leave unchanged. Return the value of this key.
3581cb0ef41Sopenharmony_ci        """
3591cb0ef41Sopenharmony_ci        self._wlock.acquire()
3601cb0ef41Sopenharmony_ci        try:
3611cb0ef41Sopenharmony_ci            try:
3621cb0ef41Sopenharmony_ci                return self[key]
3631cb0ef41Sopenharmony_ci            except KeyError:
3641cb0ef41Sopenharmony_ci                self[key] = default
3651cb0ef41Sopenharmony_ci                return default
3661cb0ef41Sopenharmony_ci        finally:
3671cb0ef41Sopenharmony_ci            self._wlock.release()
3681cb0ef41Sopenharmony_ci
3691cb0ef41Sopenharmony_ci    def clear(self):
3701cb0ef41Sopenharmony_ci        """Clear the cache."""
3711cb0ef41Sopenharmony_ci        self._wlock.acquire()
3721cb0ef41Sopenharmony_ci        try:
3731cb0ef41Sopenharmony_ci            self._mapping.clear()
3741cb0ef41Sopenharmony_ci            self._queue.clear()
3751cb0ef41Sopenharmony_ci        finally:
3761cb0ef41Sopenharmony_ci            self._wlock.release()
3771cb0ef41Sopenharmony_ci
3781cb0ef41Sopenharmony_ci    def __contains__(self, key):
3791cb0ef41Sopenharmony_ci        """Check if a key exists in this cache."""
3801cb0ef41Sopenharmony_ci        return key in self._mapping
3811cb0ef41Sopenharmony_ci
3821cb0ef41Sopenharmony_ci    def __len__(self):
3831cb0ef41Sopenharmony_ci        """Return the current size of the cache."""
3841cb0ef41Sopenharmony_ci        return len(self._mapping)
3851cb0ef41Sopenharmony_ci
3861cb0ef41Sopenharmony_ci    def __repr__(self):
3871cb0ef41Sopenharmony_ci        return '<%s %r>' % (
3881cb0ef41Sopenharmony_ci            self.__class__.__name__,
3891cb0ef41Sopenharmony_ci            self._mapping
3901cb0ef41Sopenharmony_ci        )
3911cb0ef41Sopenharmony_ci
3921cb0ef41Sopenharmony_ci    def __getitem__(self, key):
3931cb0ef41Sopenharmony_ci        """Get an item from the cache. Moves the item up so that it has the
3941cb0ef41Sopenharmony_ci        highest priority then.
3951cb0ef41Sopenharmony_ci
3961cb0ef41Sopenharmony_ci        Raise a `KeyError` if it does not exist.
3971cb0ef41Sopenharmony_ci        """
3981cb0ef41Sopenharmony_ci        self._wlock.acquire()
3991cb0ef41Sopenharmony_ci        try:
4001cb0ef41Sopenharmony_ci            rv = self._mapping[key]
4011cb0ef41Sopenharmony_ci            if self._queue[-1] != key:
4021cb0ef41Sopenharmony_ci                try:
4031cb0ef41Sopenharmony_ci                    self._remove(key)
4041cb0ef41Sopenharmony_ci                except ValueError:
4051cb0ef41Sopenharmony_ci                    # if something removed the key from the container
4061cb0ef41Sopenharmony_ci                    # when we read, ignore the ValueError that we would
4071cb0ef41Sopenharmony_ci                    # get otherwise.
4081cb0ef41Sopenharmony_ci                    pass
4091cb0ef41Sopenharmony_ci                self._append(key)
4101cb0ef41Sopenharmony_ci            return rv
4111cb0ef41Sopenharmony_ci        finally:
4121cb0ef41Sopenharmony_ci            self._wlock.release()
4131cb0ef41Sopenharmony_ci
4141cb0ef41Sopenharmony_ci    def __setitem__(self, key, value):
4151cb0ef41Sopenharmony_ci        """Sets the value for an item. Moves the item up so that it
4161cb0ef41Sopenharmony_ci        has the highest priority then.
4171cb0ef41Sopenharmony_ci        """
4181cb0ef41Sopenharmony_ci        self._wlock.acquire()
4191cb0ef41Sopenharmony_ci        try:
4201cb0ef41Sopenharmony_ci            if key in self._mapping:
4211cb0ef41Sopenharmony_ci                self._remove(key)
4221cb0ef41Sopenharmony_ci            elif len(self._mapping) == self.capacity:
4231cb0ef41Sopenharmony_ci                del self._mapping[self._popleft()]
4241cb0ef41Sopenharmony_ci            self._append(key)
4251cb0ef41Sopenharmony_ci            self._mapping[key] = value
4261cb0ef41Sopenharmony_ci        finally:
4271cb0ef41Sopenharmony_ci            self._wlock.release()
4281cb0ef41Sopenharmony_ci
4291cb0ef41Sopenharmony_ci    def __delitem__(self, key):
4301cb0ef41Sopenharmony_ci        """Remove an item from the cache dict.
4311cb0ef41Sopenharmony_ci        Raise a `KeyError` if it does not exist.
4321cb0ef41Sopenharmony_ci        """
4331cb0ef41Sopenharmony_ci        self._wlock.acquire()
4341cb0ef41Sopenharmony_ci        try:
4351cb0ef41Sopenharmony_ci            del self._mapping[key]
4361cb0ef41Sopenharmony_ci            try:
4371cb0ef41Sopenharmony_ci                self._remove(key)
4381cb0ef41Sopenharmony_ci            except ValueError:
4391cb0ef41Sopenharmony_ci                # __getitem__ is not locked, it might happen
4401cb0ef41Sopenharmony_ci                pass
4411cb0ef41Sopenharmony_ci        finally:
4421cb0ef41Sopenharmony_ci            self._wlock.release()
4431cb0ef41Sopenharmony_ci
4441cb0ef41Sopenharmony_ci    def items(self):
4451cb0ef41Sopenharmony_ci        """Return a list of items."""
4461cb0ef41Sopenharmony_ci        result = [(key, self._mapping[key]) for key in list(self._queue)]
4471cb0ef41Sopenharmony_ci        result.reverse()
4481cb0ef41Sopenharmony_ci        return result
4491cb0ef41Sopenharmony_ci
4501cb0ef41Sopenharmony_ci    def iteritems(self):
4511cb0ef41Sopenharmony_ci        """Iterate over all items."""
4521cb0ef41Sopenharmony_ci        return iter(self.items())
4531cb0ef41Sopenharmony_ci
4541cb0ef41Sopenharmony_ci    def values(self):
4551cb0ef41Sopenharmony_ci        """Return a list of all values."""
4561cb0ef41Sopenharmony_ci        return [x[1] for x in self.items()]
4571cb0ef41Sopenharmony_ci
4581cb0ef41Sopenharmony_ci    def itervalue(self):
4591cb0ef41Sopenharmony_ci        """Iterate over all values."""
4601cb0ef41Sopenharmony_ci        return iter(self.values())
4611cb0ef41Sopenharmony_ci
4621cb0ef41Sopenharmony_ci    def keys(self):
4631cb0ef41Sopenharmony_ci        """Return a list of all keys ordered by most recent usage."""
4641cb0ef41Sopenharmony_ci        return list(self)
4651cb0ef41Sopenharmony_ci
4661cb0ef41Sopenharmony_ci    def iterkeys(self):
4671cb0ef41Sopenharmony_ci        """Iterate over all keys in the cache dict, ordered by
4681cb0ef41Sopenharmony_ci        the most recent usage.
4691cb0ef41Sopenharmony_ci        """
4701cb0ef41Sopenharmony_ci        return reversed(tuple(self._queue))
4711cb0ef41Sopenharmony_ci
4721cb0ef41Sopenharmony_ci    __iter__ = iterkeys
4731cb0ef41Sopenharmony_ci
4741cb0ef41Sopenharmony_ci    def __reversed__(self):
4751cb0ef41Sopenharmony_ci        """Iterate over the values in the cache dict, oldest items
4761cb0ef41Sopenharmony_ci        coming first.
4771cb0ef41Sopenharmony_ci        """
4781cb0ef41Sopenharmony_ci        return iter(tuple(self._queue))
4791cb0ef41Sopenharmony_ci
4801cb0ef41Sopenharmony_ci    __copy__ = copy
4811cb0ef41Sopenharmony_ci
4821cb0ef41Sopenharmony_ci
4831cb0ef41Sopenharmony_ci# register the LRU cache as mutable mapping if possible
4841cb0ef41Sopenharmony_citry:
4851cb0ef41Sopenharmony_ci    from collections import MutableMapping
4861cb0ef41Sopenharmony_ci    MutableMapping.register(LRUCache)
4871cb0ef41Sopenharmony_ciexcept ImportError:
4881cb0ef41Sopenharmony_ci    pass
4891cb0ef41Sopenharmony_ci
4901cb0ef41Sopenharmony_ci
4911cb0ef41Sopenharmony_cidef select_autoescape(enabled_extensions=('html', 'htm', 'xml'),
4921cb0ef41Sopenharmony_ci                      disabled_extensions=(),
4931cb0ef41Sopenharmony_ci                      default_for_string=True,
4941cb0ef41Sopenharmony_ci                      default=False):
4951cb0ef41Sopenharmony_ci    """Intelligently sets the initial value of autoescaping based on the
4961cb0ef41Sopenharmony_ci    filename of the template.  This is the recommended way to configure
4971cb0ef41Sopenharmony_ci    autoescaping if you do not want to write a custom function yourself.
4981cb0ef41Sopenharmony_ci
4991cb0ef41Sopenharmony_ci    If you want to enable it for all templates created from strings or
5001cb0ef41Sopenharmony_ci    for all templates with `.html` and `.xml` extensions::
5011cb0ef41Sopenharmony_ci
5021cb0ef41Sopenharmony_ci        from jinja2 import Environment, select_autoescape
5031cb0ef41Sopenharmony_ci        env = Environment(autoescape=select_autoescape(
5041cb0ef41Sopenharmony_ci            enabled_extensions=('html', 'xml'),
5051cb0ef41Sopenharmony_ci            default_for_string=True,
5061cb0ef41Sopenharmony_ci        ))
5071cb0ef41Sopenharmony_ci
5081cb0ef41Sopenharmony_ci    Example configuration to turn it on at all times except if the template
5091cb0ef41Sopenharmony_ci    ends with `.txt`::
5101cb0ef41Sopenharmony_ci
5111cb0ef41Sopenharmony_ci        from jinja2 import Environment, select_autoescape
5121cb0ef41Sopenharmony_ci        env = Environment(autoescape=select_autoescape(
5131cb0ef41Sopenharmony_ci            disabled_extensions=('txt',),
5141cb0ef41Sopenharmony_ci            default_for_string=True,
5151cb0ef41Sopenharmony_ci            default=True,
5161cb0ef41Sopenharmony_ci        ))
5171cb0ef41Sopenharmony_ci
5181cb0ef41Sopenharmony_ci    The `enabled_extensions` is an iterable of all the extensions that
5191cb0ef41Sopenharmony_ci    autoescaping should be enabled for.  Likewise `disabled_extensions` is
5201cb0ef41Sopenharmony_ci    a list of all templates it should be disabled for.  If a template is
5211cb0ef41Sopenharmony_ci    loaded from a string then the default from `default_for_string` is used.
5221cb0ef41Sopenharmony_ci    If nothing matches then the initial value of autoescaping is set to the
5231cb0ef41Sopenharmony_ci    value of `default`.
5241cb0ef41Sopenharmony_ci
5251cb0ef41Sopenharmony_ci    For security reasons this function operates case insensitive.
5261cb0ef41Sopenharmony_ci
5271cb0ef41Sopenharmony_ci    .. versionadded:: 2.9
5281cb0ef41Sopenharmony_ci    """
5291cb0ef41Sopenharmony_ci    enabled_patterns = tuple('.' + x.lstrip('.').lower()
5301cb0ef41Sopenharmony_ci                             for x in enabled_extensions)
5311cb0ef41Sopenharmony_ci    disabled_patterns = tuple('.' + x.lstrip('.').lower()
5321cb0ef41Sopenharmony_ci                              for x in disabled_extensions)
5331cb0ef41Sopenharmony_ci    def autoescape(template_name):
5341cb0ef41Sopenharmony_ci        if template_name is None:
5351cb0ef41Sopenharmony_ci            return default_for_string
5361cb0ef41Sopenharmony_ci        template_name = template_name.lower()
5371cb0ef41Sopenharmony_ci        if template_name.endswith(enabled_patterns):
5381cb0ef41Sopenharmony_ci            return True
5391cb0ef41Sopenharmony_ci        if template_name.endswith(disabled_patterns):
5401cb0ef41Sopenharmony_ci            return False
5411cb0ef41Sopenharmony_ci        return default
5421cb0ef41Sopenharmony_ci    return autoescape
5431cb0ef41Sopenharmony_ci
5441cb0ef41Sopenharmony_ci
5451cb0ef41Sopenharmony_cidef htmlsafe_json_dumps(obj, dumper=None, **kwargs):
5461cb0ef41Sopenharmony_ci    """Works exactly like :func:`dumps` but is safe for use in ``<script>``
5471cb0ef41Sopenharmony_ci    tags.  It accepts the same arguments and returns a JSON string.  Note that
5481cb0ef41Sopenharmony_ci    this is available in templates through the ``|tojson`` filter which will
5491cb0ef41Sopenharmony_ci    also mark the result as safe.  Due to how this function escapes certain
5501cb0ef41Sopenharmony_ci    characters this is safe even if used outside of ``<script>`` tags.
5511cb0ef41Sopenharmony_ci
5521cb0ef41Sopenharmony_ci    The following characters are escaped in strings:
5531cb0ef41Sopenharmony_ci
5541cb0ef41Sopenharmony_ci    -   ``<``
5551cb0ef41Sopenharmony_ci    -   ``>``
5561cb0ef41Sopenharmony_ci    -   ``&``
5571cb0ef41Sopenharmony_ci    -   ``'``
5581cb0ef41Sopenharmony_ci
5591cb0ef41Sopenharmony_ci    This makes it safe to embed such strings in any place in HTML with the
5601cb0ef41Sopenharmony_ci    notable exception of double quoted attributes.  In that case single
5611cb0ef41Sopenharmony_ci    quote your attributes or HTML escape it in addition.
5621cb0ef41Sopenharmony_ci    """
5631cb0ef41Sopenharmony_ci    if dumper is None:
5641cb0ef41Sopenharmony_ci        dumper = json.dumps
5651cb0ef41Sopenharmony_ci    rv = dumper(obj, **kwargs) \
5661cb0ef41Sopenharmony_ci        .replace(u'<', u'\\u003c') \
5671cb0ef41Sopenharmony_ci        .replace(u'>', u'\\u003e') \
5681cb0ef41Sopenharmony_ci        .replace(u'&', u'\\u0026') \
5691cb0ef41Sopenharmony_ci        .replace(u"'", u'\\u0027')
5701cb0ef41Sopenharmony_ci    return Markup(rv)
5711cb0ef41Sopenharmony_ci
5721cb0ef41Sopenharmony_ci
5731cb0ef41Sopenharmony_ci@implements_iterator
5741cb0ef41Sopenharmony_ciclass Cycler(object):
5751cb0ef41Sopenharmony_ci    """A cycle helper for templates."""
5761cb0ef41Sopenharmony_ci
5771cb0ef41Sopenharmony_ci    def __init__(self, *items):
5781cb0ef41Sopenharmony_ci        if not items:
5791cb0ef41Sopenharmony_ci            raise RuntimeError('at least one item has to be provided')
5801cb0ef41Sopenharmony_ci        self.items = items
5811cb0ef41Sopenharmony_ci        self.reset()
5821cb0ef41Sopenharmony_ci
5831cb0ef41Sopenharmony_ci    def reset(self):
5841cb0ef41Sopenharmony_ci        """Resets the cycle."""
5851cb0ef41Sopenharmony_ci        self.pos = 0
5861cb0ef41Sopenharmony_ci
5871cb0ef41Sopenharmony_ci    @property
5881cb0ef41Sopenharmony_ci    def current(self):
5891cb0ef41Sopenharmony_ci        """Returns the current item."""
5901cb0ef41Sopenharmony_ci        return self.items[self.pos]
5911cb0ef41Sopenharmony_ci
5921cb0ef41Sopenharmony_ci    def next(self):
5931cb0ef41Sopenharmony_ci        """Goes one item ahead and returns it."""
5941cb0ef41Sopenharmony_ci        rv = self.current
5951cb0ef41Sopenharmony_ci        self.pos = (self.pos + 1) % len(self.items)
5961cb0ef41Sopenharmony_ci        return rv
5971cb0ef41Sopenharmony_ci
5981cb0ef41Sopenharmony_ci    __next__ = next
5991cb0ef41Sopenharmony_ci
6001cb0ef41Sopenharmony_ci
6011cb0ef41Sopenharmony_ciclass Joiner(object):
6021cb0ef41Sopenharmony_ci    """A joining helper for templates."""
6031cb0ef41Sopenharmony_ci
6041cb0ef41Sopenharmony_ci    def __init__(self, sep=u', '):
6051cb0ef41Sopenharmony_ci        self.sep = sep
6061cb0ef41Sopenharmony_ci        self.used = False
6071cb0ef41Sopenharmony_ci
6081cb0ef41Sopenharmony_ci    def __call__(self):
6091cb0ef41Sopenharmony_ci        if not self.used:
6101cb0ef41Sopenharmony_ci            self.used = True
6111cb0ef41Sopenharmony_ci            return u''
6121cb0ef41Sopenharmony_ci        return self.sep
6131cb0ef41Sopenharmony_ci
6141cb0ef41Sopenharmony_ci
6151cb0ef41Sopenharmony_ciclass Namespace(object):
6161cb0ef41Sopenharmony_ci    """A namespace object that can hold arbitrary attributes.  It may be
6171cb0ef41Sopenharmony_ci    initialized from a dictionary or with keyword argments."""
6181cb0ef41Sopenharmony_ci
6191cb0ef41Sopenharmony_ci    def __init__(*args, **kwargs):
6201cb0ef41Sopenharmony_ci        self, args = args[0], args[1:]
6211cb0ef41Sopenharmony_ci        self.__attrs = dict(*args, **kwargs)
6221cb0ef41Sopenharmony_ci
6231cb0ef41Sopenharmony_ci    def __getattribute__(self, name):
6241cb0ef41Sopenharmony_ci        if name == '_Namespace__attrs':
6251cb0ef41Sopenharmony_ci            return object.__getattribute__(self, name)
6261cb0ef41Sopenharmony_ci        try:
6271cb0ef41Sopenharmony_ci            return self.__attrs[name]
6281cb0ef41Sopenharmony_ci        except KeyError:
6291cb0ef41Sopenharmony_ci            raise AttributeError(name)
6301cb0ef41Sopenharmony_ci
6311cb0ef41Sopenharmony_ci    def __setitem__(self, name, value):
6321cb0ef41Sopenharmony_ci        self.__attrs[name] = value
6331cb0ef41Sopenharmony_ci
6341cb0ef41Sopenharmony_ci    def __repr__(self):
6351cb0ef41Sopenharmony_ci        return '<Namespace %r>' % self.__attrs
6361cb0ef41Sopenharmony_ci
6371cb0ef41Sopenharmony_ci
6381cb0ef41Sopenharmony_ci# does this python version support async for in and async generators?
6391cb0ef41Sopenharmony_citry:
6401cb0ef41Sopenharmony_ci    exec('async def _():\n async for _ in ():\n  yield _')
6411cb0ef41Sopenharmony_ci    have_async_gen = True
6421cb0ef41Sopenharmony_ciexcept SyntaxError:
6431cb0ef41Sopenharmony_ci    have_async_gen = False
6441cb0ef41Sopenharmony_ci
6451cb0ef41Sopenharmony_ci
6461cb0ef41Sopenharmony_ci# Imported here because that's where it was in the past
6471cb0ef41Sopenharmony_cifrom markupsafe import Markup, escape, soft_unicode
648