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, ('(', '<', '<'))), 241cb0ef41Sopenharmony_ci '|'.join(map(re.escape, ('.', ',', ')', '>', '\n', '>'))) 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