blob: 1fd6ec5dfd8215552bfb27b182a50e1a90aa07de [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:
15 from thread import allocate_lock
16except ImportError:
17 from dummy_thread import allocate_lock
Armin Ronacher814f6c22008-04-17 15:52:23 +020018from collections import deque
Armin Ronacher18c6ca02008-04-17 10:03:29 +020019from itertools import imap
Armin Ronacher8edbe492008-04-10 20:43:43 +020020
21
Armin Ronacherbe4ae242008-04-18 09:49:08 +020022_word_split_re = re.compile(r'(\s+)')
23_punctuation_re = re.compile(
24 '^(?P<lead>(?:%s)*)(?P<middle>.*?)(?P<trail>(?:%s)*)$' % (
25 '|'.join(imap(re.escape, ('(', '<', '&lt;'))),
26 '|'.join(imap(re.escape, ('.', ',', ')', '>', '\n', '&gt;')))
27 )
28)
29_simple_email_re = re.compile(r'^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$')
Armin Ronacher76c280b2008-05-04 12:31:48 +020030_striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
31_entity_re = re.compile(r'&([^;]+);')
Armin Ronacher9a0078d2008-08-13 18:24:17 +020032_letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
33_digits = '0123456789'
Armin Ronacherbe4ae242008-04-18 09:49:08 +020034
Armin Ronacher7259c762008-04-30 13:03:59 +020035# special singleton representing missing values for the runtime
36missing = type('MissingType', (), {'__repr__': lambda x: 'missing'})()
37
Armin Ronacherd416a972009-02-24 22:58:00 +010038# internal code
39internal_code = set()
40
Armin Ronacher7259c762008-04-30 13:03:59 +020041
Armin Ronacher7ceced52008-05-03 10:15:31 +020042# concatenate a list of strings and convert them to unicode.
43# unfortunately there is a bug in python 2.4 and lower that causes
44# unicode.join trash the traceback.
Armin Ronachercda43df2008-05-03 17:10:05 +020045_concat = u''.join
Armin Ronacher7ceced52008-05-03 10:15:31 +020046try:
47 def _test_gen_bug():
48 raise TypeError(_test_gen_bug)
49 yield None
Armin Ronachercda43df2008-05-03 17:10:05 +020050 _concat(_test_gen_bug())
Armin Ronacher7ceced52008-05-03 10:15:31 +020051except TypeError, _error:
Armin Ronachercda43df2008-05-03 17:10:05 +020052 if not _error.args or _error.args[0] is not _test_gen_bug:
Armin Ronacher7ceced52008-05-03 10:15:31 +020053 def concat(gen):
54 try:
Armin Ronachercda43df2008-05-03 17:10:05 +020055 return _concat(list(gen))
Armin Ronacher7ceced52008-05-03 10:15:31 +020056 except:
57 # this hack is needed so that the current frame
58 # does not show up in the traceback.
59 exc_type, exc_value, tb = sys.exc_info()
60 raise exc_type, exc_value, tb.tb_next
Armin Ronachercda43df2008-05-03 17:10:05 +020061 else:
62 concat = _concat
Armin Ronacher7ceced52008-05-03 10:15:31 +020063 del _test_gen_bug, _error
64
65
Armin Ronacherbd357722009-08-05 20:25:06 +020066# for python 2.x we create outselves a next() function that does the
67# basics without exception catching.
68try:
69 next = next
70except NameError:
71 def next(x):
72 return x.next()
73
74
Armin Ronacher0d242be2010-02-10 01:35:13 +010075# if this python version is unable to deal with unicode filenames
76# when passed to encode we let this function encode it properly.
77# This is used in a couple of places. As far as Jinja is concerned
78# filenames are unicode *or* bytestrings in 2.x and unicode only in
79# 3.x because compile cannot handle bytes
80if sys.version_info < (3, 0):
81 def _encode_filename(filename):
82 if isinstance(filename, unicode):
83 return filename.encode('utf-8')
84 return filename
85else:
86 def _encode_filename(filename):
87 assert filename is None or isinstance(filename, str), \
88 'filenames must be strings'
89 return filename
90
91from keyword import iskeyword as is_python_keyword
Armin Ronacher9a0078d2008-08-13 18:24:17 +020092
93
94# common types. These do exist in the special types module too which however
Armin Ronacher0d242be2010-02-10 01:35:13 +010095# does not exist in IronPython out of the box. Also that way we don't have
96# to deal with implementation specific stuff here
Armin Ronacher9a0078d2008-08-13 18:24:17 +020097class _C(object):
98 def method(self): pass
99def _func():
100 yield None
101FunctionType = type(_func)
102GeneratorType = type(_func())
103MethodType = type(_C.method)
104CodeType = type(_C.method.func_code)
105try:
106 raise TypeError()
107except TypeError:
108 _tb = sys.exc_info()[2]
109 TracebackType = type(_tb)
110 FrameType = type(_tb.tb_frame)
111del _C, _tb, _func
112
113
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200114def contextfunction(f):
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200115 """This decorator can be used to mark a function or method context callable.
116 A context callable is passed the active :class:`Context` as first argument when
117 called from the template. This is useful if a function wants to get access
118 to the context or functions provided on the context object. For example
119 a function that returns a sorted list of template variables the current
120 template exports could look like this::
121
Armin Ronacher58f351d2008-05-28 21:30:14 +0200122 @contextfunction
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200123 def get_exported_names(context):
124 return sorted(context.exported_vars)
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200125 """
126 f.contextfunction = True
127 return f
128
129
Armin Ronacher8346bd72010-03-14 19:43:47 +0100130def evalcontextfunction(f):
131 """This decoraotr can be used to mark a function or method as an eval
132 context callable. This is similar to the :func:`contextfunction`
133 but instead of passing the context, an evaluation context object is
Armin Ronacherfe150f32010-03-15 02:42:41 +0100134 passed. For more information about the eval context, see
135 :ref:`eval-context`.
Armin Ronacher8346bd72010-03-14 19:43:47 +0100136
137 .. versionadded:: 2.4
138 """
139 f.evalcontextfunction = True
140 return f
141
142
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200143def environmentfunction(f):
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200144 """This decorator can be used to mark a function or method as environment
145 callable. This decorator works exactly like the :func:`contextfunction`
146 decorator just that the first argument is the active :class:`Environment`
147 and not context.
Armin Ronacher203bfcb2008-04-24 21:54:44 +0200148 """
149 f.environmentfunction = True
150 return f
151
152
Armin Ronacherd416a972009-02-24 22:58:00 +0100153def internalcode(f):
154 """Marks the function as internally used"""
155 internal_code.add(f.func_code)
156 return f
157
158
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200159def is_undefined(obj):
160 """Check if the object passed is undefined. This does nothing more than
161 performing an instance check against :class:`Undefined` but looks nicer.
162 This can be used for custom filters or tests that want to react to
163 undefined variables. For example a custom default filter can look like
164 this::
165
166 def default(var, default=''):
167 if is_undefined(var):
168 return default
169 return var
170 """
171 from jinja2.runtime import Undefined
172 return isinstance(obj, Undefined)
173
174
Armin Ronacherba6e25a2008-11-02 15:58:14 +0100175def consume(iterable):
176 """Consumes an iterable without doing anything with it."""
177 for event in iterable:
178 pass
179
180
Armin Ronacher187bde12008-05-01 18:19:16 +0200181def clear_caches():
182 """Jinja2 keeps internal caches for environments and lexers. These are
183 used so that Jinja2 doesn't have to recreate environments and lexers all
184 the time. Normally you don't have to care about that but if you are
185 messuring memory consumption you may want to clean the caches.
186 """
187 from jinja2.environment import _spontaneous_environments
188 from jinja2.lexer import _lexer_cache
189 _spontaneous_environments.clear()
190 _lexer_cache.clear()
191
192
Armin Ronacherf59bac22008-04-20 13:11:43 +0200193def import_string(import_name, silent=False):
194 """Imports an object based on a string. This use useful if you want to
195 use import paths as endpoints or something similar. An import path can
196 be specified either in dotted notation (``xml.sax.saxutils.escape``)
197 or with a colon as object delimiter (``xml.sax.saxutils:escape``).
198
199 If the `silent` is True the return value will be `None` if the import
200 fails.
201
202 :return: imported object
Armin Ronacher9a027f42008-04-17 11:13:40 +0200203 """
Armin Ronacherf59bac22008-04-20 13:11:43 +0200204 try:
205 if ':' in import_name:
206 module, obj = import_name.split(':', 1)
207 elif '.' in import_name:
208 items = import_name.split('.')
209 module = '.'.join(items[:-1])
210 obj = items[-1]
211 else:
212 return __import__(import_name)
213 return getattr(__import__(module, None, None, [obj]), obj)
214 except (ImportError, AttributeError):
215 if not silent:
216 raise
Armin Ronacher9a027f42008-04-17 11:13:40 +0200217
218
Armin Ronacher0faa8612010-02-09 15:04:51 +0100219def open_if_exists(filename, mode='rb'):
Armin Ronacherccae0552008-10-05 23:08:58 +0200220 """Returns a file descriptor for the filename if that file exists,
221 otherwise `None`.
222 """
223 try:
Armin Ronacher790b8a82010-02-10 00:05:46 +0100224 return open(filename, mode)
Armin Ronacherccae0552008-10-05 23:08:58 +0200225 except IOError, e:
226 if e.errno not in (errno.ENOENT, errno.EISDIR):
227 raise
228
229
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200230def pformat(obj, verbose=False):
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200231 """Prettyprint an object. Either use the `pretty` library or the
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200232 builtin `pprint`.
233 """
234 try:
235 from pretty import pretty
236 return pretty(obj, verbose=verbose)
237 except ImportError:
238 from pprint import pformat
239 return pformat(obj)
Christoph Hack80909862008-04-14 01:35:10 +0200240
241
Christoph Hack80909862008-04-14 01:35:10 +0200242def urlize(text, trim_url_limit=None, nofollow=False):
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200243 """Converts any URLs in text into clickable links. Works on http://,
Christoph Hack80909862008-04-14 01:35:10 +0200244 https:// and www. links. Links can have trailing punctuation (periods,
245 commas, close-parens) and leading punctuation (opening parens) and
246 it'll still do the right thing.
247
248 If trim_url_limit is not None, the URLs in link text will be limited
249 to trim_url_limit characters.
250
251 If nofollow is True, the URLs in link text will get a rel="nofollow"
252 attribute.
253 """
254 trim_url = lambda x, limit=trim_url_limit: limit is not None \
255 and (x[:limit] + (len(x) >=limit and '...'
256 or '')) or x
Armin Ronacherd9342dc2008-11-17 00:35:30 +0100257 words = _word_split_re.split(unicode(escape(text)))
Christoph Hack80909862008-04-14 01:35:10 +0200258 nofollow_attr = nofollow and ' rel="nofollow"' or ''
259 for i, word in enumerate(words):
260 match = _punctuation_re.match(word)
261 if match:
262 lead, middle, trail = match.groups()
263 if middle.startswith('www.') or (
264 '@' not in middle and
265 not middle.startswith('http://') and
266 len(middle) > 0 and
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200267 middle[0] in _letters + _digits and (
Christoph Hack80909862008-04-14 01:35:10 +0200268 middle.endswith('.org') or
269 middle.endswith('.net') or
270 middle.endswith('.com')
271 )):
272 middle = '<a href="http://%s"%s>%s</a>' % (middle,
273 nofollow_attr, trim_url(middle))
274 if middle.startswith('http://') or \
275 middle.startswith('https://'):
276 middle = '<a href="%s"%s>%s</a>' % (middle,
277 nofollow_attr, trim_url(middle))
278 if '@' in middle and not middle.startswith('www.') and \
279 not ':' in middle and _simple_email_re.match(middle):
280 middle = '<a href="mailto:%s">%s</a>' % (middle, middle)
281 if lead + middle + trail != word:
282 words[i] = lead + middle + trail
283 return u''.join(words)
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200284
285
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200286def generate_lorem_ipsum(n=5, html=True, min=20, max=100):
287 """Generate some lorem impsum for the template."""
288 from jinja2.constants import LOREM_IPSUM_WORDS
Georg Brandl95632c42009-11-22 18:35:18 +0100289 from random import choice, randrange
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200290 words = LOREM_IPSUM_WORDS.split()
291 result = []
292
293 for _ in xrange(n):
294 next_capitalized = True
295 last_comma = last_fullstop = 0
296 word = None
297 last = None
298 p = []
299
300 # each paragraph contains out of 20 to 100 words.
301 for idx, _ in enumerate(xrange(randrange(min, max))):
302 while True:
303 word = choice(words)
304 if word != last:
305 last = word
306 break
307 if next_capitalized:
308 word = word.capitalize()
309 next_capitalized = False
310 # add commas
311 if idx - randrange(3, 8) > last_comma:
312 last_comma = idx
313 last_fullstop += 2
314 word += ','
315 # add end of sentences
316 if idx - randrange(10, 20) > last_fullstop:
317 last_comma = last_fullstop = idx
318 word += '.'
319 next_capitalized = True
320 p.append(word)
321
322 # ensure that the paragraph ends with a dot.
323 p = u' '.join(p)
324 if p.endswith(','):
325 p = p[:-1] + '.'
326 elif not p.endswith('.'):
327 p += '.'
328 result.append(p)
329
330 if not html:
331 return u'\n\n'.join(result)
332 return Markup(u'\n'.join(u'<p>%s</p>' % escape(x) for x in result))
333
334
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200335class Markup(unicode):
Armin Ronacher58f351d2008-05-28 21:30:14 +0200336 r"""Marks a string as being safe for inclusion in HTML/XML output without
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200337 needing to be escaped. This implements the `__html__` interface a couple
Armin Ronacher58f351d2008-05-28 21:30:14 +0200338 of frameworks and web applications use. :class:`Markup` is a direct
339 subclass of `unicode` and provides all the methods of `unicode` just that
340 it escapes arguments passed and always returns `Markup`.
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200341
342 The `escape` function returns markup objects so that double escaping can't
Armin Ronacher88e1cb72008-09-08 23:55:32 +0200343 happen. If you want to use autoescaping in Jinja just enable the
344 autoescaping feature in the environment.
Armin Ronacher58f351d2008-05-28 21:30:14 +0200345
346 The constructor of the :class:`Markup` class can be used for three
347 different things: When passed an unicode object it's assumed to be safe,
348 when passed an object with an HTML representation (has an `__html__`
349 method) that representation is used, otherwise the object passed is
350 converted into a unicode string and then assumed to be safe:
351
352 >>> Markup("Hello <em>World</em>!")
353 Markup(u'Hello <em>World</em>!')
354 >>> class Foo(object):
355 ... def __html__(self):
356 ... return '<a href="#">foo</a>'
357 ...
358 >>> Markup(Foo())
359 Markup(u'<a href="#">foo</a>')
360
361 If you want object passed being always treated as unsafe you can use the
362 :meth:`escape` classmethod to create a :class:`Markup` object:
363
364 >>> Markup.escape("Hello <em>World</em>!")
365 Markup(u'Hello &lt;em&gt;World&lt;/em&gt;!')
366
367 Operations on a markup string are markup aware which means that all
368 arguments are passed through the :func:`escape` function:
369
370 >>> em = Markup("<em>%s</em>")
371 >>> em % "foo & bar"
372 Markup(u'<em>foo &amp; bar</em>')
373 >>> strong = Markup("<strong>%(text)s</strong>")
374 >>> strong % {'text': '<blink>hacker here</blink>'}
375 Markup(u'<strong>&lt;blink&gt;hacker here&lt;/blink&gt;</strong>')
376 >>> Markup("<em>Hello</em> ") + "<foo>"
377 Markup(u'<em>Hello</em> &lt;foo&gt;')
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200378 """
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200379 __slots__ = ()
380
Armin Ronacher3ef20432008-06-09 18:27:19 +0200381 def __new__(cls, base=u'', encoding=None, errors='strict'):
Armin Ronacher4e6f9a22008-05-23 23:57:38 +0200382 if hasattr(base, '__html__'):
383 base = base.__html__()
Armin Ronacher3ef20432008-06-09 18:27:19 +0200384 if encoding is None:
385 return unicode.__new__(cls, base)
386 return unicode.__new__(cls, base, encoding, errors)
Armin Ronacher4e6f9a22008-05-23 23:57:38 +0200387
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200388 def __html__(self):
389 return self
390
391 def __add__(self, other):
392 if hasattr(other, '__html__') or isinstance(other, basestring):
393 return self.__class__(unicode(self) + unicode(escape(other)))
394 return NotImplemented
395
396 def __radd__(self, other):
397 if hasattr(other, '__html__') or isinstance(other, basestring):
398 return self.__class__(unicode(escape(other)) + unicode(self))
399 return NotImplemented
400
401 def __mul__(self, num):
Armin Ronacherd71fff02008-05-26 23:57:07 +0200402 if isinstance(num, (int, long)):
403 return self.__class__(unicode.__mul__(self, num))
404 return NotImplemented
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200405 __rmul__ = __mul__
406
407 def __mod__(self, arg):
408 if isinstance(arg, tuple):
409 arg = tuple(imap(_MarkupEscapeHelper, arg))
410 else:
411 arg = _MarkupEscapeHelper(arg)
412 return self.__class__(unicode.__mod__(self, arg))
413
414 def __repr__(self):
415 return '%s(%s)' % (
416 self.__class__.__name__,
417 unicode.__repr__(self)
418 )
419
420 def join(self, seq):
421 return self.__class__(unicode.join(self, imap(escape, seq)))
Armin Ronacherf59bac22008-04-20 13:11:43 +0200422 join.__doc__ = unicode.join.__doc__
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200423
424 def split(self, *args, **kwargs):
425 return map(self.__class__, unicode.split(self, *args, **kwargs))
Armin Ronacherf59bac22008-04-20 13:11:43 +0200426 split.__doc__ = unicode.split.__doc__
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200427
428 def rsplit(self, *args, **kwargs):
429 return map(self.__class__, unicode.rsplit(self, *args, **kwargs))
Armin Ronacherf59bac22008-04-20 13:11:43 +0200430 rsplit.__doc__ = unicode.rsplit.__doc__
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200431
432 def splitlines(self, *args, **kwargs):
433 return map(self.__class__, unicode.splitlines(self, *args, **kwargs))
Armin Ronacherf59bac22008-04-20 13:11:43 +0200434 splitlines.__doc__ = unicode.splitlines.__doc__
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200435
Armin Ronacher76c280b2008-05-04 12:31:48 +0200436 def unescape(self):
Armin Ronacher58f351d2008-05-28 21:30:14 +0200437 r"""Unescape markup again into an unicode string. This also resolves
438 known HTML4 and XHTML entities:
439
440 >>> Markup("Main &raquo; <em>About</em>").unescape()
441 u'Main \xbb <em>About</em>'
442 """
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200443 from jinja2.constants import HTML_ENTITIES
Armin Ronacher76c280b2008-05-04 12:31:48 +0200444 def handle_match(m):
445 name = m.group(1)
Armin Ronacher9a0078d2008-08-13 18:24:17 +0200446 if name in HTML_ENTITIES:
447 return unichr(HTML_ENTITIES[name])
Armin Ronacher76c280b2008-05-04 12:31:48 +0200448 try:
449 if name[:2] in ('#x', '#X'):
450 return unichr(int(name[2:], 16))
451 elif name.startswith('#'):
452 return unichr(int(name[1:]))
453 except ValueError:
454 pass
455 return u''
456 return _entity_re.sub(handle_match, unicode(self))
457
458 def striptags(self):
Armin Ronacher58f351d2008-05-28 21:30:14 +0200459 r"""Unescape markup into an unicode string and strip all tags. This
460 also resolves known HTML4 and XHTML entities. Whitespace is
461 normalized to one:
462
463 >>> Markup("Main &raquo; <em>About</em>").striptags()
464 u'Main \xbb About'
465 """
Armin Ronacher76c280b2008-05-04 12:31:48 +0200466 stripped = u' '.join(_striptags_re.sub('', self).split())
467 return Markup(stripped).unescape()
468
Armin Ronacherf35e2812008-05-06 16:04:10 +0200469 @classmethod
470 def escape(cls, s):
Armin Ronacher58f351d2008-05-28 21:30:14 +0200471 """Escape the string. Works like :func:`escape` with the difference
472 that for subclasses of :class:`Markup` this function would return the
473 correct subclass.
474 """
Armin Ronacherf35e2812008-05-06 16:04:10 +0200475 rv = escape(s)
476 if rv.__class__ is not cls:
477 return cls(rv)
478 return rv
479
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200480 def make_wrapper(name):
481 orig = getattr(unicode, name)
482 def func(self, *args, **kwargs):
Armin Ronacherd71fff02008-05-26 23:57:07 +0200483 args = _escape_argspec(list(args), enumerate(args))
484 _escape_argspec(kwargs, kwargs.iteritems())
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200485 return self.__class__(orig(self, *args, **kwargs))
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200486 func.__name__ = orig.__name__
487 func.__doc__ = orig.__doc__
488 return func
Armin Ronacherd71fff02008-05-26 23:57:07 +0200489
Armin Ronacher42a19882009-08-05 18:45:39 +0200490 for method in '__getitem__', 'capitalize', \
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200491 'title', 'lower', 'upper', 'replace', 'ljust', \
Armin Ronacher709f6e52008-04-28 18:18:16 +0200492 'rjust', 'lstrip', 'rstrip', 'center', 'strip', \
Armin Ronacher316157d2008-04-28 18:30:27 +0200493 'translate', 'expandtabs', 'swapcase', 'zfill':
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200494 locals()[method] = make_wrapper(method)
Armin Ronacher709f6e52008-04-28 18:18:16 +0200495
496 # new in python 2.5
497 if hasattr(unicode, 'partition'):
Armin Ronacherd71fff02008-05-26 23:57:07 +0200498 partition = make_wrapper('partition'),
499 rpartition = make_wrapper('rpartition')
500
501 # new in python 2.6
502 if hasattr(unicode, 'format'):
503 format = make_wrapper('format')
504
Armin Ronacher42a19882009-08-05 18:45:39 +0200505 # not in python 3
506 if hasattr(unicode, '__getslice__'):
507 __getslice__ = make_wrapper('__getslice__')
508
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200509 del method, make_wrapper
510
511
Armin Ronacherd71fff02008-05-26 23:57:07 +0200512def _escape_argspec(obj, iterable):
513 """Helper for various string-wrapped functions."""
514 for key, value in iterable:
515 if hasattr(value, '__html__') or isinstance(value, basestring):
516 obj[key] = escape(value)
517 return obj
518
519
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200520class _MarkupEscapeHelper(object):
521 """Helper for Markup.__mod__"""
522
523 def __init__(self, obj):
524 self.obj = obj
525
526 __getitem__ = lambda s, x: _MarkupEscapeHelper(s.obj[x])
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200527 __str__ = lambda s: str(escape(s.obj))
Armin Ronacher790b8a82010-02-10 00:05:46 +0100528 __unicode__ = lambda s: unicode(escape(s.obj))
Armin Ronacher3ef20432008-06-09 18:27:19 +0200529 __repr__ = lambda s: str(escape(repr(s.obj)))
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200530 __int__ = lambda s: int(s.obj)
531 __float__ = lambda s: float(s.obj)
Armin Ronacher814f6c22008-04-17 15:52:23 +0200532
533
534class LRUCache(object):
535 """A simple LRU Cache implementation."""
Armin Ronacher58f351d2008-05-28 21:30:14 +0200536
537 # this is fast for small capacities (something below 1000) but doesn't
538 # scale. But as long as it's only used as storage for templates this
539 # won't do any harm.
Armin Ronacher814f6c22008-04-17 15:52:23 +0200540
541 def __init__(self, capacity):
542 self.capacity = capacity
543 self._mapping = {}
544 self._queue = deque()
Armin Ronacher7962ce72008-05-20 17:52:52 +0200545 self._postinit()
Armin Ronacher814f6c22008-04-17 15:52:23 +0200546
Armin Ronacher7962ce72008-05-20 17:52:52 +0200547 def _postinit(self):
Armin Ronacher814f6c22008-04-17 15:52:23 +0200548 # alias all queue methods for faster lookup
549 self._popleft = self._queue.popleft
550 self._pop = self._queue.pop
551 if hasattr(self._queue, 'remove'):
552 self._remove = self._queue.remove
Armin Ronacher000b4912008-05-01 18:40:15 +0200553 self._wlock = allocate_lock()
Armin Ronacher814f6c22008-04-17 15:52:23 +0200554 self._append = self._queue.append
555
556 def _remove(self, obj):
557 """Python 2.4 compatibility."""
558 for idx, item in enumerate(self._queue):
559 if item == obj:
560 del self._queue[idx]
561 break
562
Armin Ronacher7962ce72008-05-20 17:52:52 +0200563 def __getstate__(self):
564 return {
565 'capacity': self.capacity,
566 '_mapping': self._mapping,
567 '_queue': self._queue
568 }
569
570 def __setstate__(self, d):
571 self.__dict__.update(d)
572 self._postinit()
573
574 def __getnewargs__(self):
575 return (self.capacity,)
576
Armin Ronacher814f6c22008-04-17 15:52:23 +0200577 def copy(self):
578 """Return an shallow copy of the instance."""
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200579 rv = self.__class__(self.capacity)
Armin Ronacher814f6c22008-04-17 15:52:23 +0200580 rv._mapping.update(self._mapping)
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200581 rv._queue = deque(self._queue)
Armin Ronacher814f6c22008-04-17 15:52:23 +0200582 return rv
583
584 def get(self, key, default=None):
585 """Return an item from the cache dict or `default`"""
Armin Ronacher000b4912008-05-01 18:40:15 +0200586 try:
Armin Ronacher814f6c22008-04-17 15:52:23 +0200587 return self[key]
Armin Ronacher000b4912008-05-01 18:40:15 +0200588 except KeyError:
589 return default
Armin Ronacher814f6c22008-04-17 15:52:23 +0200590
591 def setdefault(self, key, default=None):
Armin Ronacherbe4ae242008-04-18 09:49:08 +0200592 """Set `default` if the key is not in the cache otherwise
Armin Ronacher814f6c22008-04-17 15:52:23 +0200593 leave unchanged. Return the value of this key.
594 """
Armin Ronacher000b4912008-05-01 18:40:15 +0200595 try:
Armin Ronacher814f6c22008-04-17 15:52:23 +0200596 return self[key]
Armin Ronacher000b4912008-05-01 18:40:15 +0200597 except KeyError:
598 self[key] = default
599 return default
Armin Ronacher814f6c22008-04-17 15:52:23 +0200600
601 def clear(self):
602 """Clear the cache."""
Armin Ronacher000b4912008-05-01 18:40:15 +0200603 self._wlock.acquire()
604 try:
605 self._mapping.clear()
606 self._queue.clear()
607 finally:
608 self._wlock.release()
Armin Ronacher814f6c22008-04-17 15:52:23 +0200609
610 def __contains__(self, key):
611 """Check if a key exists in this cache."""
612 return key in self._mapping
613
614 def __len__(self):
615 """Return the current size of the cache."""
616 return len(self._mapping)
617
618 def __repr__(self):
619 return '<%s %r>' % (
620 self.__class__.__name__,
621 self._mapping
622 )
623
624 def __getitem__(self, key):
625 """Get an item from the cache. Moves the item up so that it has the
626 highest priority then.
627
628 Raise an `KeyError` if it does not exist.
629 """
630 rv = self._mapping[key]
631 if self._queue[-1] != key:
Armin Ronacher8de6f182009-01-12 11:08:26 +0100632 try:
633 self._remove(key)
Armin Ronachere7c72bc2009-09-14 12:20:33 -0700634 except ValueError:
Armin Ronacher8de6f182009-01-12 11:08:26 +0100635 # if something removed the key from the container
636 # when we read, ignore the ValueError that we would
637 # get otherwise.
638 pass
Armin Ronacher814f6c22008-04-17 15:52:23 +0200639 self._append(key)
640 return rv
641
642 def __setitem__(self, key, value):
643 """Sets the value for an item. Moves the item up so that it
644 has the highest priority then.
645 """
Armin Ronacher000b4912008-05-01 18:40:15 +0200646 self._wlock.acquire()
647 try:
648 if key in self._mapping:
Armin Ronacher74230e62009-10-25 12:46:31 +0100649 try:
650 self._remove(key)
651 except ValueError:
652 # __getitem__ is not locked, it might happen
653 pass
Armin Ronacher000b4912008-05-01 18:40:15 +0200654 elif len(self._mapping) == self.capacity:
655 del self._mapping[self._popleft()]
656 self._append(key)
657 self._mapping[key] = value
658 finally:
659 self._wlock.release()
Armin Ronacher814f6c22008-04-17 15:52:23 +0200660
661 def __delitem__(self, key):
662 """Remove an item from the cache dict.
663 Raise an `KeyError` if it does not exist.
664 """
Armin Ronacher000b4912008-05-01 18:40:15 +0200665 self._wlock.acquire()
666 try:
667 del self._mapping[key]
Armin Ronachere7c72bc2009-09-14 12:20:33 -0700668 try:
669 self._remove(key)
670 except ValueError:
671 # __getitem__ is not locked, it might happen
672 pass
Armin Ronacher000b4912008-05-01 18:40:15 +0200673 finally:
674 self._wlock.release()
Armin Ronacher814f6c22008-04-17 15:52:23 +0200675
Armin Ronachere25f24d2008-05-19 11:20:41 +0200676 def items(self):
677 """Return a list of items."""
678 result = [(key, self._mapping[key]) for key in list(self._queue)]
679 result.reverse()
680 return result
681
682 def iteritems(self):
683 """Iterate over all items."""
684 return iter(self.items())
685
686 def values(self):
687 """Return a list of all values."""
688 return [x[1] for x in self.items()]
689
690 def itervalue(self):
691 """Iterate over all values."""
692 return iter(self.values())
693
694 def keys(self):
695 """Return a list of all keys ordered by most recent usage."""
696 return list(self)
697
698 def iterkeys(self):
699 """Iterate over all keys in the cache dict, ordered by
Armin Ronacher814f6c22008-04-17 15:52:23 +0200700 the most recent usage.
701 """
Armin Ronachere2244882008-05-19 09:25:57 +0200702 return reversed(tuple(self._queue))
Armin Ronacher814f6c22008-04-17 15:52:23 +0200703
Armin Ronachere25f24d2008-05-19 11:20:41 +0200704 __iter__ = iterkeys
705
Armin Ronacher814f6c22008-04-17 15:52:23 +0200706 def __reversed__(self):
707 """Iterate over the values in the cache dict, oldest items
708 coming first.
709 """
Armin Ronachere2244882008-05-19 09:25:57 +0200710 return iter(tuple(self._queue))
Armin Ronacher814f6c22008-04-17 15:52:23 +0200711
712 __copy__ = copy
713
Armin Ronacherbd33f112008-04-18 09:17:32 +0200714
Armin Ronacher9bb7e472008-05-28 11:26:59 +0200715# register the LRU cache as mutable mapping if possible
716try:
717 from collections import MutableMapping
718 MutableMapping.register(LRUCache)
719except ImportError:
720 pass
721
722
Armin Ronacherccae0552008-10-05 23:08:58 +0200723class Cycler(object):
724 """A cycle helper for templates."""
725
726 def __init__(self, *items):
727 if not items:
728 raise RuntimeError('at least one item has to be provided')
729 self.items = items
730 self.reset()
731
732 def reset(self):
733 """Resets the cycle."""
734 self.pos = 0
735
736 @property
737 def current(self):
738 """Returns the current item."""
739 return self.items[self.pos]
740
741 def next(self):
742 """Goes one item ahead and returns it."""
743 rv = self.current
744 self.pos = (self.pos + 1) % len(self.items)
745 return rv
746
747
Armin Ronacherd34eb122008-10-13 23:47:51 +0200748class Joiner(object):
749 """A joining helper for templates."""
750
751 def __init__(self, sep=u', '):
752 self.sep = sep
753 self.used = False
754
755 def __call__(self):
756 if not self.used:
757 self.used = True
758 return u''
759 return self.sep
760
761
Armin Ronacherbd33f112008-04-18 09:17:32 +0200762# we have to import it down here as the speedups module imports the
763# markup type which is define above.
764try:
Armin Ronacherf59bac22008-04-20 13:11:43 +0200765 from jinja2._speedups import escape, soft_unicode
Armin Ronacherbd33f112008-04-18 09:17:32 +0200766except ImportError:
Lukas Meuserad48a2e2008-05-01 18:19:57 +0200767 def escape(s):
Armin Ronacherf35e2812008-05-06 16:04:10 +0200768 """Convert the characters &, <, >, ' and " in string s to HTML-safe
769 sequences. Use this if you need to display text that might contain
Armin Ronacher9a1e33c2008-05-05 22:00:46 +0200770 such characters in HTML. Marks return value as markup string.
Armin Ronacherbd33f112008-04-18 09:17:32 +0200771 """
Lukas Meuserad48a2e2008-05-01 18:19:57 +0200772 if hasattr(s, '__html__'):
773 return s.__html__()
774 return Markup(unicode(s)
Armin Ronacherbd33f112008-04-18 09:17:32 +0200775 .replace('&', '&amp;')
776 .replace('>', '&gt;')
777 .replace('<', '&lt;')
Armin Ronacherf35e2812008-05-06 16:04:10 +0200778 .replace("'", '&#39;')
Armin Ronacher9d42abf2008-05-14 18:10:41 +0200779 .replace('"', '&#34;')
Armin Ronacherbd33f112008-04-18 09:17:32 +0200780 )
Armin Ronacherf59bac22008-04-20 13:11:43 +0200781
782 def soft_unicode(s):
783 """Make a string unicode if it isn't already. That way a markup
784 string is not converted back to unicode.
785 """
786 if not isinstance(s, unicode):
787 s = unicode(s)
788 return s
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200789
790
791# partials
792try:
793 from functools import partial
794except ImportError:
795 class partial(object):
796 def __init__(self, _func, *args, **kwargs):
Benjamin Wiegand228c1832008-04-28 18:09:27 +0200797 self._func = _func
Armin Ronacher4f7d2d52008-04-22 10:40:26 +0200798 self._args = args
799 self._kwargs = kwargs
800 def __call__(self, *args, **kwargs):
801 kwargs.update(self._kwargs)
802 return self._func(*(self._args + args), **kwargs)