| Index: third_party/jinja2/utils.py
|
| diff --git a/third_party/jinja2/utils.py b/third_party/jinja2/utils.py
|
| index 49e9e9ae0737dd5876b1ca67d8f00185dcad0370..ddc47da0a0462d480d4513f75f667f1472deb822 100644
|
| --- a/third_party/jinja2/utils.py
|
| +++ b/third_party/jinja2/utils.py
|
| @@ -9,21 +9,17 @@
|
| :license: BSD, see LICENSE for more details.
|
| """
|
| import re
|
| -import sys
|
| import errno
|
| -try:
|
| - from thread import allocate_lock
|
| -except ImportError:
|
| - from dummy_thread import allocate_lock
|
| from collections import deque
|
| -from itertools import imap
|
| +from jinja2._compat import text_type, string_types, implements_iterator, \
|
| + allocate_lock, url_quote
|
|
|
|
|
| _word_split_re = re.compile(r'(\s+)')
|
| _punctuation_re = re.compile(
|
| '^(?P<lead>(?:%s)*)(?P<middle>.*?)(?P<trail>(?:%s)*)$' % (
|
| - '|'.join(imap(re.escape, ('(', '<', '<'))),
|
| - '|'.join(imap(re.escape, ('.', ',', ')', '>', '\n', '>')))
|
| + '|'.join(map(re.escape, ('(', '<', '<'))),
|
| + '|'.join(map(re.escape, ('.', ',', ')', '>', '\n', '>')))
|
| )
|
| )
|
| _simple_email_re = re.compile(r'^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$')
|
| @@ -38,77 +34,7 @@ missing = type('MissingType', (), {'__repr__': lambda x: 'missing'})()
|
| # internal code
|
| internal_code = set()
|
|
|
| -
|
| -# concatenate a list of strings and convert them to unicode.
|
| -# unfortunately there is a bug in python 2.4 and lower that causes
|
| -# unicode.join trash the traceback.
|
| -_concat = u''.join
|
| -try:
|
| - def _test_gen_bug():
|
| - raise TypeError(_test_gen_bug)
|
| - yield None
|
| - _concat(_test_gen_bug())
|
| -except TypeError, _error:
|
| - if not _error.args or _error.args[0] is not _test_gen_bug:
|
| - def concat(gen):
|
| - try:
|
| - return _concat(list(gen))
|
| - except Exception:
|
| - # this hack is needed so that the current frame
|
| - # does not show up in the traceback.
|
| - exc_type, exc_value, tb = sys.exc_info()
|
| - raise exc_type, exc_value, tb.tb_next
|
| - else:
|
| - concat = _concat
|
| - del _test_gen_bug, _error
|
| -
|
| -
|
| -# for python 2.x we create outselves a next() function that does the
|
| -# basics without exception catching.
|
| -try:
|
| - next = next
|
| -except NameError:
|
| - def next(x):
|
| - return x.next()
|
| -
|
| -
|
| -# if this python version is unable to deal with unicode filenames
|
| -# when passed to encode we let this function encode it properly.
|
| -# This is used in a couple of places. As far as Jinja is concerned
|
| -# filenames are unicode *or* bytestrings in 2.x and unicode only in
|
| -# 3.x because compile cannot handle bytes
|
| -if sys.version_info < (3, 0):
|
| - def _encode_filename(filename):
|
| - if isinstance(filename, unicode):
|
| - return filename.encode('utf-8')
|
| - return filename
|
| -else:
|
| - def _encode_filename(filename):
|
| - assert filename is None or isinstance(filename, str), \
|
| - 'filenames must be strings'
|
| - return filename
|
| -
|
| -from keyword import iskeyword as is_python_keyword
|
| -
|
| -
|
| -# common types. These do exist in the special types module too which however
|
| -# does not exist in IronPython out of the box. Also that way we don't have
|
| -# to deal with implementation specific stuff here
|
| -class _C(object):
|
| - def method(self): pass
|
| -def _func():
|
| - yield None
|
| -FunctionType = type(_func)
|
| -GeneratorType = type(_func())
|
| -MethodType = type(_C.method)
|
| -CodeType = type(_C.method.func_code)
|
| -try:
|
| - raise TypeError()
|
| -except TypeError:
|
| - _tb = sys.exc_info()[2]
|
| - TracebackType = type(_tb)
|
| - FrameType = type(_tb.tb_frame)
|
| -del _C, _tb, _func
|
| +concat = u''.join
|
|
|
|
|
| def contextfunction(f):
|
| @@ -128,7 +54,7 @@ def contextfunction(f):
|
|
|
|
|
| def evalcontextfunction(f):
|
| - """This decoraotr can be used to mark a function or method as an eval
|
| + """This decorator can be used to mark a function or method as an eval
|
| context callable. This is similar to the :func:`contextfunction`
|
| but instead of passing the context, an evaluation context object is
|
| passed. For more information about the eval context, see
|
| @@ -152,7 +78,7 @@ def environmentfunction(f):
|
|
|
| def internalcode(f):
|
| """Marks the function as internally used"""
|
| - internal_code.add(f.func_code)
|
| + internal_code.add(f.__code__)
|
| return f
|
|
|
|
|
| @@ -191,7 +117,7 @@ def clear_caches():
|
|
|
|
|
| def import_string(import_name, silent=False):
|
| - """Imports an object based on a string. This use useful if you want to
|
| + """Imports an object based on a string. This is useful if you want to
|
| use import paths as endpoints or something similar. An import path can
|
| be specified either in dotted notation (``xml.sax.saxutils.escape``)
|
| or with a colon as object delimiter (``xml.sax.saxutils:escape``).
|
| @@ -222,7 +148,7 @@ def open_if_exists(filename, mode='rb'):
|
| """
|
| try:
|
| return open(filename, mode)
|
| - except IOError, e:
|
| + except IOError as e:
|
| if e.errno not in (errno.ENOENT, errno.EISDIR):
|
| raise
|
|
|
| @@ -271,7 +197,7 @@ def urlize(text, trim_url_limit=None, nofollow=False):
|
| trim_url = lambda x, limit=trim_url_limit: limit is not None \
|
| and (x[:limit] + (len(x) >=limit and '...'
|
| or '')) or x
|
| - words = _word_split_re.split(unicode(escape(text)))
|
| + words = _word_split_re.split(text_type(escape(text)))
|
| nofollow_attr = nofollow and ' rel="nofollow"' or ''
|
| for i, word in enumerate(words):
|
| match = _punctuation_re.match(word)
|
| @@ -280,6 +206,7 @@ def urlize(text, trim_url_limit=None, nofollow=False):
|
| if middle.startswith('www.') or (
|
| '@' not in middle and
|
| not middle.startswith('http://') and
|
| + not middle.startswith('https://') and
|
| len(middle) > 0 and
|
| middle[0] in _letters + _digits and (
|
| middle.endswith('.org') or
|
| @@ -307,7 +234,7 @@ def generate_lorem_ipsum(n=5, html=True, min=20, max=100):
|
| words = LOREM_IPSUM_WORDS.split()
|
| result = []
|
|
|
| - for _ in xrange(n):
|
| + for _ in range(n):
|
| next_capitalized = True
|
| last_comma = last_fullstop = 0
|
| word = None
|
| @@ -315,7 +242,7 @@ def generate_lorem_ipsum(n=5, html=True, min=20, max=100):
|
| p = []
|
|
|
| # each paragraph contains out of 20 to 100 words.
|
| - for idx, _ in enumerate(xrange(randrange(min, max))):
|
| + for idx, _ in enumerate(range(randrange(min, max))):
|
| while True:
|
| word = choice(words)
|
| if word != last:
|
| @@ -349,6 +276,21 @@ def generate_lorem_ipsum(n=5, html=True, min=20, max=100):
|
| return Markup(u'\n'.join(u'<p>%s</p>' % escape(x) for x in result))
|
|
|
|
|
| +def unicode_urlencode(obj, charset='utf-8'):
|
| + """URL escapes a single bytestring or unicode string with the
|
| + given charset if applicable to URL safe quoting under all rules
|
| + that need to be considered under all supported Python versions.
|
| +
|
| + If non strings are provided they are converted to their unicode
|
| + representation first.
|
| + """
|
| + if not isinstance(obj, string_types):
|
| + obj = text_type(obj)
|
| + if isinstance(obj, text_type):
|
| + obj = obj.encode(charset)
|
| + return text_type(url_quote(obj))
|
| +
|
| +
|
| class LRUCache(object):
|
| """A simple LRU Cache implementation."""
|
|
|
| @@ -366,18 +308,10 @@ class LRUCache(object):
|
| # alias all queue methods for faster lookup
|
| self._popleft = self._queue.popleft
|
| self._pop = self._queue.pop
|
| - if hasattr(self._queue, 'remove'):
|
| - self._remove = self._queue.remove
|
| + self._remove = self._queue.remove
|
| self._wlock = allocate_lock()
|
| self._append = self._queue.append
|
|
|
| - def _remove(self, obj):
|
| - """Python 2.4 compatibility."""
|
| - for idx, item in enumerate(self._queue):
|
| - if item == obj:
|
| - del self._queue[idx]
|
| - break
|
| -
|
| def __getstate__(self):
|
| return {
|
| 'capacity': self.capacity,
|
| @@ -393,7 +327,7 @@ class LRUCache(object):
|
| return (self.capacity,)
|
|
|
| def copy(self):
|
| - """Return an shallow copy of the instance."""
|
| + """Return a shallow copy of the instance."""
|
| rv = self.__class__(self.capacity)
|
| rv._mapping.update(self._mapping)
|
| rv._queue = deque(self._queue)
|
| @@ -410,11 +344,15 @@ class LRUCache(object):
|
| """Set `default` if the key is not in the cache otherwise
|
| leave unchanged. Return the value of this key.
|
| """
|
| + self._wlock.acquire()
|
| try:
|
| - return self[key]
|
| - except KeyError:
|
| - self[key] = default
|
| - return default
|
| + try:
|
| + return self[key]
|
| + except KeyError:
|
| + self[key] = default
|
| + return default
|
| + finally:
|
| + self._wlock.release()
|
|
|
| def clear(self):
|
| """Clear the cache."""
|
| @@ -443,19 +381,23 @@ class LRUCache(object):
|
| """Get an item from the cache. Moves the item up so that it has the
|
| highest priority then.
|
|
|
| - Raise an `KeyError` if it does not exist.
|
| + Raise a `KeyError` if it does not exist.
|
| """
|
| - rv = self._mapping[key]
|
| - if self._queue[-1] != key:
|
| - try:
|
| - self._remove(key)
|
| - except ValueError:
|
| - # if something removed the key from the container
|
| - # when we read, ignore the ValueError that we would
|
| - # get otherwise.
|
| - pass
|
| - self._append(key)
|
| - return rv
|
| + self._wlock.acquire()
|
| + try:
|
| + rv = self._mapping[key]
|
| + if self._queue[-1] != key:
|
| + try:
|
| + self._remove(key)
|
| + except ValueError:
|
| + # if something removed the key from the container
|
| + # when we read, ignore the ValueError that we would
|
| + # get otherwise.
|
| + pass
|
| + self._append(key)
|
| + return rv
|
| + finally:
|
| + self._wlock.release()
|
|
|
| def __setitem__(self, key, value):
|
| """Sets the value for an item. Moves the item up so that it
|
| @@ -464,11 +406,7 @@ class LRUCache(object):
|
| self._wlock.acquire()
|
| try:
|
| if key in self._mapping:
|
| - try:
|
| - self._remove(key)
|
| - except ValueError:
|
| - # __getitem__ is not locked, it might happen
|
| - pass
|
| + self._remove(key)
|
| elif len(self._mapping) == self.capacity:
|
| del self._mapping[self._popleft()]
|
| self._append(key)
|
| @@ -478,7 +416,7 @@ class LRUCache(object):
|
|
|
| def __delitem__(self, key):
|
| """Remove an item from the cache dict.
|
| - Raise an `KeyError` if it does not exist.
|
| + Raise a `KeyError` if it does not exist.
|
| """
|
| self._wlock.acquire()
|
| try:
|
| @@ -538,6 +476,7 @@ except ImportError:
|
| pass
|
|
|
|
|
| +@implements_iterator
|
| class Cycler(object):
|
| """A cycle helper for templates."""
|
|
|
| @@ -556,7 +495,7 @@ class Cycler(object):
|
| """Returns the current item."""
|
| return self.items[self.pos]
|
|
|
| - def next(self):
|
| + def __next__(self):
|
| """Goes one item ahead and returns it."""
|
| rv = self.current
|
| self.pos = (self.pos + 1) % len(self.items)
|
| @@ -577,25 +516,5 @@ class Joiner(object):
|
| return self.sep
|
|
|
|
|
| -# try markupsafe first, if that fails go with Jinja2's bundled version
|
| -# of markupsafe. Markupsafe was previously Jinja2's implementation of
|
| -# the Markup object but was moved into a separate package in a patchleve
|
| -# release
|
| -try:
|
| - from markupsafe import Markup, escape, soft_unicode
|
| -except ImportError:
|
| - from jinja2._markupsafe import Markup, escape, soft_unicode
|
| -
|
| -
|
| -# partials
|
| -try:
|
| - from functools import partial
|
| -except ImportError:
|
| - class partial(object):
|
| - def __init__(self, _func, *args, **kwargs):
|
| - self._func = _func
|
| - self._args = args
|
| - self._kwargs = kwargs
|
| - def __call__(self, *args, **kwargs):
|
| - kwargs.update(self._kwargs)
|
| - return self._func(*(self._args + args), **kwargs)
|
| +# Imported here because that's where it was in the past
|
| +from markupsafe import Markup, escape, soft_unicode
|
|
|