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