blob: ca0968bf41702933b7f9b9e70d4a568b3fba7b8f [file] [log] [blame]
Armin Ronacher07bc6842008-03-31 14:18:49 +02001# -*- coding: utf-8 -*-
2"""
3 jinja2.utils
4 ~~~~~~~~~~~~
5
6 Utility functions.
7
Armin Ronacher55494e42010-01-22 09:41:48 +01008 :copyright: (c) 2010 by the Jinja Team.
Armin Ronacher07bc6842008-03-31 14:18:49 +02009 :license: BSD, see LICENSE for more details.
10"""
Christoph Hack80909862008-04-14 01:35:10 +020011import re
Benjamin Wiegand96828552008-05-03 22:27:29 +020012import sys
Armin Ronacherccae0552008-10-05 23:08:58 +020013import errno
Thomas Waldmanne0003552013-05-17 23:52:14 +020014import six
Thomas Waldmann7d295622013-05-18 00:06:22 +020015from six.moves import map
Armin Ronacher000b4912008-05-01 18:40:15 +020016try:
Armin Ronacher1d4c6382012-01-07 17:46:40 +010017 from urllib.parse import quote_from_bytes as url_quote
18except ImportError:
19 from urllib import quote as url_quote
20try:
Armin Ronacher000b4912008-05-01 18:40:15 +020021 from thread import allocate_lock
22except ImportError:
Thomas Waldmann7d295622013-05-18 00:06:22 +020023 try:
24 from _thread import allocate_lock # py 3
25 except ImportError:
26 from dummy_thread import allocate_lock
Armin Ronacher814f6c22008-04-17 15:52:23 +020027from collections import deque
Armin Ronacher8edbe492008-04-10 20:43:43 +020028
Armin Ronacherbe4ae242008-04-18 09:49:08 +020029_word_split_re = re.compile(r'(\s+)')
30_punctuation_re = re.compile(
31 '^(?P<lead>(?:%s)*)(?P<middle>.*?)(?P<trail>(?:%s)*)$' % (
Thomas Waldmann7d295622013-05-18 00:06:22 +020032 '|'.join(map(re.escape, ('(', '<', '&lt;'))),
33 '|'.join(map(re.escape, ('.', ',', ')', '>', '\n', '&gt;')))
Armin Ronacherbe4ae242008-04-18 09:49:08 +020034 )
35)
36_simple_email_re = re.compile(r'^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$')
Armin Ronacher76c280b2008-05-04 12:31:48 +020037_striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
38_entity_re = re.compile(r'&([^;]+);')
Armin Ronacher9a0078d2008-08-13 18:24:17 +020039_letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
40_digits = '0123456789'
Armin Ronacherbe4ae242008-04-18 09:49:08 +020041
Armin Ronacher7259c762008-04-30 13:03:59 +020042# special singleton representing missing values for the runtime
43missing = type('MissingType', (), {'__repr__': lambda x: 'missing'})()
44
Armin Ronacherd416a972009-02-24 22:58:00 +010045# internal code
46internal_code = set()
47
Armin Ronacher7259c762008-04-30 13:03:59 +020048
Armin Ronacher7ceced52008-05-03 10:15:31 +020049# concatenate a list of strings and convert them to unicode.
50# unfortunately there is a bug in python 2.4 and lower that causes
51# unicode.join trash the traceback.
Armin Ronachercda43df2008-05-03 17:10:05 +020052_concat = u''.join
Armin Ronacher7ceced52008-05-03 10:15:31 +020053try:
54 def _test_gen_bug():
55 raise TypeError(_test_gen_bug)
56 yield None
Armin Ronachercda43df2008-05-03 17:10:05 +020057 _concat(_test_gen_bug())
Thomas Waldmanne0003552013-05-17 23:52:14 +020058except TypeError as _error:
Armin Ronachercda43df2008-05-03 17:10:05 +020059 if not _error.args or _error.args[0] is not _test_gen_bug:
Armin Ronacher7ceced52008-05-03 10:15:31 +020060 def concat(gen):
61 try:
Armin Ronachercda43df2008-05-03 17:10:05 +020062 return _concat(list(gen))
Ian Lewisab014bd2010-10-31 20:29:28 +090063 except Exception:
Armin Ronacher7ceced52008-05-03 10:15:31 +020064 # this hack is needed so that the current frame
65 # does not show up in the traceback.
66 exc_type, exc_value, tb = sys.exc_info()
Thomas Waldmann7d295622013-05-18 00:06:22 +020067 six.reraise(exc_type, exc_value, tb.tb_next)
Armin Ronachercda43df2008-05-03 17:10:05 +020068 else:
69 concat = _concat
Armin Ronacher7ceced52008-05-03 10:15:31 +020070 del _test_gen_bug, _error
71
72
Armin Ronacher0d242be2010-02-10 01:35:13 +010073# if this python version is unable to deal with unicode filenames
74# when passed to encode we let this function encode it properly.
75# This is used in a couple of places. As far as Jinja is concerned
76# filenames are unicode *or* bytestrings in 2.x and unicode only in
77# 3.x because compile cannot handle bytes
78if sys.version_info < (3, 0):
79 def _encode_filename(filename):
80 if isinstance(filename, unicode):
81 return filename.encode('utf-8')
82 return filename
83else:
84 def _encode_filename(filename):
85 assert filename is None or isinstance(filename, str), \
86 'filenames must be strings'
87 return filename
88
89from keyword import iskeyword as is_python_keyword
Armin Ronacher9a0078d2008-08-13 18:24:17 +020090
91
92# common types. These do exist in the special types module too which however
Armin Ronacher0d242be2010-02-10 01:35:13 +010093# does not exist in IronPython out of the box. Also that way we don't have
94# to deal with implementation specific stuff here
Armin Ronacher9a0078d2008-08-13 18:24:17 +020095class _C(object):
96 def method(self): pass
97def _func():
98 yield None
99FunctionType = type(_func)
100GeneratorType = type(_func())
101MethodType = type(_C.method)
Thomas Waldmanne0003552013-05-17 23:52:14 +0200102CodeType = type(_C.method.__code__)
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200103try:
104 raise TypeError()
105except TypeError:
106 _tb = sys.exc_info()[2]
107 TracebackType = type(_tb)
108 FrameType = type(_tb.tb_frame)
109del _C, _tb, _func
110
111
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200112def contextfunction(f):
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200113 """This decorator can be used to mark a function or method context callable.
114 A context callable is passed the active :class:`Context` as first argument when
115 called from the template. This is useful if a function wants to get access
116 to the context or functions provided on the context object. For example
117 a function that returns a sorted list of template variables the current
118 template exports could look like this::
119
Armin Ronacher58f351d2008-05-28 21:30:14 +0200120 @contextfunction
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200121 def get_exported_names(context):
122 return sorted(context.exported_vars)
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200123 """
124 f.contextfunction = True
125 return f
126
127
Armin Ronacher8346bd72010-03-14 19:43:47 +0100128def evalcontextfunction(f):
Florent Xicluna0ec4f762012-02-05 13:09:15 +0100129 """This decorator can be used to mark a function or method as an eval
Armin Ronacher8346bd72010-03-14 19:43:47 +0100130 context callable. This is similar to the :func:`contextfunction`
131 but instead of passing the context, an evaluation context object is
Armin Ronacherfe150f32010-03-15 02:42:41 +0100132 passed. For more information about the eval context, see
133 :ref:`eval-context`.
Armin Ronacher8346bd72010-03-14 19:43:47 +0100134
135 .. versionadded:: 2.4
136 """
137 f.evalcontextfunction = True
138 return f
139
140
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200141def environmentfunction(f):
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200142 """This decorator can be used to mark a function or method as environment
143 callable. This decorator works exactly like the :func:`contextfunction`
144 decorator just that the first argument is the active :class:`Environment`
145 and not context.
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200146 """
147 f.environmentfunction = True
148 return f
149
150
Armin Ronacherd416a972009-02-24 22:58:00 +0100151def internalcode(f):
152 """Marks the function as internally used"""
Thomas Waldmanne0003552013-05-17 23:52:14 +0200153 internal_code.add(f.__code__)
Armin Ronacherd416a972009-02-24 22:58:00 +0100154 return f
155
156
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200157def is_undefined(obj):
158 """Check if the object passed is undefined. This does nothing more than
159 performing an instance check against :class:`Undefined` but looks nicer.
160 This can be used for custom filters or tests that want to react to
161 undefined variables. For example a custom default filter can look like
162 this::
163
164 def default(var, default=''):
165 if is_undefined(var):
166 return default
167 return var
168 """
169 from jinja2.runtime import Undefined
170 return isinstance(obj, Undefined)
171
172
Armin Ronacherba6e25a2008-11-02 15:58:14 +0100173def consume(iterable):
174 """Consumes an iterable without doing anything with it."""
175 for event in iterable:
176 pass
177
178
Armin Ronacher187bde12008-05-01 18:19:16 +0200179def clear_caches():
180 """Jinja2 keeps internal caches for environments and lexers. These are
181 used so that Jinja2 doesn't have to recreate environments and lexers all
182 the time. Normally you don't have to care about that but if you are
183 messuring memory consumption you may want to clean the caches.
184 """
185 from jinja2.environment import _spontaneous_environments
186 from jinja2.lexer import _lexer_cache
187 _spontaneous_environments.clear()
188 _lexer_cache.clear()
189
190
Armin Ronacherf59bac22008-04-20 13:11:43 +0200191def import_string(import_name, silent=False):
Florent Xicluna0ec4f762012-02-05 13:09:15 +0100192 """Imports an object based on a string. This is useful if you want to
Armin Ronacherf59bac22008-04-20 13:11:43 +0200193 use import paths as endpoints or something similar. An import path can
194 be specified either in dotted notation (``xml.sax.saxutils.escape``)
195 or with a colon as object delimiter (``xml.sax.saxutils:escape``).
196
197 If the `silent` is True the return value will be `None` if the import
198 fails.
199
200 :return: imported object
Armin Ronacher9a027f42008-04-17 11:13:40 +0200201 """
Armin Ronacherf59bac22008-04-20 13:11:43 +0200202 try:
203 if ':' in import_name:
204 module, obj = import_name.split(':', 1)
205 elif '.' in import_name:
206 items = import_name.split('.')
207 module = '.'.join(items[:-1])
208 obj = items[-1]
209 else:
210 return __import__(import_name)
211 return getattr(__import__(module, None, None, [obj]), obj)
212 except (ImportError, AttributeError):
213 if not silent:
214 raise
Armin Ronacher9a027f42008-04-17 11:13:40 +0200215
216
Armin Ronacher0faa8612010-02-09 15:04:51 +0100217def open_if_exists(filename, mode='rb'):
Armin Ronacherccae0552008-10-05 23:08:58 +0200218 """Returns a file descriptor for the filename if that file exists,
219 otherwise `None`.
220 """
221 try:
Armin Ronacher790b8a82010-02-10 00:05:46 +0100222 return open(filename, mode)
Thomas Waldmanne0003552013-05-17 23:52:14 +0200223 except IOError as e:
Armin Ronacherccae0552008-10-05 23:08:58 +0200224 if e.errno not in (errno.ENOENT, errno.EISDIR):
225 raise
226
227
Armin Ronacher98dbf5f2010-04-12 15:49:59 +0200228def object_type_repr(obj):
229 """Returns the name of the object's type. For some recognized
230 singletons the name of the object is returned instead. (For
231 example for `None` and `Ellipsis`).
232 """
233 if obj is None:
234 return 'None'
235 elif obj is Ellipsis:
236 return 'Ellipsis'
Armin Ronacher802f4722010-04-20 19:48:46 +0200237 # __builtin__ in 2.x, builtins in 3.x
238 if obj.__class__.__module__ in ('__builtin__', 'builtins'):
Armin Ronacher800ac7f2010-04-20 13:45:11 +0200239 name = obj.__class__.__name__
Armin Ronacher98dbf5f2010-04-12 15:49:59 +0200240 else:
Armin Ronacher800ac7f2010-04-20 13:45:11 +0200241 name = obj.__class__.__module__ + '.' + obj.__class__.__name__
Armin Ronacher98dbf5f2010-04-12 15:49:59 +0200242 return '%s object' % name
243
244
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200245def pformat(obj, verbose=False):
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200246 """Prettyprint an object. Either use the `pretty` library or the
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200247 builtin `pprint`.
248 """
249 try:
250 from pretty import pretty
251 return pretty(obj, verbose=verbose)
252 except ImportError:
253 from pprint import pformat
254 return pformat(obj)
Christoph Hack80909862008-04-14 01:35:10 +0200255
256
Christoph Hack80909862008-04-14 01:35:10 +0200257def urlize(text, trim_url_limit=None, nofollow=False):
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200258 """Converts any URLs in text into clickable links. Works on http://,
Christoph Hack80909862008-04-14 01:35:10 +0200259 https:// and www. links. Links can have trailing punctuation (periods,
260 commas, close-parens) and leading punctuation (opening parens) and
261 it'll still do the right thing.
262
263 If trim_url_limit is not None, the URLs in link text will be limited
264 to trim_url_limit characters.
265
266 If nofollow is True, the URLs in link text will get a rel="nofollow"
267 attribute.
268 """
269 trim_url = lambda x, limit=trim_url_limit: limit is not None \
270 and (x[:limit] + (len(x) >=limit and '...'
271 or '')) or x
Thomas Waldmanne0003552013-05-17 23:52:14 +0200272 words = _word_split_re.split(six.text_type(escape(text)))
Christoph Hack80909862008-04-14 01:35:10 +0200273 nofollow_attr = nofollow and ' rel="nofollow"' or ''
274 for i, word in enumerate(words):
275 match = _punctuation_re.match(word)
276 if match:
277 lead, middle, trail = match.groups()
278 if middle.startswith('www.') or (
279 '@' not in middle and
280 not middle.startswith('http://') and
mozillazg66448932013-03-18 14:27:54 +0800281 not middle.startswith('https://') and
Christoph Hack80909862008-04-14 01:35:10 +0200282 len(middle) > 0 and
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200283 middle[0] in _letters + _digits and (
Christoph Hack80909862008-04-14 01:35:10 +0200284 middle.endswith('.org') or
285 middle.endswith('.net') or
286 middle.endswith('.com')
287 )):
288 middle = '<a href="http://%s"%s>%s</a>' % (middle,
289 nofollow_attr, trim_url(middle))
290 if middle.startswith('http://') or \
291 middle.startswith('https://'):
292 middle = '<a href="%s"%s>%s</a>' % (middle,
293 nofollow_attr, trim_url(middle))
294 if '@' in middle and not middle.startswith('www.') and \
295 not ':' in middle and _simple_email_re.match(middle):
296 middle = '<a href="mailto:%s">%s</a>' % (middle, middle)
297 if lead + middle + trail != word:
298 words[i] = lead + middle + trail
299 return u''.join(words)
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200300
301
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200302def generate_lorem_ipsum(n=5, html=True, min=20, max=100):
303 """Generate some lorem impsum for the template."""
304 from jinja2.constants import LOREM_IPSUM_WORDS
Georg Brandl95632c42009-11-22 18:35:18 +0100305 from random import choice, randrange
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200306 words = LOREM_IPSUM_WORDS.split()
307 result = []
308
Thomas Waldmanne0003552013-05-17 23:52:14 +0200309 for _ in range(n):
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200310 next_capitalized = True
311 last_comma = last_fullstop = 0
312 word = None
313 last = None
314 p = []
315
316 # each paragraph contains out of 20 to 100 words.
Thomas Waldmanne0003552013-05-17 23:52:14 +0200317 for idx, _ in enumerate(range(randrange(min, max))):
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200318 while True:
319 word = choice(words)
320 if word != last:
321 last = word
322 break
323 if next_capitalized:
324 word = word.capitalize()
325 next_capitalized = False
326 # add commas
327 if idx - randrange(3, 8) > last_comma:
328 last_comma = idx
329 last_fullstop += 2
330 word += ','
331 # add end of sentences
332 if idx - randrange(10, 20) > last_fullstop:
333 last_comma = last_fullstop = idx
334 word += '.'
335 next_capitalized = True
336 p.append(word)
337
338 # ensure that the paragraph ends with a dot.
339 p = u' '.join(p)
340 if p.endswith(','):
341 p = p[:-1] + '.'
342 elif not p.endswith('.'):
343 p += '.'
344 result.append(p)
345
346 if not html:
347 return u'\n\n'.join(result)
348 return Markup(u'\n'.join(u'<p>%s</p>' % escape(x) for x in result))
349
350
Armin Ronacher51454012012-01-07 17:47:56 +0100351def unicode_urlencode(obj, charset='utf-8'):
Armin Ronacher1d4c6382012-01-07 17:46:40 +0100352 """URL escapes a single bytestring or unicode string with the
353 given charset if applicable to URL safe quoting under all rules
354 that need to be considered under all supported Python versions.
355
356 If non strings are provided they are converted to their unicode
357 representation first.
358 """
Thomas Waldmann7d295622013-05-18 00:06:22 +0200359 if not isinstance(obj, six.string_types):
Thomas Waldmanne0003552013-05-17 23:52:14 +0200360 obj = six.text_type(obj)
Thomas Waldmann7d295622013-05-18 00:06:22 +0200361 if isinstance(obj, six.text_type):
Armin Ronacher1d4c6382012-01-07 17:46:40 +0100362 obj = obj.encode(charset)
Thomas Waldmanne0003552013-05-17 23:52:14 +0200363 return six.text_type(url_quote(obj))
Armin Ronacher1d4c6382012-01-07 17:46:40 +0100364
365
Armin Ronacher814f6c22008-04-17 15:52:23 +0200366class LRUCache(object):
367 """A simple LRU Cache implementation."""
Armin Ronacher58f351d2008-05-28 21:30:14 +0200368
369 # this is fast for small capacities (something below 1000) but doesn't
370 # scale. But as long as it's only used as storage for templates this
371 # won't do any harm.
Armin Ronacher814f6c22008-04-17 15:52:23 +0200372
373 def __init__(self, capacity):
374 self.capacity = capacity
375 self._mapping = {}
376 self._queue = deque()
Armin Ronacher7962ce72008-05-20 17:52:52 +0200377 self._postinit()
Armin Ronacher814f6c22008-04-17 15:52:23 +0200378
Armin Ronacher7962ce72008-05-20 17:52:52 +0200379 def _postinit(self):
Armin Ronacher814f6c22008-04-17 15:52:23 +0200380 # alias all queue methods for faster lookup
381 self._popleft = self._queue.popleft
382 self._pop = self._queue.pop
383 if hasattr(self._queue, 'remove'):
384 self._remove = self._queue.remove
Armin Ronacher000b4912008-05-01 18:40:15 +0200385 self._wlock = allocate_lock()
Armin Ronacher814f6c22008-04-17 15:52:23 +0200386 self._append = self._queue.append
387
388 def _remove(self, obj):
389 """Python 2.4 compatibility."""
390 for idx, item in enumerate(self._queue):
391 if item == obj:
392 del self._queue[idx]
393 break
394
Armin Ronacher7962ce72008-05-20 17:52:52 +0200395 def __getstate__(self):
396 return {
397 'capacity': self.capacity,
398 '_mapping': self._mapping,
399 '_queue': self._queue
400 }
401
402 def __setstate__(self, d):
403 self.__dict__.update(d)
404 self._postinit()
405
406 def __getnewargs__(self):
407 return (self.capacity,)
408
Armin Ronacher814f6c22008-04-17 15:52:23 +0200409 def copy(self):
Florent Xicluna0ec4f762012-02-05 13:09:15 +0100410 """Return a shallow copy of the instance."""
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200411 rv = self.__class__(self.capacity)
Armin Ronacher814f6c22008-04-17 15:52:23 +0200412 rv._mapping.update(self._mapping)
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200413 rv._queue = deque(self._queue)
Armin Ronacher814f6c22008-04-17 15:52:23 +0200414 return rv
415
416 def get(self, key, default=None):
417 """Return an item from the cache dict or `default`"""
Armin Ronacher000b4912008-05-01 18:40:15 +0200418 try:
Armin Ronacher814f6c22008-04-17 15:52:23 +0200419 return self[key]
Armin Ronacher000b4912008-05-01 18:40:15 +0200420 except KeyError:
421 return default
Armin Ronacher814f6c22008-04-17 15:52:23 +0200422
423 def setdefault(self, key, default=None):
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200424 """Set `default` if the key is not in the cache otherwise
Armin Ronacher814f6c22008-04-17 15:52:23 +0200425 leave unchanged. Return the value of this key.
426 """
Armin Ronacherd4e54382013-04-13 00:38:27 +0100427 self._wlock.acquire()
Armin Ronacher000b4912008-05-01 18:40:15 +0200428 try:
Armin Ronacherd4e54382013-04-13 00:38:27 +0100429 try:
430 return self[key]
431 except KeyError:
432 self[key] = default
433 return default
434 finally:
435 self._wlock.release()
Armin Ronacher814f6c22008-04-17 15:52:23 +0200436
437 def clear(self):
438 """Clear the cache."""
Armin Ronacher000b4912008-05-01 18:40:15 +0200439 self._wlock.acquire()
440 try:
441 self._mapping.clear()
442 self._queue.clear()
443 finally:
444 self._wlock.release()
Armin Ronacher814f6c22008-04-17 15:52:23 +0200445
446 def __contains__(self, key):
447 """Check if a key exists in this cache."""
448 return key in self._mapping
449
450 def __len__(self):
451 """Return the current size of the cache."""
452 return len(self._mapping)
453
454 def __repr__(self):
455 return '<%s %r>' % (
456 self.__class__.__name__,
457 self._mapping
458 )
459
460 def __getitem__(self, key):
461 """Get an item from the cache. Moves the item up so that it has the
462 highest priority then.
463
Florent Xicluna0ec4f762012-02-05 13:09:15 +0100464 Raise a `KeyError` if it does not exist.
Armin Ronacher814f6c22008-04-17 15:52:23 +0200465 """
Armin Ronacherd4e54382013-04-13 00:38:27 +0100466 self._wlock.acquire()
467 try:
468 rv = self._mapping[key]
469 if self._queue[-1] != key:
470 try:
471 self._remove(key)
472 except ValueError:
473 # if something removed the key from the container
474 # when we read, ignore the ValueError that we would
475 # get otherwise.
476 pass
477 self._append(key)
478 return rv
479 finally:
480 self._wlock.release()
Armin Ronacher814f6c22008-04-17 15:52:23 +0200481
482 def __setitem__(self, key, value):
483 """Sets the value for an item. Moves the item up so that it
484 has the highest priority then.
485 """
Armin Ronacher000b4912008-05-01 18:40:15 +0200486 self._wlock.acquire()
487 try:
488 if key in self._mapping:
Armin Ronacherd4e54382013-04-13 00:38:27 +0100489 self._remove(key)
Armin Ronacher000b4912008-05-01 18:40:15 +0200490 elif len(self._mapping) == self.capacity:
491 del self._mapping[self._popleft()]
492 self._append(key)
493 self._mapping[key] = value
494 finally:
495 self._wlock.release()
Armin Ronacher814f6c22008-04-17 15:52:23 +0200496
497 def __delitem__(self, key):
498 """Remove an item from the cache dict.
Florent Xicluna0ec4f762012-02-05 13:09:15 +0100499 Raise a `KeyError` if it does not exist.
Armin Ronacher814f6c22008-04-17 15:52:23 +0200500 """
Armin Ronacher000b4912008-05-01 18:40:15 +0200501 self._wlock.acquire()
502 try:
503 del self._mapping[key]
Armin Ronachere7c72bc2009-09-14 12:20:33 -0700504 try:
505 self._remove(key)
506 except ValueError:
507 # __getitem__ is not locked, it might happen
508 pass
Armin Ronacher000b4912008-05-01 18:40:15 +0200509 finally:
510 self._wlock.release()
Armin Ronacher814f6c22008-04-17 15:52:23 +0200511
Armin Ronachere25f24d2008-05-19 11:20:41 +0200512 def items(self):
513 """Return a list of items."""
514 result = [(key, self._mapping[key]) for key in list(self._queue)]
515 result.reverse()
516 return result
517
518 def iteritems(self):
519 """Iterate over all items."""
520 return iter(self.items())
521
522 def values(self):
523 """Return a list of all values."""
524 return [x[1] for x in self.items()]
525
526 def itervalue(self):
527 """Iterate over all values."""
528 return iter(self.values())
529
530 def keys(self):
531 """Return a list of all keys ordered by most recent usage."""
532 return list(self)
533
534 def iterkeys(self):
535 """Iterate over all keys in the cache dict, ordered by
Armin Ronacher814f6c22008-04-17 15:52:23 +0200536 the most recent usage.
537 """
Armin Ronachere2244882008-05-19 09:25:57 +0200538 return reversed(tuple(self._queue))
Armin Ronacher814f6c22008-04-17 15:52:23 +0200539
Armin Ronachere25f24d2008-05-19 11:20:41 +0200540 __iter__ = iterkeys
541
Armin Ronacher814f6c22008-04-17 15:52:23 +0200542 def __reversed__(self):
543 """Iterate over the values in the cache dict, oldest items
544 coming first.
545 """
Armin Ronachere2244882008-05-19 09:25:57 +0200546 return iter(tuple(self._queue))
Armin Ronacher814f6c22008-04-17 15:52:23 +0200547
548 __copy__ = copy
549
Armin Ronacherbd33f112008-04-18 09:17:32 +0200550
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200551# register the LRU cache as mutable mapping if possible
552try:
553 from collections import MutableMapping
554 MutableMapping.register(LRUCache)
555except ImportError:
556 pass
557
558
Thomas Waldmann7d295622013-05-18 00:06:22 +0200559class Cycler(six.Iterator):
Armin Ronacherccae0552008-10-05 23:08:58 +0200560 """A cycle helper for templates."""
561
562 def __init__(self, *items):
563 if not items:
564 raise RuntimeError('at least one item has to be provided')
565 self.items = items
566 self.reset()
567
568 def reset(self):
569 """Resets the cycle."""
570 self.pos = 0
571
572 @property
573 def current(self):
574 """Returns the current item."""
575 return self.items[self.pos]
576
Thomas Waldmann7d295622013-05-18 00:06:22 +0200577 def __next__(self):
Armin Ronacherccae0552008-10-05 23:08:58 +0200578 """Goes one item ahead and returns it."""
579 rv = self.current
580 self.pos = (self.pos + 1) % len(self.items)
581 return rv
582
583
Armin Ronacherd34eb122008-10-13 23:47:51 +0200584class Joiner(object):
585 """A joining helper for templates."""
586
587 def __init__(self, sep=u', '):
588 self.sep = sep
589 self.used = False
590
591 def __call__(self):
592 if not self.used:
593 self.used = True
594 return u''
595 return self.sep
596
597
Armin Ronacherf9f5f262010-08-17 11:57:07 +0200598# try markupsafe first, if that fails go with Jinja2's bundled version
599# of markupsafe. Markupsafe was previously Jinja2's implementation of
Florent Xicluna0ec4f762012-02-05 13:09:15 +0100600# the Markup object but was moved into a separate package in a patchlevel
Armin Ronacherf9f5f262010-08-17 11:57:07 +0200601# release
Armin Ronacherbd33f112008-04-18 09:17:32 +0200602try:
Armin Ronacherf9f5f262010-08-17 11:57:07 +0200603 from markupsafe import Markup, escape, soft_unicode
Armin Ronacherbd33f112008-04-18 09:17:32 +0200604except ImportError:
Armin Ronacherf9f5f262010-08-17 11:57:07 +0200605 from jinja2._markupsafe import Markup, escape, soft_unicode
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200606
607
608# partials
609try:
610 from functools import partial
611except ImportError:
612 class partial(object):
613 def __init__(self, _func, *args, **kwargs):
Benjamin Wiegand228c1832008-04-28 18:09:27 +0200614 self._func = _func
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200615 self._args = args
616 self._kwargs = kwargs
617 def __call__(self, *args, **kwargs):
618 kwargs.update(self._kwargs)
619 return self._func(*(self._args + args), **kwargs)