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, ('(', '<', '<'))), 24*635a8641SAndroid Build Coastguard Worker '|'.join(map(re.escape, ('.', ',', ')', '>', '\n', '>'))) 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