blob: 121a008b2e7b25adf3761304650162ca4f3b4220 [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
Armin Ronacher000b4912008-05-01 18:40:15 +020015try:
Armin Ronacher1d4c6382012-01-07 17:46:40 +010016 from urllib.parse import quote_from_bytes as url_quote
17except ImportError:
18 from urllib import quote as url_quote
19try:
Armin Ronacher000b4912008-05-01 18:40:15 +020020 from thread import allocate_lock
21except ImportError:
22 from dummy_thread import allocate_lock
Armin Ronacher814f6c22008-04-17 15:52:23 +020023from collections import deque
Armin Ronacher18c6ca02008-04-17 10:03:29 +020024from itertools import imap
Armin Ronacher8edbe492008-04-10 20:43:43 +020025
26
Armin Ronacherbe4ae242008-04-18 09:49:08 +020027_word_split_re = re.compile(r'(\s+)')
28_punctuation_re = re.compile(
29 '^(?P<lead>(?:%s)*)(?P<middle>.*?)(?P<trail>(?:%s)*)$' % (
30 '|'.join(imap(re.escape, ('(', '<', '&lt;'))),
31 '|'.join(imap(re.escape, ('.', ',', ')', '>', '\n', '&gt;')))
32 )
33)
34_simple_email_re = re.compile(r'^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$')
Armin Ronacher76c280b2008-05-04 12:31:48 +020035_striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
36_entity_re = re.compile(r'&([^;]+);')
Armin Ronacher9a0078d2008-08-13 18:24:17 +020037_letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
38_digits = '0123456789'
Armin Ronacherbe4ae242008-04-18 09:49:08 +020039
Armin Ronacher7259c762008-04-30 13:03:59 +020040# special singleton representing missing values for the runtime
41missing = type('MissingType', (), {'__repr__': lambda x: 'missing'})()
42
Armin Ronacherd416a972009-02-24 22:58:00 +010043# internal code
44internal_code = set()
45
Armin Ronacher7259c762008-04-30 13:03:59 +020046
Armin Ronacher7ceced52008-05-03 10:15:31 +020047# concatenate a list of strings and convert them to unicode.
48# unfortunately there is a bug in python 2.4 and lower that causes
49# unicode.join trash the traceback.
Armin Ronachercda43df2008-05-03 17:10:05 +020050_concat = u''.join
Armin Ronacher7ceced52008-05-03 10:15:31 +020051try:
52 def _test_gen_bug():
53 raise TypeError(_test_gen_bug)
54 yield None
Armin Ronachercda43df2008-05-03 17:10:05 +020055 _concat(_test_gen_bug())
Thomas Waldmanne0003552013-05-17 23:52:14 +020056except TypeError as _error:
Armin Ronachercda43df2008-05-03 17:10:05 +020057 if not _error.args or _error.args[0] is not _test_gen_bug:
Armin Ronacher7ceced52008-05-03 10:15:31 +020058 def concat(gen):
59 try:
Armin Ronachercda43df2008-05-03 17:10:05 +020060 return _concat(list(gen))
Ian Lewisab014bd2010-10-31 20:29:28 +090061 except Exception:
Armin Ronacher7ceced52008-05-03 10:15:31 +020062 # this hack is needed so that the current frame
63 # does not show up in the traceback.
64 exc_type, exc_value, tb = sys.exc_info()
65 raise exc_type, exc_value, tb.tb_next
Armin Ronachercda43df2008-05-03 17:10:05 +020066 else:
67 concat = _concat
Armin Ronacher7ceced52008-05-03 10:15:31 +020068 del _test_gen_bug, _error
69
70
Florent Xicluna0ec4f762012-02-05 13:09:15 +010071# for python 2.x we create ourselves a next() function that does the
Armin Ronacherbd357722009-08-05 20:25:06 +020072# basics without exception catching.
73try:
74 next = next
75except NameError:
76 def next(x):
Thomas Waldmanne0003552013-05-17 23:52:14 +020077 return six.advance_iterator(x)
Armin Ronacherbd357722009-08-05 20:25:06 +020078
79
Armin Ronacher0d242be2010-02-10 01:35:13 +010080# if this python version is unable to deal with unicode filenames
81# when passed to encode we let this function encode it properly.
82# This is used in a couple of places. As far as Jinja is concerned
83# filenames are unicode *or* bytestrings in 2.x and unicode only in
84# 3.x because compile cannot handle bytes
85if sys.version_info < (3, 0):
86 def _encode_filename(filename):
87 if isinstance(filename, unicode):
88 return filename.encode('utf-8')
89 return filename
90else:
91 def _encode_filename(filename):
92 assert filename is None or isinstance(filename, str), \
93 'filenames must be strings'
94 return filename
95
96from keyword import iskeyword as is_python_keyword
Armin Ronacher9a0078d2008-08-13 18:24:17 +020097
98
99# common types. These do exist in the special types module too which however
Armin Ronacher0d242be2010-02-10 01:35:13 +0100100# does not exist in IronPython out of the box. Also that way we don't have
101# to deal with implementation specific stuff here
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200102class _C(object):
103 def method(self): pass
104def _func():
105 yield None
106FunctionType = type(_func)
107GeneratorType = type(_func())
108MethodType = type(_C.method)
Thomas Waldmanne0003552013-05-17 23:52:14 +0200109CodeType = type(_C.method.__code__)
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200110try:
111 raise TypeError()
112except TypeError:
113 _tb = sys.exc_info()[2]
114 TracebackType = type(_tb)
115 FrameType = type(_tb.tb_frame)
116del _C, _tb, _func
117
118
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200119def contextfunction(f):
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200120 """This decorator can be used to mark a function or method context callable.
121 A context callable is passed the active :class:`Context` as first argument when
122 called from the template. This is useful if a function wants to get access
123 to the context or functions provided on the context object. For example
124 a function that returns a sorted list of template variables the current
125 template exports could look like this::
126
Armin Ronacher58f351d2008-05-28 21:30:14 +0200127 @contextfunction
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200128 def get_exported_names(context):
129 return sorted(context.exported_vars)
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200130 """
131 f.contextfunction = True
132 return f
133
134
Armin Ronacher8346bd72010-03-14 19:43:47 +0100135def evalcontextfunction(f):
Florent Xicluna0ec4f762012-02-05 13:09:15 +0100136 """This decorator can be used to mark a function or method as an eval
Armin Ronacher8346bd72010-03-14 19:43:47 +0100137 context callable. This is similar to the :func:`contextfunction`
138 but instead of passing the context, an evaluation context object is
Armin Ronacherfe150f32010-03-15 02:42:41 +0100139 passed. For more information about the eval context, see
140 :ref:`eval-context`.
Armin Ronacher8346bd72010-03-14 19:43:47 +0100141
142 .. versionadded:: 2.4
143 """
144 f.evalcontextfunction = True
145 return f
146
147
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200148def environmentfunction(f):
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200149 """This decorator can be used to mark a function or method as environment
150 callable. This decorator works exactly like the :func:`contextfunction`
151 decorator just that the first argument is the active :class:`Environment`
152 and not context.
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200153 """
154 f.environmentfunction = True
155 return f
156
157
Armin Ronacherd416a972009-02-24 22:58:00 +0100158def internalcode(f):
159 """Marks the function as internally used"""
Thomas Waldmanne0003552013-05-17 23:52:14 +0200160 internal_code.add(f.__code__)
Armin Ronacherd416a972009-02-24 22:58:00 +0100161 return f
162
163
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200164def is_undefined(obj):
165 """Check if the object passed is undefined. This does nothing more than
166 performing an instance check against :class:`Undefined` but looks nicer.
167 This can be used for custom filters or tests that want to react to
168 undefined variables. For example a custom default filter can look like
169 this::
170
171 def default(var, default=''):
172 if is_undefined(var):
173 return default
174 return var
175 """
176 from jinja2.runtime import Undefined
177 return isinstance(obj, Undefined)
178
179
Armin Ronacherba6e25a2008-11-02 15:58:14 +0100180def consume(iterable):
181 """Consumes an iterable without doing anything with it."""
182 for event in iterable:
183 pass
184
185
Armin Ronacher187bde12008-05-01 18:19:16 +0200186def clear_caches():
187 """Jinja2 keeps internal caches for environments and lexers. These are
188 used so that Jinja2 doesn't have to recreate environments and lexers all
189 the time. Normally you don't have to care about that but if you are
190 messuring memory consumption you may want to clean the caches.
191 """
192 from jinja2.environment import _spontaneous_environments
193 from jinja2.lexer import _lexer_cache
194 _spontaneous_environments.clear()
195 _lexer_cache.clear()
196
197
Armin Ronacherf59bac22008-04-20 13:11:43 +0200198def import_string(import_name, silent=False):
Florent Xicluna0ec4f762012-02-05 13:09:15 +0100199 """Imports an object based on a string. This is useful if you want to
Armin Ronacherf59bac22008-04-20 13:11:43 +0200200 use import paths as endpoints or something similar. An import path can
201 be specified either in dotted notation (``xml.sax.saxutils.escape``)
202 or with a colon as object delimiter (``xml.sax.saxutils:escape``).
203
204 If the `silent` is True the return value will be `None` if the import
205 fails.
206
207 :return: imported object
Armin Ronacher9a027f42008-04-17 11:13:40 +0200208 """
Armin Ronacherf59bac22008-04-20 13:11:43 +0200209 try:
210 if ':' in import_name:
211 module, obj = import_name.split(':', 1)
212 elif '.' in import_name:
213 items = import_name.split('.')
214 module = '.'.join(items[:-1])
215 obj = items[-1]
216 else:
217 return __import__(import_name)
218 return getattr(__import__(module, None, None, [obj]), obj)
219 except (ImportError, AttributeError):
220 if not silent:
221 raise
Armin Ronacher9a027f42008-04-17 11:13:40 +0200222
223
Armin Ronacher0faa8612010-02-09 15:04:51 +0100224def open_if_exists(filename, mode='rb'):
Armin Ronacherccae0552008-10-05 23:08:58 +0200225 """Returns a file descriptor for the filename if that file exists,
226 otherwise `None`.
227 """
228 try:
Armin Ronacher790b8a82010-02-10 00:05:46 +0100229 return open(filename, mode)
Thomas Waldmanne0003552013-05-17 23:52:14 +0200230 except IOError as e:
Armin Ronacherccae0552008-10-05 23:08:58 +0200231 if e.errno not in (errno.ENOENT, errno.EISDIR):
232 raise
233
234
Armin Ronacher98dbf5f2010-04-12 15:49:59 +0200235def object_type_repr(obj):
236 """Returns the name of the object's type. For some recognized
237 singletons the name of the object is returned instead. (For
238 example for `None` and `Ellipsis`).
239 """
240 if obj is None:
241 return 'None'
242 elif obj is Ellipsis:
243 return 'Ellipsis'
Armin Ronacher802f4722010-04-20 19:48:46 +0200244 # __builtin__ in 2.x, builtins in 3.x
245 if obj.__class__.__module__ in ('__builtin__', 'builtins'):
Armin Ronacher800ac7f2010-04-20 13:45:11 +0200246 name = obj.__class__.__name__
Armin Ronacher98dbf5f2010-04-12 15:49:59 +0200247 else:
Armin Ronacher800ac7f2010-04-20 13:45:11 +0200248 name = obj.__class__.__module__ + '.' + obj.__class__.__name__
Armin Ronacher98dbf5f2010-04-12 15:49:59 +0200249 return '%s object' % name
250
251
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200252def pformat(obj, verbose=False):
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200253 """Prettyprint an object. Either use the `pretty` library or the
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200254 builtin `pprint`.
255 """
256 try:
257 from pretty import pretty
258 return pretty(obj, verbose=verbose)
259 except ImportError:
260 from pprint import pformat
261 return pformat(obj)
Christoph Hack80909862008-04-14 01:35:10 +0200262
263
Christoph Hack80909862008-04-14 01:35:10 +0200264def urlize(text, trim_url_limit=None, nofollow=False):
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200265 """Converts any URLs in text into clickable links. Works on http://,
Christoph Hack80909862008-04-14 01:35:10 +0200266 https:// and www. links. Links can have trailing punctuation (periods,
267 commas, close-parens) and leading punctuation (opening parens) and
268 it'll still do the right thing.
269
270 If trim_url_limit is not None, the URLs in link text will be limited
271 to trim_url_limit characters.
272
273 If nofollow is True, the URLs in link text will get a rel="nofollow"
274 attribute.
275 """
276 trim_url = lambda x, limit=trim_url_limit: limit is not None \
277 and (x[:limit] + (len(x) >=limit and '...'
278 or '')) or x
Thomas Waldmanne0003552013-05-17 23:52:14 +0200279 words = _word_split_re.split(six.text_type(escape(text)))
Christoph Hack80909862008-04-14 01:35:10 +0200280 nofollow_attr = nofollow and ' rel="nofollow"' or ''
281 for i, word in enumerate(words):
282 match = _punctuation_re.match(word)
283 if match:
284 lead, middle, trail = match.groups()
285 if middle.startswith('www.') or (
286 '@' not in middle and
287 not middle.startswith('http://') and
mozillazg66448932013-03-18 14:27:54 +0800288 not middle.startswith('https://') and
Christoph Hack80909862008-04-14 01:35:10 +0200289 len(middle) > 0 and
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200290 middle[0] in _letters + _digits and (
Christoph Hack80909862008-04-14 01:35:10 +0200291 middle.endswith('.org') or
292 middle.endswith('.net') or
293 middle.endswith('.com')
294 )):
295 middle = '<a href="http://%s"%s>%s</a>' % (middle,
296 nofollow_attr, trim_url(middle))
297 if middle.startswith('http://') or \
298 middle.startswith('https://'):
299 middle = '<a href="%s"%s>%s</a>' % (middle,
300 nofollow_attr, trim_url(middle))
301 if '@' in middle and not middle.startswith('www.') and \
302 not ':' in middle and _simple_email_re.match(middle):
303 middle = '<a href="mailto:%s">%s</a>' % (middle, middle)
304 if lead + middle + trail != word:
305 words[i] = lead + middle + trail
306 return u''.join(words)
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200307
308
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200309def generate_lorem_ipsum(n=5, html=True, min=20, max=100):
310 """Generate some lorem impsum for the template."""
311 from jinja2.constants import LOREM_IPSUM_WORDS
Georg Brandl95632c42009-11-22 18:35:18 +0100312 from random import choice, randrange
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200313 words = LOREM_IPSUM_WORDS.split()
314 result = []
315
Thomas Waldmanne0003552013-05-17 23:52:14 +0200316 for _ in range(n):
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200317 next_capitalized = True
318 last_comma = last_fullstop = 0
319 word = None
320 last = None
321 p = []
322
323 # each paragraph contains out of 20 to 100 words.
Thomas Waldmanne0003552013-05-17 23:52:14 +0200324 for idx, _ in enumerate(range(randrange(min, max))):
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200325 while True:
326 word = choice(words)
327 if word != last:
328 last = word
329 break
330 if next_capitalized:
331 word = word.capitalize()
332 next_capitalized = False
333 # add commas
334 if idx - randrange(3, 8) > last_comma:
335 last_comma = idx
336 last_fullstop += 2
337 word += ','
338 # add end of sentences
339 if idx - randrange(10, 20) > last_fullstop:
340 last_comma = last_fullstop = idx
341 word += '.'
342 next_capitalized = True
343 p.append(word)
344
345 # ensure that the paragraph ends with a dot.
346 p = u' '.join(p)
347 if p.endswith(','):
348 p = p[:-1] + '.'
349 elif not p.endswith('.'):
350 p += '.'
351 result.append(p)
352
353 if not html:
354 return u'\n\n'.join(result)
355 return Markup(u'\n'.join(u'<p>%s</p>' % escape(x) for x in result))
356
357
Armin Ronacher51454012012-01-07 17:47:56 +0100358def unicode_urlencode(obj, charset='utf-8'):
Armin Ronacher1d4c6382012-01-07 17:46:40 +0100359 """URL escapes a single bytestring or unicode string with the
360 given charset if applicable to URL safe quoting under all rules
361 that need to be considered under all supported Python versions.
362
363 If non strings are provided they are converted to their unicode
364 representation first.
365 """
366 if not isinstance(obj, basestring):
Thomas Waldmanne0003552013-05-17 23:52:14 +0200367 obj = six.text_type(obj)
Armin Ronacher1d4c6382012-01-07 17:46:40 +0100368 if isinstance(obj, unicode):
369 obj = obj.encode(charset)
Thomas Waldmanne0003552013-05-17 23:52:14 +0200370 return six.text_type(url_quote(obj))
Armin Ronacher1d4c6382012-01-07 17:46:40 +0100371
372
Armin Ronacher814f6c22008-04-17 15:52:23 +0200373class LRUCache(object):
374 """A simple LRU Cache implementation."""
Armin Ronacher58f351d2008-05-28 21:30:14 +0200375
376 # this is fast for small capacities (something below 1000) but doesn't
377 # scale. But as long as it's only used as storage for templates this
378 # won't do any harm.
Armin Ronacher814f6c22008-04-17 15:52:23 +0200379
380 def __init__(self, capacity):
381 self.capacity = capacity
382 self._mapping = {}
383 self._queue = deque()
Armin Ronacher7962ce72008-05-20 17:52:52 +0200384 self._postinit()
Armin Ronacher814f6c22008-04-17 15:52:23 +0200385
Armin Ronacher7962ce72008-05-20 17:52:52 +0200386 def _postinit(self):
Armin Ronacher814f6c22008-04-17 15:52:23 +0200387 # alias all queue methods for faster lookup
388 self._popleft = self._queue.popleft
389 self._pop = self._queue.pop
390 if hasattr(self._queue, 'remove'):
391 self._remove = self._queue.remove
Armin Ronacher000b4912008-05-01 18:40:15 +0200392 self._wlock = allocate_lock()
Armin Ronacher814f6c22008-04-17 15:52:23 +0200393 self._append = self._queue.append
394
395 def _remove(self, obj):
396 """Python 2.4 compatibility."""
397 for idx, item in enumerate(self._queue):
398 if item == obj:
399 del self._queue[idx]
400 break
401
Armin Ronacher7962ce72008-05-20 17:52:52 +0200402 def __getstate__(self):
403 return {
404 'capacity': self.capacity,
405 '_mapping': self._mapping,
406 '_queue': self._queue
407 }
408
409 def __setstate__(self, d):
410 self.__dict__.update(d)
411 self._postinit()
412
413 def __getnewargs__(self):
414 return (self.capacity,)
415
Armin Ronacher814f6c22008-04-17 15:52:23 +0200416 def copy(self):
Florent Xicluna0ec4f762012-02-05 13:09:15 +0100417 """Return a shallow copy of the instance."""
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200418 rv = self.__class__(self.capacity)
Armin Ronacher814f6c22008-04-17 15:52:23 +0200419 rv._mapping.update(self._mapping)
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200420 rv._queue = deque(self._queue)
Armin Ronacher814f6c22008-04-17 15:52:23 +0200421 return rv
422
423 def get(self, key, default=None):
424 """Return an item from the cache dict or `default`"""
Armin Ronacher000b4912008-05-01 18:40:15 +0200425 try:
Armin Ronacher814f6c22008-04-17 15:52:23 +0200426 return self[key]
Armin Ronacher000b4912008-05-01 18:40:15 +0200427 except KeyError:
428 return default
Armin Ronacher814f6c22008-04-17 15:52:23 +0200429
430 def setdefault(self, key, default=None):
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200431 """Set `default` if the key is not in the cache otherwise
Armin Ronacher814f6c22008-04-17 15:52:23 +0200432 leave unchanged. Return the value of this key.
433 """
Armin Ronacherd4e54382013-04-13 00:38:27 +0100434 self._wlock.acquire()
Armin Ronacher000b4912008-05-01 18:40:15 +0200435 try:
Armin Ronacherd4e54382013-04-13 00:38:27 +0100436 try:
437 return self[key]
438 except KeyError:
439 self[key] = default
440 return default
441 finally:
442 self._wlock.release()
Armin Ronacher814f6c22008-04-17 15:52:23 +0200443
444 def clear(self):
445 """Clear the cache."""
Armin Ronacher000b4912008-05-01 18:40:15 +0200446 self._wlock.acquire()
447 try:
448 self._mapping.clear()
449 self._queue.clear()
450 finally:
451 self._wlock.release()
Armin Ronacher814f6c22008-04-17 15:52:23 +0200452
453 def __contains__(self, key):
454 """Check if a key exists in this cache."""
455 return key in self._mapping
456
457 def __len__(self):
458 """Return the current size of the cache."""
459 return len(self._mapping)
460
461 def __repr__(self):
462 return '<%s %r>' % (
463 self.__class__.__name__,
464 self._mapping
465 )
466
467 def __getitem__(self, key):
468 """Get an item from the cache. Moves the item up so that it has the
469 highest priority then.
470
Florent Xicluna0ec4f762012-02-05 13:09:15 +0100471 Raise a `KeyError` if it does not exist.
Armin Ronacher814f6c22008-04-17 15:52:23 +0200472 """
Armin Ronacherd4e54382013-04-13 00:38:27 +0100473 self._wlock.acquire()
474 try:
475 rv = self._mapping[key]
476 if self._queue[-1] != key:
477 try:
478 self._remove(key)
479 except ValueError:
480 # if something removed the key from the container
481 # when we read, ignore the ValueError that we would
482 # get otherwise.
483 pass
484 self._append(key)
485 return rv
486 finally:
487 self._wlock.release()
Armin Ronacher814f6c22008-04-17 15:52:23 +0200488
489 def __setitem__(self, key, value):
490 """Sets the value for an item. Moves the item up so that it
491 has the highest priority then.
492 """
Armin Ronacher000b4912008-05-01 18:40:15 +0200493 self._wlock.acquire()
494 try:
495 if key in self._mapping:
Armin Ronacherd4e54382013-04-13 00:38:27 +0100496 self._remove(key)
Armin Ronacher000b4912008-05-01 18:40:15 +0200497 elif len(self._mapping) == self.capacity:
498 del self._mapping[self._popleft()]
499 self._append(key)
500 self._mapping[key] = value
501 finally:
502 self._wlock.release()
Armin Ronacher814f6c22008-04-17 15:52:23 +0200503
504 def __delitem__(self, key):
505 """Remove an item from the cache dict.
Florent Xicluna0ec4f762012-02-05 13:09:15 +0100506 Raise a `KeyError` if it does not exist.
Armin Ronacher814f6c22008-04-17 15:52:23 +0200507 """
Armin Ronacher000b4912008-05-01 18:40:15 +0200508 self._wlock.acquire()
509 try:
510 del self._mapping[key]
Armin Ronachere7c72bc2009-09-14 12:20:33 -0700511 try:
512 self._remove(key)
513 except ValueError:
514 # __getitem__ is not locked, it might happen
515 pass
Armin Ronacher000b4912008-05-01 18:40:15 +0200516 finally:
517 self._wlock.release()
Armin Ronacher814f6c22008-04-17 15:52:23 +0200518
Armin Ronachere25f24d2008-05-19 11:20:41 +0200519 def items(self):
520 """Return a list of items."""
521 result = [(key, self._mapping[key]) for key in list(self._queue)]
522 result.reverse()
523 return result
524
525 def iteritems(self):
526 """Iterate over all items."""
527 return iter(self.items())
528
529 def values(self):
530 """Return a list of all values."""
531 return [x[1] for x in self.items()]
532
533 def itervalue(self):
534 """Iterate over all values."""
535 return iter(self.values())
536
537 def keys(self):
538 """Return a list of all keys ordered by most recent usage."""
539 return list(self)
540
541 def iterkeys(self):
542 """Iterate over all keys in the cache dict, ordered by
Armin Ronacher814f6c22008-04-17 15:52:23 +0200543 the most recent usage.
544 """
Armin Ronachere2244882008-05-19 09:25:57 +0200545 return reversed(tuple(self._queue))
Armin Ronacher814f6c22008-04-17 15:52:23 +0200546
Armin Ronachere25f24d2008-05-19 11:20:41 +0200547 __iter__ = iterkeys
548
Armin Ronacher814f6c22008-04-17 15:52:23 +0200549 def __reversed__(self):
550 """Iterate over the values in the cache dict, oldest items
551 coming first.
552 """
Armin Ronachere2244882008-05-19 09:25:57 +0200553 return iter(tuple(self._queue))
Armin Ronacher814f6c22008-04-17 15:52:23 +0200554
555 __copy__ = copy
556
Armin Ronacherbd33f112008-04-18 09:17:32 +0200557
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200558# register the LRU cache as mutable mapping if possible
559try:
560 from collections import MutableMapping
561 MutableMapping.register(LRUCache)
562except ImportError:
563 pass
564
565
Armin Ronacherccae0552008-10-05 23:08:58 +0200566class Cycler(object):
567 """A cycle helper for templates."""
568
569 def __init__(self, *items):
570 if not items:
571 raise RuntimeError('at least one item has to be provided')
572 self.items = items
573 self.reset()
574
575 def reset(self):
576 """Resets the cycle."""
577 self.pos = 0
578
579 @property
580 def current(self):
581 """Returns the current item."""
582 return self.items[self.pos]
583
584 def next(self):
585 """Goes one item ahead and returns it."""
586 rv = self.current
587 self.pos = (self.pos + 1) % len(self.items)
588 return rv
589
590
Armin Ronacherd34eb122008-10-13 23:47:51 +0200591class Joiner(object):
592 """A joining helper for templates."""
593
594 def __init__(self, sep=u', '):
595 self.sep = sep
596 self.used = False
597
598 def __call__(self):
599 if not self.used:
600 self.used = True
601 return u''
602 return self.sep
603
604
Armin Ronacherf9f5f262010-08-17 11:57:07 +0200605# try markupsafe first, if that fails go with Jinja2's bundled version
606# of markupsafe. Markupsafe was previously Jinja2's implementation of
Florent Xicluna0ec4f762012-02-05 13:09:15 +0100607# the Markup object but was moved into a separate package in a patchlevel
Armin Ronacherf9f5f262010-08-17 11:57:07 +0200608# release
Armin Ronacherbd33f112008-04-18 09:17:32 +0200609try:
Armin Ronacherf9f5f262010-08-17 11:57:07 +0200610 from markupsafe import Markup, escape, soft_unicode
Armin Ronacherbd33f112008-04-18 09:17:32 +0200611except ImportError:
Armin Ronacherf9f5f262010-08-17 11:57:07 +0200612 from jinja2._markupsafe import Markup, escape, soft_unicode
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200613
614
615# partials
616try:
617 from functools import partial
618except ImportError:
619 class partial(object):
620 def __init__(self, _func, *args, **kwargs):
Benjamin Wiegand228c1832008-04-28 18:09:27 +0200621 self._func = _func
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200622 self._args = args
623 self._kwargs = kwargs
624 def __call__(self, *args, **kwargs):
625 kwargs.update(self._kwargs)
626 return self._func(*(self._args + args), **kwargs)