1
# -*- coding: utf-8 -*-
8
:copyright: (c) 2010 by the Jinja Team.
9
:license: BSD, see LICENSE for more details.
13
from collections import deque
14
from jinja2._compat import text_type, string_types, implements_iterator, \
15
allocate_lock, url_quote
18
_word_split_re = re.compile(r'(\s+)')
19
_punctuation_re = re.compile(
20
'^(?P<lead>(?:%s)*)(?P<middle>.*?)(?P<trail>(?:%s)*)$' % (
21
'|'.join(map(re.escape, ('(', '<', '<'))),
22
'|'.join(map(re.escape, ('.', ',', ')', '>', '\n', '>')))
25
_simple_email_re = re.compile(r'^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$')
26
_striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
27
_entity_re = re.compile(r'&([^;]+);')
28
_letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
29
_digits = '0123456789'
31
# special singleton representing missing values for the runtime
32
missing = type('MissingType', (), {'__repr__': lambda x: 'missing'})()
40
def contextfunction(f):
41
"""This decorator can be used to mark a function or method context callable.
42
A context callable is passed the active :class:`Context` as first argument when
43
called from the template. This is useful if a function wants to get access
44
to the context or functions provided on the context object. For example
45
a function that returns a sorted list of template variables the current
46
template exports could look like this::
49
def get_exported_names(context):
50
return sorted(context.exported_vars)
52
f.contextfunction = True
56
def evalcontextfunction(f):
57
"""This decorator can be used to mark a function or method as an eval
58
context callable. This is similar to the :func:`contextfunction`
59
but instead of passing the context, an evaluation context object is
60
passed. For more information about the eval context, see
65
f.evalcontextfunction = True
69
def environmentfunction(f):
70
"""This decorator can be used to mark a function or method as environment
71
callable. This decorator works exactly like the :func:`contextfunction`
72
decorator just that the first argument is the active :class:`Environment`
75
f.environmentfunction = True
80
"""Marks the function as internally used"""
81
internal_code.add(f.__code__)
85
def is_undefined(obj):
86
"""Check if the object passed is undefined. This does nothing more than
87
performing an instance check against :class:`Undefined` but looks nicer.
88
This can be used for custom filters or tests that want to react to
89
undefined variables. For example a custom default filter can look like
92
def default(var, default=''):
97
from jinja2.runtime import Undefined
98
return isinstance(obj, Undefined)
101
def consume(iterable):
102
"""Consumes an iterable without doing anything with it."""
103
for event in iterable:
108
"""Jinja2 keeps internal caches for environments and lexers. These are
109
used so that Jinja2 doesn't have to recreate environments and lexers all
110
the time. Normally you don't have to care about that but if you are
111
messuring memory consumption you may want to clean the caches.
113
from jinja2.environment import _spontaneous_environments
114
from jinja2.lexer import _lexer_cache
115
_spontaneous_environments.clear()
119
def import_string(import_name, silent=False):
120
"""Imports an object based on a string. This is useful if you want to
121
use import paths as endpoints or something similar. An import path can
122
be specified either in dotted notation (``xml.sax.saxutils.escape``)
123
or with a colon as object delimiter (``xml.sax.saxutils:escape``).
125
If the `silent` is True the return value will be `None` if the import
128
:return: imported object
131
if ':' in import_name:
132
module, obj = import_name.split(':', 1)
133
elif '.' in import_name:
134
items = import_name.split('.')
135
module = '.'.join(items[:-1])
138
return __import__(import_name)
139
return getattr(__import__(module, None, None, [obj]), obj)
140
except (ImportError, AttributeError):
145
def open_if_exists(filename, mode='rb'):
146
"""Returns a file descriptor for the filename if that file exists,
150
return open(filename, mode)
152
if e.errno not in (errno.ENOENT, errno.EISDIR):
156
def object_type_repr(obj):
157
"""Returns the name of the object's type. For some recognized
158
singletons the name of the object is returned instead. (For
159
example for `None` and `Ellipsis`).
163
elif obj is Ellipsis:
165
# __builtin__ in 2.x, builtins in 3.x
166
if obj.__class__.__module__ in ('__builtin__', 'builtins'):
167
name = obj.__class__.__name__
169
name = obj.__class__.__module__ + '.' + obj.__class__.__name__
170
return '%s object' % name
173
def pformat(obj, verbose=False):
174
"""Prettyprint an object. Either use the `pretty` library or the
178
from pretty import pretty
179
return pretty(obj, verbose=verbose)
181
from pprint import pformat
185
def urlize(text, trim_url_limit=None, nofollow=False):
186
"""Converts any URLs in text into clickable links. Works on http://,
187
https:// and www. links. Links can have trailing punctuation (periods,
188
commas, close-parens) and leading punctuation (opening parens) and
189
it'll still do the right thing.
191
If trim_url_limit is not None, the URLs in link text will be limited
192
to trim_url_limit characters.
194
If nofollow is True, the URLs in link text will get a rel="nofollow"
197
trim_url = lambda x, limit=trim_url_limit: limit is not None \
198
and (x[:limit] + (len(x) >=limit and '...'
200
words = _word_split_re.split(text_type(escape(text)))
201
nofollow_attr = nofollow and ' rel="nofollow"' or ''
202
for i, word in enumerate(words):
203
match = _punctuation_re.match(word)
205
lead, middle, trail = match.groups()
206
if middle.startswith('www.') or (
207
'@' not in middle and
208
not middle.startswith('http://') and
209
not middle.startswith('https://') and
211
middle[0] in _letters + _digits and (
212
middle.endswith('.org') or
213
middle.endswith('.net') or
214
middle.endswith('.com')
216
middle = '<a href="http://%s"%s>%s</a>' % (middle,
217
nofollow_attr, trim_url(middle))
218
if middle.startswith('http://') or \
219
middle.startswith('https://'):
220
middle = '<a href="%s"%s>%s</a>' % (middle,
221
nofollow_attr, trim_url(middle))
222
if '@' in middle and not middle.startswith('www.') and \
223
not ':' in middle and _simple_email_re.match(middle):
224
middle = '<a href="mailto:%s">%s</a>' % (middle, middle)
225
if lead + middle + trail != word:
226
words[i] = lead + middle + trail
227
return u''.join(words)
230
def generate_lorem_ipsum(n=5, html=True, min=20, max=100):
231
"""Generate some lorem impsum for the template."""
232
from jinja2.constants import LOREM_IPSUM_WORDS
233
from random import choice, randrange
234
words = LOREM_IPSUM_WORDS.split()
238
next_capitalized = True
239
last_comma = last_fullstop = 0
244
# each paragraph contains out of 20 to 100 words.
245
for idx, _ in enumerate(range(randrange(min, max))):
252
word = word.capitalize()
253
next_capitalized = False
255
if idx - randrange(3, 8) > last_comma:
259
# add end of sentences
260
if idx - randrange(10, 20) > last_fullstop:
261
last_comma = last_fullstop = idx
263
next_capitalized = True
266
# ensure that the paragraph ends with a dot.
270
elif not p.endswith('.'):
275
return u'\n\n'.join(result)
276
return Markup(u'\n'.join(u'<p>%s</p>' % escape(x) for x in result))
279
def unicode_urlencode(obj, charset='utf-8'):
280
"""URL escapes a single bytestring or unicode string with the
281
given charset if applicable to URL safe quoting under all rules
282
that need to be considered under all supported Python versions.
284
If non strings are provided they are converted to their unicode
285
representation first.
287
if not isinstance(obj, string_types):
289
if isinstance(obj, text_type):
290
obj = obj.encode(charset)
291
return text_type(url_quote(obj))
294
class LRUCache(object):
295
"""A simple LRU Cache implementation."""
297
# this is fast for small capacities (something below 1000) but doesn't
298
# scale. But as long as it's only used as storage for templates this
301
def __init__(self, capacity):
302
self.capacity = capacity
304
self._queue = deque()
308
# alias all queue methods for faster lookup
309
self._popleft = self._queue.popleft
310
self._pop = self._queue.pop
311
self._remove = self._queue.remove
312
self._wlock = allocate_lock()
313
self._append = self._queue.append
315
def __getstate__(self):
317
'capacity': self.capacity,
318
'_mapping': self._mapping,
319
'_queue': self._queue
322
def __setstate__(self, d):
323
self.__dict__.update(d)
326
def __getnewargs__(self):
327
return (self.capacity,)
330
"""Return a shallow copy of the instance."""
331
rv = self.__class__(self.capacity)
332
rv._mapping.update(self._mapping)
333
rv._queue = deque(self._queue)
336
def get(self, key, default=None):
337
"""Return an item from the cache dict or `default`"""
343
def setdefault(self, key, default=None):
344
"""Set `default` if the key is not in the cache otherwise
345
leave unchanged. Return the value of this key.
347
self._wlock.acquire()
355
self._wlock.release()
358
"""Clear the cache."""
359
self._wlock.acquire()
361
self._mapping.clear()
364
self._wlock.release()
366
def __contains__(self, key):
367
"""Check if a key exists in this cache."""
368
return key in self._mapping
371
"""Return the current size of the cache."""
372
return len(self._mapping)
376
self.__class__.__name__,
380
def __getitem__(self, key):
381
"""Get an item from the cache. Moves the item up so that it has the
382
highest priority then.
384
Raise a `KeyError` if it does not exist.
386
self._wlock.acquire()
388
rv = self._mapping[key]
389
if self._queue[-1] != key:
393
# if something removed the key from the container
394
# when we read, ignore the ValueError that we would
400
self._wlock.release()
402
def __setitem__(self, key, value):
403
"""Sets the value for an item. Moves the item up so that it
404
has the highest priority then.
406
self._wlock.acquire()
408
if key in self._mapping:
410
elif len(self._mapping) == self.capacity:
411
del self._mapping[self._popleft()]
413
self._mapping[key] = value
415
self._wlock.release()
417
def __delitem__(self, key):
418
"""Remove an item from the cache dict.
419
Raise a `KeyError` if it does not exist.
421
self._wlock.acquire()
423
del self._mapping[key]
427
# __getitem__ is not locked, it might happen
430
self._wlock.release()
433
"""Return a list of items."""
434
result = [(key, self._mapping[key]) for key in list(self._queue)]
439
"""Iterate over all items."""
440
return iter(self.items())
443
"""Return a list of all values."""
444
return [x[1] for x in self.items()]
447
"""Iterate over all values."""
448
return iter(self.values())
451
"""Return a list of all keys ordered by most recent usage."""
455
"""Iterate over all keys in the cache dict, ordered by
456
the most recent usage.
458
return reversed(tuple(self._queue))
462
def __reversed__(self):
463
"""Iterate over the values in the cache dict, oldest items
466
return iter(tuple(self._queue))
471
# register the LRU cache as mutable mapping if possible
473
from collections import MutableMapping
474
MutableMapping.register(LRUCache)
480
class Cycler(object):
481
"""A cycle helper for templates."""
483
def __init__(self, *items):
485
raise RuntimeError('at least one item has to be provided')
490
"""Resets the cycle."""
495
"""Returns the current item."""
496
return self.items[self.pos]
499
"""Goes one item ahead and returns it."""
501
self.pos = (self.pos + 1) % len(self.items)
505
class Joiner(object):
506
"""A joining helper for templates."""
508
def __init__(self, sep=u', '):
519
# Imported here because that's where it was in the past
520
from markupsafe import Markup, escape, soft_unicode