1 # -*- coding: utf-8 -*-
8 :copyright: (c) 2010 by the Jinja Team.
9 :license: BSD, see LICENSE for more details.
13 from random import choice
14 from operator import itemgetter
15 from itertools import imap, groupby
16 from jinja2.utils import Markup, escape, pformat, urlize, soft_unicode
17 from jinja2.runtime import Undefined
18 from jinja2.exceptions import FilterArgumentError, SecurityError
21 _word_re = re.compile(r'\w+(?u)')
25 """Decorator for marking context dependent filters. The current
26 :class:`Context` will be passed as first argument.
28 f.contextfilter = True
32 def evalcontextfilter(f):
33 """Decorator for marking eval-context dependent filters. An eval
34 context object is passed as first argument. For more information
35 about the eval context, see :ref:`eval-context`.
39 f.evalcontextfilter = True
43 def environmentfilter(f):
44 """Decorator for marking evironment dependent filters. The current
45 :class:`Environment` is passed to the filter as first argument.
47 f.environmentfilter = True
51 def do_forceescape(value):
52 """Enforce HTML escaping. This will probably double escape variables."""
53 if hasattr(value, '__html__'):
54 value = value.__html__()
55 return escape(unicode(value))
59 def do_replace(eval_ctx, s, old, new, count=None):
60 """Return a copy of the value with all occurrences of a substring
61 replaced with a new one. The first argument is the substring
62 that should be replaced, the second is the replacement string.
63 If the optional third argument ``count`` is given, only the first
64 ``count`` occurrences are replaced:
68 {{ "Hello World"|replace("Hello", "Goodbye") }}
71 {{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
76 if not eval_ctx.autoescape:
77 return unicode(s).replace(unicode(old), unicode(new), count)
78 if hasattr(old, '__html__') or hasattr(new, '__html__') and \
79 not hasattr(s, '__html__'):
83 return s.replace(soft_unicode(old), soft_unicode(new), count)
87 """Convert a value to uppercase."""
88 return soft_unicode(s).upper()
92 """Convert a value to lowercase."""
93 return soft_unicode(s).lower()
97 def do_xmlattr(_eval_ctx, d, autospace=True):
98 """Create an SGML/XML attribute string based on the items in a dict.
99 All values that are neither `none` nor `undefined` are automatically
102 .. sourcecode:: html+jinja
104 <ul{{ {'class': 'my_list', 'missing': none,
105 'id': 'list-%d'|format(variable)}|xmlattr }}>
109 Results in something like this:
113 <ul class="my_list" id="list-42">
117 As you can see it automatically prepends a space in front of the item
118 if the filter returned something unless the second parameter is false.
121 u'%s="%s"' % (escape(key), escape(value))
122 for key, value in d.iteritems()
123 if value is not None and not isinstance(value, Undefined)
127 if _eval_ctx.autoescape:
132 def do_capitalize(s):
133 """Capitalize a value. The first character will be uppercase, all others
136 return soft_unicode(s).capitalize()
140 """Return a titlecased version of the value. I.e. words will start with
141 uppercase letters, all remaining characters are lowercase.
143 return soft_unicode(s).title()
146 def do_dictsort(value, case_sensitive=False, by='key'):
147 """Sort a dict and yield (key, value) pairs. Because python dicts are
148 unsorted you may want to use this function to order them by either
151 .. sourcecode:: jinja
153 {% for item in mydict|dictsort %}
154 sort the dict by key, case insensitive
156 {% for item in mydict|dicsort(true) %}
157 sort the dict by key, case sensitive
159 {% for item in mydict|dictsort(false, 'value') %}
160 sort the dict by key, case insensitive, sorted
161 normally and ordered by value.
168 raise FilterArgumentError('You can only sort by either '
172 if isinstance(value, basestring) and not case_sensitive:
173 value = value.lower()
176 return sorted(value.items(), key=sort_func)
179 def do_sort(value, reverse=False, case_sensitive=False):
180 """Sort an iterable. Per default it sorts ascending, if you pass it
181 true as first argument it will reverse the sorting.
183 If the iterable is made of strings the third parameter can be used to
184 control the case sensitiveness of the comparison which is disabled by
187 .. sourcecode:: jinja
189 {% for item in iterable|sort %}
193 if not case_sensitive:
195 if isinstance(item, basestring):
200 return sorted(value, key=sort_func, reverse=reverse)
203 def do_default(value, default_value=u'', boolean=False):
204 """If the value is undefined it will return the passed default value,
205 otherwise the value of the variable:
207 .. sourcecode:: jinja
209 {{ my_variable|default('my_variable is not defined') }}
211 This will output the value of ``my_variable`` if the variable was
212 defined, otherwise ``'my_variable is not defined'``. If you want
213 to use default with variables that evaluate to false you have to
214 set the second parameter to `true`:
216 .. sourcecode:: jinja
218 {{ ''|default('the string was empty', true) }}
220 if (boolean and not value) or isinstance(value, Undefined):
226 def do_join(eval_ctx, value, d=u''):
227 """Return a string which is the concatenation of the strings in the
228 sequence. The separator between elements is an empty string per
229 default, you can define it with the optional parameter:
231 .. sourcecode:: jinja
233 {{ [1, 2, 3]|join('|') }}
239 # no automatic escaping? joining is a lot eaiser then
240 if not eval_ctx.autoescape:
241 return unicode(d).join(imap(unicode, value))
243 # if the delimiter doesn't have an html representation we check
244 # if any of the items has. If yes we do a coercion to Markup
245 if not hasattr(d, '__html__'):
248 for idx, item in enumerate(value):
249 if hasattr(item, '__html__'):
252 value[idx] = unicode(item)
259 # no html involved, to normal joining
260 return soft_unicode(d).join(imap(soft_unicode, value))
263 def do_center(value, width=80):
264 """Centers the value in a field of a given width."""
265 return unicode(value).center(width)
269 def do_first(environment, seq):
270 """Return the first item of a sequence."""
272 return iter(seq).next()
273 except StopIteration:
274 return environment.undefined('No first item, sequence was empty.')
278 def do_last(environment, seq):
279 """Return the last item of a sequence."""
281 return iter(reversed(seq)).next()
282 except StopIteration:
283 return environment.undefined('No last item, sequence was empty.')
287 def do_random(environment, seq):
288 """Return a random item from the sequence."""
292 return environment.undefined('No random item, sequence was empty.')
295 def do_filesizeformat(value, binary=False):
296 """Format the value like a 'human-readable' file size (i.e. 13 KB,
297 4.1 MB, 102 bytes, etc). Per default decimal prefixes are used (mega,
298 giga, etc.), if the second parameter is set to `True` the binary
299 prefixes are used (mebi, gibi).
302 base = binary and 1024 or 1000
303 middle = binary and 'i' or ''
305 return "%d Byte%s" % (bytes, bytes != 1 and 's' or '')
306 elif bytes < base * base:
307 return "%.1f K%sB" % (bytes / base, middle)
308 elif bytes < base * base * base:
309 return "%.1f M%sB" % (bytes / (base * base), middle)
310 return "%.1f G%sB" % (bytes / (base * base * base), middle)
313 def do_pprint(value, verbose=False):
314 """Pretty print a variable. Useful for debugging.
316 With Jinja 1.2 onwards you can pass it a parameter. If this parameter
317 is truthy the output will be more verbose (this requires `pretty`)
319 return pformat(value, verbose=verbose)
323 def do_urlize(eval_ctx, value, trim_url_limit=None, nofollow=False):
324 """Converts URLs in plain text into clickable links.
326 If you pass the filter an additional integer it will shorten the urls
327 to that number. Also a third argument exists that makes the urls
330 .. sourcecode:: jinja
332 {{ mytext|urlize(40, true) }}
333 links are shortened to 40 chars and defined with rel="nofollow"
335 rv = urlize(value, trim_url_limit, nofollow)
336 if eval_ctx.autoescape:
341 def do_indent(s, width=4, indentfirst=False):
342 """Return a copy of the passed string, each line indented by
343 4 spaces. The first line is not indented. If you want to
344 change the number of spaces or indent the first line too
345 you can pass additional parameters to the filter:
347 .. sourcecode:: jinja
349 {{ mytext|indent(2, true) }}
350 indent by two spaces and indent the first line too.
352 indention = u' ' * width
353 rv = (u'\n' + indention).join(s.splitlines())
359 def do_truncate(s, length=255, killwords=False, end='...'):
360 """Return a truncated copy of the string. The length is specified
361 with the first parameter which defaults to ``255``. If the second
362 parameter is ``true`` the filter will cut the text at length. Otherwise
363 it will try to save the last word. If the text was in fact
364 truncated it will append an ellipsis sign (``"..."``). If you want a
365 different ellipsis sign than ``"..."`` you can specify it using the
368 .. sourcecode jinja::
370 {{ mytext|truncate(300, false, '»') }}
371 truncate mytext to 300 chars, don't split up words, use a
372 right pointing double arrow as ellipsis sign.
377 return s[:length] + end
387 return u' '.join(result)
390 def do_wordwrap(s, width=79, break_long_words=True):
392 Return a copy of the string passed to the filter wrapped after
393 ``79`` characters. You can override this default using the first
394 parameter. If you set the second parameter to `false` Jinja will not
395 split words apart if they are longer than `width`.
398 return u'\n'.join(textwrap.wrap(s, width=width, expand_tabs=False,
399 replace_whitespace=False,
400 break_long_words=break_long_words))
404 """Count the words in that string."""
405 return len(_word_re.findall(s))
408 def do_int(value, default=0):
409 """Convert the value into an integer. If the
410 conversion doesn't work it will return ``0``. You can
411 override this default using the first parameter.
415 except (TypeError, ValueError):
416 # this quirk is necessary so that "42.23"|int gives 42.
418 return int(float(value))
419 except (TypeError, ValueError):
423 def do_float(value, default=0.0):
424 """Convert the value into a floating point number. If the
425 conversion doesn't work it will return ``0.0``. You can
426 override this default using the first parameter.
430 except (TypeError, ValueError):
434 def do_format(value, *args, **kwargs):
436 Apply python string formatting on an object:
438 .. sourcecode:: jinja
440 {{ "%s - %s"|format("Hello?", "Foo!") }}
444 raise FilterArgumentError('can\'t handle positional and keyword '
445 'arguments at the same time')
446 return soft_unicode(value) % (kwargs or args)
450 """Strip leading and trailing whitespace."""
451 return soft_unicode(value).strip()
454 def do_striptags(value):
455 """Strip SGML/XML tags and replace adjacent whitespace by one space.
457 if hasattr(value, '__html__'):
458 value = value.__html__()
459 return Markup(unicode(value)).striptags()
462 def do_slice(value, slices, fill_with=None):
463 """Slice an iterator and return a list of lists containing
464 those items. Useful if you want to create a div containing
465 three ul tags that represent columns:
467 .. sourcecode:: html+jinja
469 <div class="columwrapper">
470 {%- for column in items|slice(3) %}
471 <ul class="column-{{ loop.index }}">
472 {%- for item in column %}
479 If you pass it a second argument it's used to fill missing
480 values on the last iteration.
484 items_per_slice = length // slices
485 slices_with_extra = length % slices
487 for slice_number in xrange(slices):
488 start = offset + slice_number * items_per_slice
489 if slice_number < slices_with_extra:
491 end = offset + (slice_number + 1) * items_per_slice
493 if fill_with is not None and slice_number >= slices_with_extra:
494 tmp.append(fill_with)
498 def do_batch(value, linecount, fill_with=None):
500 A filter that batches items. It works pretty much like `slice`
501 just the other way round. It returns a list of lists with the
502 given number of items. If you provide a second parameter this
503 is used to fill missing items. See this example:
505 .. sourcecode:: html+jinja
508 {%- for row in items|batch(3, ' ') %}
510 {%- for column in row %}
511 <td>{{ column }}</td>
520 if len(tmp) == linecount:
525 if fill_with is not None and len(tmp) < linecount:
526 tmp += [fill_with] * (linecount - len(tmp))
530 def do_round(value, precision=0, method='common'):
531 """Round the number to a given precision. The first
532 parameter specifies the precision (default is ``0``), the
533 second the rounding method:
535 - ``'common'`` rounds either up or down
536 - ``'ceil'`` always rounds up
537 - ``'floor'`` always rounds down
539 If you don't specify a method ``'common'`` is used.
541 .. sourcecode:: jinja
545 {{ 42.55|round(1, 'floor') }}
548 Note that even if rounded to 0 precision, a float is returned. If
549 you need a real integer, pipe it through `int`:
551 .. sourcecode:: jinja
553 {{ 42.55|round|int }}
556 if not method in ('common', 'ceil', 'floor'):
557 raise FilterArgumentError('method must be common, ceil or floor')
558 if method == 'common':
559 return round(value, precision)
560 func = getattr(math, method)
561 return func(value * (10 ** precision)) / (10 ** precision)
565 def do_groupby(environment, value, attribute):
566 """Group a sequence of objects by a common attribute.
568 If you for example have a list of dicts or objects that represent persons
569 with `gender`, `first_name` and `last_name` attributes and you want to
570 group all users by genders you can do something like the following
573 .. sourcecode:: html+jinja
576 {% for group in persons|groupby('gender') %}
577 <li>{{ group.grouper }}<ul>
578 {% for person in group.list %}
579 <li>{{ person.first_name }} {{ person.last_name }}</li>
580 {% endfor %}</ul></li>
584 Additionally it's possible to use tuple unpacking for the grouper and
587 .. sourcecode:: html+jinja
590 {% for grouper, list in persons|groupby('gender') %}
595 As you can see the item we're grouping by is stored in the `grouper`
596 attribute and the `list` contains all the objects that have this grouper
599 expr = lambda x: environment.getitem(x, attribute)
600 return sorted(map(_GroupTuple, groupby(sorted(value, key=expr), expr)))
603 class _GroupTuple(tuple):
605 grouper = property(itemgetter(0))
606 list = property(itemgetter(1))
608 def __new__(cls, (key, value)):
609 return tuple.__new__(cls, (key, list(value)))
613 """Convert the value into a list. If it was a string the returned list
614 will be a list of characters.
619 def do_mark_safe(value):
620 """Mark the value as safe which means that in an environment with automatic
621 escaping enabled this variable will not be escaped.
626 def do_mark_unsafe(value):
627 """Mark a value as unsafe. This is the reverse operation for :func:`safe`."""
628 return unicode(value)
631 def do_reverse(value):
632 """Reverse the object or return an iterator the iterates over it the other
635 if isinstance(value, basestring):
638 return reversed(value)
645 raise FilterArgumentError('argument must be iterable')
649 def do_attr(environment, obj, name):
650 """Get an attribute of an object. ``foo|attr("bar")`` works like
651 ``foo["bar"]`` just that always an attribute is returned and items are not
654 See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details.
662 value = getattr(obj, name)
663 except AttributeError:
666 if environment.sandboxed and not \
667 environment.is_safe_attribute(obj, name, value):
668 return environment.unsafe_undefined(obj, name)
670 return environment.undefined(obj=obj, name=name)
675 'replace': do_replace,
680 'forceescape': do_forceescape,
681 'capitalize': do_capitalize,
683 'default': do_default,
687 'dictsort': do_dictsort,
690 'reverse': do_reverse,
694 'capitalize': do_capitalize,
698 'filesizeformat': do_filesizeformat,
700 'truncate': do_truncate,
701 'wordwrap': do_wordwrap,
702 'wordcount': do_wordcount,
705 'string': soft_unicode,
710 'striptags': do_striptags,
716 'groupby': do_groupby,
717 'safe': do_mark_safe,
718 'xmlattr': do_xmlattr