blob: 402718d9d0bb7c6091caea8c57a0fa30ae57b91b [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
Armin Ronacher000b4912008-05-01 18:40:15 +020014try:
Armin Ronacher1d4c6382012-01-07 17:46:40 +010015 from urllib.parse import quote_from_bytes as url_quote
16except ImportError:
17 from urllib import quote as url_quote
18try:
Armin Ronacher000b4912008-05-01 18:40:15 +020019 from thread import allocate_lock
20except ImportError:
21 from dummy_thread import allocate_lock
Armin Ronacher814f6c22008-04-17 15:52:23 +020022from collections import deque
Armin Ronacher18c6ca02008-04-17 10:03:29 +020023from itertools import imap
Armin Ronacher8edbe492008-04-10 20:43:43 +020024
25
Armin Ronacherbe4ae242008-04-18 09:49:08 +020026_word_split_re = re.compile(r'(\s+)')
27_punctuation_re = re.compile(
28 '^(?P<lead>(?:%s)*)(?P<middle>.*?)(?P<trail>(?:%s)*)$' % (
29 '|'.join(imap(re.escape, ('(', '<', '&lt;'))),
30 '|'.join(imap(re.escape, ('.', ',', ')', '>', '\n', '&gt;')))
31 )
32)
33_simple_email_re = re.compile(r'^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$')
Armin Ronacher76c280b2008-05-04 12:31:48 +020034_striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
35_entity_re = re.compile(r'&([^;]+);')
Armin Ronacher9a0078d2008-08-13 18:24:17 +020036_letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
37_digits = '0123456789'
Armin Ronacherbe4ae242008-04-18 09:49:08 +020038
Armin Ronacher7259c762008-04-30 13:03:59 +020039# special singleton representing missing values for the runtime
40missing = type('MissingType', (), {'__repr__': lambda x: 'missing'})()
41
Armin Ronacherd416a972009-02-24 22:58:00 +010042# internal code
43internal_code = set()
44
Armin Ronacher7259c762008-04-30 13:03:59 +020045
Armin Ronacher7ceced52008-05-03 10:15:31 +020046# concatenate a list of strings and convert them to unicode.
47# unfortunately there is a bug in python 2.4 and lower that causes
48# unicode.join trash the traceback.
Armin Ronachercda43df2008-05-03 17:10:05 +020049_concat = u''.join
Armin Ronacher7ceced52008-05-03 10:15:31 +020050try:
51 def _test_gen_bug():
52 raise TypeError(_test_gen_bug)
53 yield None
Armin Ronachercda43df2008-05-03 17:10:05 +020054 _concat(_test_gen_bug())
Armin Ronacher7ceced52008-05-03 10:15:31 +020055except TypeError, _error:
Armin Ronachercda43df2008-05-03 17:10:05 +020056 if not _error.args or _error.args[0] is not _test_gen_bug:
Armin Ronacher7ceced52008-05-03 10:15:31 +020057 def concat(gen):
58 try:
Armin Ronachercda43df2008-05-03 17:10:05 +020059 return _concat(list(gen))
Ian Lewisab014bd2010-10-31 20:29:28 +090060 except Exception:
Armin Ronacher7ceced52008-05-03 10:15:31 +020061 # this hack is needed so that the current frame
62 # does not show up in the traceback.
63 exc_type, exc_value, tb = sys.exc_info()
64 raise exc_type, exc_value, tb.tb_next
Armin Ronachercda43df2008-05-03 17:10:05 +020065 else:
66 concat = _concat
Armin Ronacher7ceced52008-05-03 10:15:31 +020067 del _test_gen_bug, _error
68
69
Florent Xicluna0ec4f762012-02-05 13:09:15 +010070# for python 2.x we create ourselves a next() function that does the
Armin Ronacherbd357722009-08-05 20:25:06 +020071# basics without exception catching.
72try:
73 next = next
74except NameError:
75 def next(x):
76 return x.next()
77
78
Armin Ronacher0d242be2010-02-10 01:35:13 +010079# if this python version is unable to deal with unicode filenames
80# when passed to encode we let this function encode it properly.
81# This is used in a couple of places. As far as Jinja is concerned
82# filenames are unicode *or* bytestrings in 2.x and unicode only in
83# 3.x because compile cannot handle bytes
84if sys.version_info < (3, 0):
85 def _encode_filename(filename):
86 if isinstance(filename, unicode):
87 return filename.encode('utf-8')
88 return filename
89else:
90 def _encode_filename(filename):
91 assert filename is None or isinstance(filename, str), \
92 'filenames must be strings'
93 return filename
94
95from keyword import iskeyword as is_python_keyword
Armin Ronacher9a0078d2008-08-13 18:24:17 +020096
97
98# common types. These do exist in the special types module too which however
Armin Ronacher0d242be2010-02-10 01:35:13 +010099# does not exist in IronPython out of the box. Also that way we don't have
100# to deal with implementation specific stuff here
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200101class _C(object):
102 def method(self): pass
103def _func():
104 yield None
105FunctionType = type(_func)
106GeneratorType = type(_func())
107MethodType = type(_C.method)
108CodeType = type(_C.method.func_code)
109try:
110 raise TypeError()
111except TypeError:
112 _tb = sys.exc_info()[2]
113 TracebackType = type(_tb)
114 FrameType = type(_tb.tb_frame)
115del _C, _tb, _func
116
117
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200118def contextfunction(f):
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200119 """This decorator can be used to mark a function or method context callable.
120 A context callable is passed the active :class:`Context` as first argument when
121 called from the template. This is useful if a function wants to get access
122 to the context or functions provided on the context object. For example
123 a function that returns a sorted list of template variables the current
124 template exports could look like this::
125
Armin Ronacher58f351d2008-05-28 21:30:14 +0200126 @contextfunction
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200127 def get_exported_names(context):
128 return sorted(context.exported_vars)
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200129 """
130 f.contextfunction = True
131 return f
132
133
Armin Ronacher8346bd72010-03-14 19:43:47 +0100134def evalcontextfunction(f):
Florent Xicluna0ec4f762012-02-05 13:09:15 +0100135 """This decorator can be used to mark a function or method as an eval
Armin Ronacher8346bd72010-03-14 19:43:47 +0100136 context callable. This is similar to the :func:`contextfunction`
137 but instead of passing the context, an evaluation context object is
Armin Ronacherfe150f32010-03-15 02:42:41 +0100138 passed. For more information about the eval context, see
139 :ref:`eval-context`.
Armin Ronacher8346bd72010-03-14 19:43:47 +0100140
141 .. versionadded:: 2.4
142 """
143 f.evalcontextfunction = True
144 return f
145
146
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200147def environmentfunction(f):
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200148 """This decorator can be used to mark a function or method as environment
149 callable. This decorator works exactly like the :func:`contextfunction`
150 decorator just that the first argument is the active :class:`Environment`
151 and not context.
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200152 """
153 f.environmentfunction = True
154 return f
155
156
Armin Ronacherd416a972009-02-24 22:58:00 +0100157def internalcode(f):
158 """Marks the function as internally used"""
159 internal_code.add(f.func_code)
160 return f
161
162
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200163def is_undefined(obj):
164 """Check if the object passed is undefined. This does nothing more than
165 performing an instance check against :class:`Undefined` but looks nicer.
166 This can be used for custom filters or tests that want to react to
167 undefined variables. For example a custom default filter can look like
168 this::
169
170 def default(var, default=''):
171 if is_undefined(var):
172 return default
173 return var
174 """
175 from jinja2.runtime import Undefined
176 return isinstance(obj, Undefined)
177
178
Armin Ronacherba6e25a2008-11-02 15:58:14 +0100179def consume(iterable):
180 """Consumes an iterable without doing anything with it."""
181 for event in iterable:
182 pass
183
184
Armin Ronacher187bde12008-05-01 18:19:16 +0200185def clear_caches():
186 """Jinja2 keeps internal caches for environments and lexers. These are
187 used so that Jinja2 doesn't have to recreate environments and lexers all
188 the time. Normally you don't have to care about that but if you are
189 messuring memory consumption you may want to clean the caches.
190 """
191 from jinja2.environment import _spontaneous_environments
192 from jinja2.lexer import _lexer_cache
193 _spontaneous_environments.clear()
194 _lexer_cache.clear()
195
196
Armin Ronacherf59bac22008-04-20 13:11:43 +0200197def import_string(import_name, silent=False):
Florent Xicluna0ec4f762012-02-05 13:09:15 +0100198 """Imports an object based on a string. This is useful if you want to
Armin Ronacherf59bac22008-04-20 13:11:43 +0200199 use import paths as endpoints or something similar. An import path can
200 be specified either in dotted notation (``xml.sax.saxutils.escape``)
201 or with a colon as object delimiter (``xml.sax.saxutils:escape``).
202
203 If the `silent` is True the return value will be `None` if the import
204 fails.
205
206 :return: imported object
Armin Ronacher9a027f42008-04-17 11:13:40 +0200207 """
Armin Ronacherf59bac22008-04-20 13:11:43 +0200208 try:
209 if ':' in import_name:
210 module, obj = import_name.split(':', 1)
211 elif '.' in import_name:
212 items = import_name.split('.')
213 module = '.'.join(items[:-1])
214 obj = items[-1]
215 else:
216 return __import__(import_name)
217 return getattr(__import__(module, None, None, [obj]), obj)
218 except (ImportError, AttributeError):
219 if not silent:
220 raise
Armin Ronacher9a027f42008-04-17 11:13:40 +0200221
222
Armin Ronacher0faa8612010-02-09 15:04:51 +0100223def open_if_exists(filename, mode='rb'):
Armin Ronacherccae0552008-10-05 23:08:58 +0200224 """Returns a file descriptor for the filename if that file exists,
225 otherwise `None`.
226 """
227 try:
Armin Ronacher790b8a82010-02-10 00:05:46 +0100228 return open(filename, mode)
Armin Ronacherccae0552008-10-05 23:08:58 +0200229 except IOError, e:
230 if e.errno not in (errno.ENOENT, errno.EISDIR):
231 raise
232
233
Armin Ronacher98dbf5f2010-04-12 15:49:59 +0200234def object_type_repr(obj):
235 """Returns the name of the object's type. For some recognized
236 singletons the name of the object is returned instead. (For
237 example for `None` and `Ellipsis`).
238 """
239 if obj is None:
240 return 'None'
241 elif obj is Ellipsis:
242 return 'Ellipsis'
Armin Ronacher802f4722010-04-20 19:48:46 +0200243 # __builtin__ in 2.x, builtins in 3.x
244 if obj.__class__.__module__ in ('__builtin__', 'builtins'):
Armin Ronacher800ac7f2010-04-20 13:45:11 +0200245 name = obj.__class__.__name__
Armin Ronacher98dbf5f2010-04-12 15:49:59 +0200246 else:
Armin Ronacher800ac7f2010-04-20 13:45:11 +0200247 name = obj.__class__.__module__ + '.' + obj.__class__.__name__
Armin Ronacher98dbf5f2010-04-12 15:49:59 +0200248 return '%s object' % name
249
250
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200251def pformat(obj, verbose=False):
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200252 """Prettyprint an object. Either use the `pretty` library or the
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200253 builtin `pprint`.
254 """
255 try:
256 from pretty import pretty
257 return pretty(obj, verbose=verbose)
258 except ImportError:
259 from pprint import pformat
260 return pformat(obj)
Christoph Hack80909862008-04-14 01:35:10 +0200261
262
Christoph Hack80909862008-04-14 01:35:10 +0200263def urlize(text, trim_url_limit=None, nofollow=False):
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200264 """Converts any URLs in text into clickable links. Works on http://,
Christoph Hack80909862008-04-14 01:35:10 +0200265 https:// and www. links. Links can have trailing punctuation (periods,
266 commas, close-parens) and leading punctuation (opening parens) and
267 it'll still do the right thing.
268
269 If trim_url_limit is not None, the URLs in link text will be limited
270 to trim_url_limit characters.
271
272 If nofollow is True, the URLs in link text will get a rel="nofollow"
273 attribute.
274 """
275 trim_url = lambda x, limit=trim_url_limit: limit is not None \
276 and (x[:limit] + (len(x) >=limit and '...'
277 or '')) or x
Armin Ronacherd9342dc2008-11-17 00:35:30 +0100278 words = _word_split_re.split(unicode(escape(text)))
Christoph Hack80909862008-04-14 01:35:10 +0200279 nofollow_attr = nofollow and ' rel="nofollow"' or ''
280 for i, word in enumerate(words):
281 match = _punctuation_re.match(word)
282 if match:
283 lead, middle, trail = match.groups()
284 if middle.startswith('www.') or (
285 '@' not in middle and
286 not middle.startswith('http://') and
mozillazg66448932013-03-18 14:27:54 +0800287 not middle.startswith('https://') and
Christoph Hack80909862008-04-14 01:35:10 +0200288 len(middle) > 0 and
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200289 middle[0] in _letters + _digits and (
Christoph Hack80909862008-04-14 01:35:10 +0200290 middle.endswith('.org') or
291 middle.endswith('.net') or
292 middle.endswith('.com')
293 )):
294 middle = '<a href="http://%s"%s>%s</a>' % (middle,
295 nofollow_attr, trim_url(middle))
296 if middle.startswith('http://') or \
297 middle.startswith('https://'):
298 middle = '<a href="%s"%s>%s</a>' % (middle,
299 nofollow_attr, trim_url(middle))
300 if '@' in middle and not middle.startswith('www.') and \
301 not ':' in middle and _simple_email_re.match(middle):
302 middle = '<a href="mailto:%s">%s</a>' % (middle, middle)
303 if lead + middle + trail != word:
304 words[i] = lead + middle + trail
305 return u''.join(words)
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200306
307
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200308def generate_lorem_ipsum(n=5, html=True, min=20, max=100):
309 """Generate some lorem impsum for the template."""
310 from jinja2.constants import LOREM_IPSUM_WORDS
Georg Brandl95632c42009-11-22 18:35:18 +0100311 from random import choice, randrange
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200312 words = LOREM_IPSUM_WORDS.split()
313 result = []
314
315 for _ in xrange(n):
316 next_capitalized = True
317 last_comma = last_fullstop = 0
318 word = None
319 last = None
320 p = []
321
322 # each paragraph contains out of 20 to 100 words.
323 for idx, _ in enumerate(xrange(randrange(min, max))):
324 while True:
325 word = choice(words)
326 if word != last:
327 last = word
328 break
329 if next_capitalized:
330 word = word.capitalize()
331 next_capitalized = False
332 # add commas
333 if idx - randrange(3, 8) > last_comma:
334 last_comma = idx
335 last_fullstop += 2
336 word += ','
337 # add end of sentences
338 if idx - randrange(10, 20) > last_fullstop:
339 last_comma = last_fullstop = idx
340 word += '.'
341 next_capitalized = True
342 p.append(word)
343
344 # ensure that the paragraph ends with a dot.
345 p = u' '.join(p)
346 if p.endswith(','):
347 p = p[:-1] + '.'
348 elif not p.endswith('.'):
349 p += '.'
350 result.append(p)
351
352 if not html:
353 return u'\n\n'.join(result)
354 return Markup(u'\n'.join(u'<p>%s</p>' % escape(x) for x in result))
355
356
Armin Ronacher51454012012-01-07 17:47:56 +0100357def unicode_urlencode(obj, charset='utf-8'):
Armin Ronacher1d4c6382012-01-07 17:46:40 +0100358 """URL escapes a single bytestring or unicode string with the
359 given charset if applicable to URL safe quoting under all rules
360 that need to be considered under all supported Python versions.
361
362 If non strings are provided they are converted to their unicode
363 representation first.
364 """
365 if not isinstance(obj, basestring):
366 obj = unicode(obj)
367 if isinstance(obj, unicode):
368 obj = obj.encode(charset)
369 return unicode(url_quote(obj))
370
371
Armin Ronacher814f6c22008-04-17 15:52:23 +0200372class LRUCache(object):
373 """A simple LRU Cache implementation."""
Armin Ronacher58f351d2008-05-28 21:30:14 +0200374
375 # this is fast for small capacities (something below 1000) but doesn't
376 # scale. But as long as it's only used as storage for templates this
377 # won't do any harm.
Armin Ronacher814f6c22008-04-17 15:52:23 +0200378
379 def __init__(self, capacity):
380 self.capacity = capacity
381 self._mapping = {}
382 self._queue = deque()
Armin Ronacher7962ce72008-05-20 17:52:52 +0200383 self._postinit()
Armin Ronacher814f6c22008-04-17 15:52:23 +0200384
Armin Ronacher7962ce72008-05-20 17:52:52 +0200385 def _postinit(self):
Armin Ronacher814f6c22008-04-17 15:52:23 +0200386 # alias all queue methods for faster lookup
387 self._popleft = self._queue.popleft
388 self._pop = self._queue.pop
389 if hasattr(self._queue, 'remove'):
390 self._remove = self._queue.remove
Armin Ronacher000b4912008-05-01 18:40:15 +0200391 self._wlock = allocate_lock()
Armin Ronacher814f6c22008-04-17 15:52:23 +0200392 self._append = self._queue.append
393
394 def _remove(self, obj):
395 """Python 2.4 compatibility."""
396 for idx, item in enumerate(self._queue):
397 if item == obj:
398 del self._queue[idx]
399 break
400
Armin Ronacher7962ce72008-05-20 17:52:52 +0200401 def __getstate__(self):
402 return {
403 'capacity': self.capacity,
404 '_mapping': self._mapping,
405 '_queue': self._queue
406 }
407
408 def __setstate__(self, d):
409 self.__dict__.update(d)
410 self._postinit()
411
412 def __getnewargs__(self):
413 return (self.capacity,)
414
Armin Ronacher814f6c22008-04-17 15:52:23 +0200415 def copy(self):
Florent Xicluna0ec4f762012-02-05 13:09:15 +0100416 """Return a shallow copy of the instance."""
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200417 rv = self.__class__(self.capacity)
Armin Ronacher814f6c22008-04-17 15:52:23 +0200418 rv._mapping.update(self._mapping)
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200419 rv._queue = deque(self._queue)
Armin Ronacher814f6c22008-04-17 15:52:23 +0200420 return rv
421
422 def get(self, key, default=None):
423 """Return an item from the cache dict or `default`"""
Armin Ronacher000b4912008-05-01 18:40:15 +0200424 try:
Armin Ronacher814f6c22008-04-17 15:52:23 +0200425 return self[key]
Armin Ronacher000b4912008-05-01 18:40:15 +0200426 except KeyError:
427 return default
Armin Ronacher814f6c22008-04-17 15:52:23 +0200428
429 def setdefault(self, key, default=None):
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200430 """Set `default` if the key is not in the cache otherwise
Armin Ronacher814f6c22008-04-17 15:52:23 +0200431 leave unchanged. Return the value of this key.
432 """
Armin Ronacher000b4912008-05-01 18:40:15 +0200433 try:
Armin Ronacher814f6c22008-04-17 15:52:23 +0200434 return self[key]
Armin Ronacher000b4912008-05-01 18:40:15 +0200435 except KeyError:
436 self[key] = default
437 return default
Armin Ronacher814f6c22008-04-17 15:52:23 +0200438
439 def clear(self):
440 """Clear the cache."""
Armin Ronacher000b4912008-05-01 18:40:15 +0200441 self._wlock.acquire()
442 try:
443 self._mapping.clear()
444 self._queue.clear()
445 finally:
446 self._wlock.release()
Armin Ronacher814f6c22008-04-17 15:52:23 +0200447
448 def __contains__(self, key):
449 """Check if a key exists in this cache."""
450 return key in self._mapping
451
452 def __len__(self):
453 """Return the current size of the cache."""
454 return len(self._mapping)
455
456 def __repr__(self):
457 return '<%s %r>' % (
458 self.__class__.__name__,
459 self._mapping
460 )
461
462 def __getitem__(self, key):
463 """Get an item from the cache. Moves the item up so that it has the
464 highest priority then.
465
Florent Xicluna0ec4f762012-02-05 13:09:15 +0100466 Raise a `KeyError` if it does not exist.
Armin Ronacher814f6c22008-04-17 15:52:23 +0200467 """
468 rv = self._mapping[key]
469 if self._queue[-1] != key:
Armin Ronacher8de6f182009-01-12 11:08:26 +0100470 try:
471 self._remove(key)
Armin Ronachere7c72bc2009-09-14 12:20:33 -0700472 except ValueError:
Armin Ronacher8de6f182009-01-12 11:08:26 +0100473 # if something removed the key from the container
474 # when we read, ignore the ValueError that we would
475 # get otherwise.
476 pass
Armin Ronacher814f6c22008-04-17 15:52:23 +0200477 self._append(key)
478 return rv
479
480 def __setitem__(self, key, value):
481 """Sets the value for an item. Moves the item up so that it
482 has the highest priority then.
483 """
Armin Ronacher000b4912008-05-01 18:40:15 +0200484 self._wlock.acquire()
485 try:
486 if key in self._mapping:
Armin Ronacher74230e62009-10-25 12:46:31 +0100487 try:
488 self._remove(key)
489 except ValueError:
490 # __getitem__ is not locked, it might happen
491 pass
Armin Ronacher000b4912008-05-01 18:40:15 +0200492 elif len(self._mapping) == self.capacity:
493 del self._mapping[self._popleft()]
494 self._append(key)
495 self._mapping[key] = value
496 finally:
497 self._wlock.release()
Armin Ronacher814f6c22008-04-17 15:52:23 +0200498
499 def __delitem__(self, key):
500 """Remove an item from the cache dict.
Florent Xicluna0ec4f762012-02-05 13:09:15 +0100501 Raise a `KeyError` if it does not exist.
Armin Ronacher814f6c22008-04-17 15:52:23 +0200502 """
Armin Ronacher000b4912008-05-01 18:40:15 +0200503 self._wlock.acquire()
504 try:
505 del self._mapping[key]
Armin Ronachere7c72bc2009-09-14 12:20:33 -0700506 try:
507 self._remove(key)
508 except ValueError:
509 # __getitem__ is not locked, it might happen
510 pass
Armin Ronacher000b4912008-05-01 18:40:15 +0200511 finally:
512 self._wlock.release()
Armin Ronacher814f6c22008-04-17 15:52:23 +0200513
Armin Ronachere25f24d2008-05-19 11:20:41 +0200514 def items(self):
515 """Return a list of items."""
516 result = [(key, self._mapping[key]) for key in list(self._queue)]
517 result.reverse()
518 return result
519
520 def iteritems(self):
521 """Iterate over all items."""
522 return iter(self.items())
523
524 def values(self):
525 """Return a list of all values."""
526 return [x[1] for x in self.items()]
527
528 def itervalue(self):
529 """Iterate over all values."""
530 return iter(self.values())
531
532 def keys(self):
533 """Return a list of all keys ordered by most recent usage."""
534 return list(self)
535
536 def iterkeys(self):
537 """Iterate over all keys in the cache dict, ordered by
Armin Ronacher814f6c22008-04-17 15:52:23 +0200538 the most recent usage.
539 """
Armin Ronachere2244882008-05-19 09:25:57 +0200540 return reversed(tuple(self._queue))
Armin Ronacher814f6c22008-04-17 15:52:23 +0200541
Armin Ronachere25f24d2008-05-19 11:20:41 +0200542 __iter__ = iterkeys
543
Armin Ronacher814f6c22008-04-17 15:52:23 +0200544 def __reversed__(self):
545 """Iterate over the values in the cache dict, oldest items
546 coming first.
547 """
Armin Ronachere2244882008-05-19 09:25:57 +0200548 return iter(tuple(self._queue))
Armin Ronacher814f6c22008-04-17 15:52:23 +0200549
550 __copy__ = copy
551
Armin Ronacherbd33f112008-04-18 09:17:32 +0200552
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200553# register the LRU cache as mutable mapping if possible
554try:
555 from collections import MutableMapping
556 MutableMapping.register(LRUCache)
557except ImportError:
558 pass
559
560
Armin Ronacherccae0552008-10-05 23:08:58 +0200561class Cycler(object):
562 """A cycle helper for templates."""
563
564 def __init__(self, *items):
565 if not items:
566 raise RuntimeError('at least one item has to be provided')
567 self.items = items
568 self.reset()
569
570 def reset(self):
571 """Resets the cycle."""
572 self.pos = 0
573
574 @property
575 def current(self):
576 """Returns the current item."""
577 return self.items[self.pos]
578
579 def next(self):
580 """Goes one item ahead and returns it."""
581 rv = self.current
582 self.pos = (self.pos + 1) % len(self.items)
583 return rv
584
585
Armin Ronacherd34eb122008-10-13 23:47:51 +0200586class Joiner(object):
587 """A joining helper for templates."""
588
589 def __init__(self, sep=u', '):
590 self.sep = sep
591 self.used = False
592
593 def __call__(self):
594 if not self.used:
595 self.used = True
596 return u''
597 return self.sep
598
599
Armin Ronacherf9f5f262010-08-17 11:57:07 +0200600# try markupsafe first, if that fails go with Jinja2's bundled version
601# of markupsafe. Markupsafe was previously Jinja2's implementation of
Florent Xicluna0ec4f762012-02-05 13:09:15 +0100602# the Markup object but was moved into a separate package in a patchlevel
Armin Ronacherf9f5f262010-08-17 11:57:07 +0200603# release
Armin Ronacherbd33f112008-04-18 09:17:32 +0200604try:
Armin Ronacherf9f5f262010-08-17 11:57:07 +0200605 from markupsafe import Markup, escape, soft_unicode
Armin Ronacherbd33f112008-04-18 09:17:32 +0200606except ImportError:
Armin Ronacherf9f5f262010-08-17 11:57:07 +0200607 from jinja2._markupsafe import Markup, escape, soft_unicode
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200608
609
610# partials
611try:
612 from functools import partial
613except ImportError:
614 class partial(object):
615 def __init__(self, _func, *args, **kwargs):
Benjamin Wiegand228c1832008-04-28 18:09:27 +0200616 self._func = _func
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200617 self._args = args
618 self._kwargs = kwargs
619 def __call__(self, *args, **kwargs):
620 kwargs.update(self._kwargs)
621 return self._func(*(self._args + args), **kwargs)