1 # -*- coding: utf-8 -*-
8 :copyright: 2008 by Armin Ronacher.
9 :license: BSD, see LICENSE for more details.
13 from collections import deque
14 from copy import deepcopy
15 from itertools import imap
18 _word_split_re = re.compile(r'(\s+)')
19 _punctuation_re = re.compile(
20 '^(?P<lead>(?:%s)*)(?P<middle>.*?)(?P<trail>(?:%s)*)$' % (
21 '|'.join(imap(re.escape, ('(', '<', '<'))),
22 '|'.join(imap(re.escape, ('.', ',', ')', '>', '\n', '>')))
25 _simple_email_re = re.compile(r'^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$')
28 def contextfunction(f):
29 """This decorator can be used to mark a callable as context callable. A
30 context callable is passed the active context as first argument if it
31 was directly stored in the context.
33 f.contextfunction = True
37 def environmentfunction(f):
38 """This decorator can be used to mark a callable as environment callable.
39 A environment callable is passed the current environment as first argument
40 if it was directly stored in the context.
42 f.environmentfunction = True
46 def import_string(import_name, silent=False):
47 """Imports an object based on a string. This use useful if you want to
48 use import paths as endpoints or something similar. An import path can
49 be specified either in dotted notation (``xml.sax.saxutils.escape``)
50 or with a colon as object delimiter (``xml.sax.saxutils:escape``).
52 If the `silent` is True the return value will be `None` if the import
55 :return: imported object
58 if ':' in import_name:
59 module, obj = import_name.split(':', 1)
60 elif '.' in import_name:
61 items = import_name.split('.')
62 module = '.'.join(items[:-1])
65 return __import__(import_name)
66 return getattr(__import__(module, None, None, [obj]), obj)
67 except (ImportError, AttributeError):
72 def pformat(obj, verbose=False):
73 """Prettyprint an object. Either use the `pretty` library or the
77 from pretty import pretty
78 return pretty(obj, verbose=verbose)
80 from pprint import pformat
84 def urlize(text, trim_url_limit=None, nofollow=False):
85 """Converts any URLs in text into clickable links. Works on http://,
86 https:// and www. links. Links can have trailing punctuation (periods,
87 commas, close-parens) and leading punctuation (opening parens) and
88 it'll still do the right thing.
90 If trim_url_limit is not None, the URLs in link text will be limited
91 to trim_url_limit characters.
93 If nofollow is True, the URLs in link text will get a rel="nofollow"
96 trim_url = lambda x, limit=trim_url_limit: limit is not None \
97 and (x[:limit] + (len(x) >=limit and '...'
99 words = _word_split_re.split(text)
100 nofollow_attr = nofollow and ' rel="nofollow"' or ''
101 for i, word in enumerate(words):
102 match = _punctuation_re.match(word)
104 lead, middle, trail = match.groups()
105 if middle.startswith('www.') or (
106 '@' not in middle and
107 not middle.startswith('http://') and
109 middle[0] in string.letters + string.digits and (
110 middle.endswith('.org') or
111 middle.endswith('.net') or
112 middle.endswith('.com')
114 middle = '<a href="http://%s"%s>%s</a>' % (middle,
115 nofollow_attr, trim_url(middle))
116 if middle.startswith('http://') or \
117 middle.startswith('https://'):
118 middle = '<a href="%s"%s>%s</a>' % (middle,
119 nofollow_attr, trim_url(middle))
120 if '@' in middle and not middle.startswith('www.') and \
121 not ':' in middle and _simple_email_re.match(middle):
122 middle = '<a href="mailto:%s">%s</a>' % (middle, middle)
123 if lead + middle + trail != word:
124 words[i] = lead + middle + trail
125 return u''.join(words)
128 def generate_lorem_ipsum(n=5, html=True, min=20, max=100):
129 """Generate some lorem impsum for the template."""
130 from jinja2.constants import LOREM_IPSUM_WORDS
131 from random import choice, random, randrange
132 words = LOREM_IPSUM_WORDS.split()
136 next_capitalized = True
137 last_comma = last_fullstop = 0
142 # each paragraph contains out of 20 to 100 words.
143 for idx, _ in enumerate(xrange(randrange(min, max))):
150 word = word.capitalize()
151 next_capitalized = False
153 if idx - randrange(3, 8) > last_comma:
157 # add end of sentences
158 if idx - randrange(10, 20) > last_fullstop:
159 last_comma = last_fullstop = idx
161 next_capitalized = True
164 # ensure that the paragraph ends with a dot.
168 elif not p.endswith('.'):
173 return u'\n\n'.join(result)
174 return Markup(u'\n'.join(u'<p>%s</p>' % escape(x) for x in result))
177 class Markup(unicode):
178 """Marks a string as being safe for inclusion in HTML/XML output without
179 needing to be escaped. This implements the `__html__` interface a couple
180 of frameworks and web applications use.
182 The `escape` function returns markup objects so that double escaping can't
183 happen. If you want to use autoescaping in Jinja just set the finalizer
184 of the environment to `escape`.
191 def __add__(self, other):
192 if hasattr(other, '__html__') or isinstance(other, basestring):
193 return self.__class__(unicode(self) + unicode(escape(other)))
194 return NotImplemented
196 def __radd__(self, other):
197 if hasattr(other, '__html__') or isinstance(other, basestring):
198 return self.__class__(unicode(escape(other)) + unicode(self))
199 return NotImplemented
201 def __mul__(self, num):
202 if not isinstance(num, (int, long)):
203 return NotImplemented
204 return self.__class__(unicode.__mul__(self, num))
207 def __mod__(self, arg):
208 if isinstance(arg, tuple):
209 arg = tuple(imap(_MarkupEscapeHelper, arg))
211 arg = _MarkupEscapeHelper(arg)
212 return self.__class__(unicode.__mod__(self, arg))
216 self.__class__.__name__,
217 unicode.__repr__(self)
221 return self.__class__(unicode.join(self, imap(escape, seq)))
222 join.__doc__ = unicode.join.__doc__
224 def split(self, *args, **kwargs):
225 return map(self.__class__, unicode.split(self, *args, **kwargs))
226 split.__doc__ = unicode.split.__doc__
228 def rsplit(self, *args, **kwargs):
229 return map(self.__class__, unicode.rsplit(self, *args, **kwargs))
230 rsplit.__doc__ = unicode.rsplit.__doc__
232 def splitlines(self, *args, **kwargs):
233 return map(self.__class__, unicode.splitlines(self, *args, **kwargs))
234 splitlines.__doc__ = unicode.splitlines.__doc__
236 def make_wrapper(name):
237 orig = getattr(unicode, name)
238 def func(self, *args, **kwargs):
240 for idx, arg in enumerate(args):
241 if hasattr(arg, '__html__') or isinstance(arg, basestring):
242 args[idx] = escape(arg)
243 for name, arg in kwargs.iteritems():
244 if hasattr(arg, '__html__') or isinstance(arg, basestring):
245 kwargs[name] = escape(arg)
246 return self.__class__(orig(self, *args, **kwargs))
247 func.__name__ = orig.__name__
248 func.__doc__ = orig.__doc__
250 for method in '__getitem__', '__getslice__', 'capitalize', \
251 'title', 'lower', 'upper', 'replace', 'ljust', \
252 'rjust', 'lstrip', 'rstrip', 'center', 'strip', \
253 'translate', 'expandtabs', 'swapcase', 'zfill':
254 locals()[method] = make_wrapper(method)
257 if hasattr(unicode, 'partition'):
259 partition=make_wrapper('partition'),
260 rpartition=make_wrapper('rpartition')
262 del method, make_wrapper
265 class _MarkupEscapeHelper(object):
266 """Helper for Markup.__mod__"""
268 def __init__(self, obj):
271 __getitem__ = lambda s, x: _MarkupEscapeHelper(s.obj[x])
272 __unicode__ = lambda s: unicode(escape(s.obj))
273 __str__ = lambda s: str(escape(s.obj))
274 __repr__ = lambda s: str(repr(escape(s.obj)))
275 __int__ = lambda s: int(s.obj)
276 __float__ = lambda s: float(s.obj)
279 class LRUCache(object):
280 """A simple LRU Cache implementation."""
281 # this is fast for small capacities (something around 200) but doesn't
282 # scale. But as long as it's only used for the database connections in
283 # a non request fallback it's fine.
285 def __init__(self, capacity):
286 self.capacity = capacity
288 self._queue = deque()
290 # alias all queue methods for faster lookup
291 self._popleft = self._queue.popleft
292 self._pop = self._queue.pop
293 if hasattr(self._queue, 'remove'):
294 self._remove = self._queue.remove
295 self._append = self._queue.append
297 def _remove(self, obj):
298 """Python 2.4 compatibility."""
299 for idx, item in enumerate(self._queue):
305 """Return an shallow copy of the instance."""
306 rv = self.__class__(self.capacity)
307 rv._mapping.update(self._mapping)
308 rv._queue = deque(self._queue)
311 def get(self, key, default=None):
312 """Return an item from the cache dict or `default`"""
317 def setdefault(self, key, default=None):
318 """Set `default` if the key is not in the cache otherwise
319 leave unchanged. Return the value of this key.
327 """Clear the cache."""
328 self._mapping.clear()
331 def __contains__(self, key):
332 """Check if a key exists in this cache."""
333 return key in self._mapping
336 """Return the current size of the cache."""
337 return len(self._mapping)
341 self.__class__.__name__,
345 def __getitem__(self, key):
346 """Get an item from the cache. Moves the item up so that it has the
347 highest priority then.
349 Raise an `KeyError` if it does not exist.
351 rv = self._mapping[key]
352 if self._queue[-1] != key:
357 def __setitem__(self, key, value):
358 """Sets the value for an item. Moves the item up so that it
359 has the highest priority then.
361 if key in self._mapping:
363 elif len(self._mapping) == self.capacity:
364 del self._mapping[self._popleft()]
366 self._mapping[key] = value
368 def __delitem__(self, key):
369 """Remove an item from the cache dict.
370 Raise an `KeyError` if it does not exist.
372 del self._mapping[key]
376 """Iterate over all values in the cache dict, ordered by
377 the most recent usage.
379 return reversed(self._queue)
381 def __reversed__(self):
382 """Iterate over the values in the cache dict, oldest items
385 return iter(self._queue)
390 # we have to import it down here as the speedups module imports the
391 # markup type which is define above.
393 from jinja2._speedups import escape, soft_unicode
396 """Convert the characters &, <, >, and " in string s to HTML-safe
397 sequences. Use this if you need to display text that might contain
398 such characters in HTML.
400 if hasattr(obj, '__html__'):
401 return obj.__html__()
402 return Markup(unicode(obj)
403 .replace('&', '&')
404 .replace('>', '>')
405 .replace('<', '<')
406 .replace('"', '"')
410 """Make a string unicode if it isn't already. That way a markup
411 string is not converted back to unicode.
413 if not isinstance(s, unicode):
420 from functools import partial
422 class partial(object):
423 def __init__(self, _func, *args, **kwargs):
426 self._kwargs = kwargs
427 def __call__(self, *args, **kwargs):
428 kwargs.update(self._kwargs)
429 return self._func(*(self._args + args), **kwargs)