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 if getattr(f, 'environmentfilter', False):
29 raise TypeError('filter already marked as environment filter')
30 f.contextfilter = True
34 def environmentfilter(f):
35 """Decorator for marking evironment dependent filters. The current
36 :class:`Environment` is passed to the filter as first argument.
38 if getattr(f, 'contextfilter', False):
39 raise TypeError('filter already marked as context filter')
40 f.environmentfilter = True
44 def do_forceescape(value):
45 """Enforce HTML escaping. This will probably double escape variables."""
46 if hasattr(value, '__html__'):
47 value = value.__html__()
48 return escape(unicode(value))
52 def do_replace(environment, s, old, new, count=None):
53 """Return a copy of the value with all occurrences of a substring
54 replaced with a new one. The first argument is the substring
55 that should be replaced, the second is the replacement string.
56 If the optional third argument ``count`` is given, only the first
57 ``count`` occurrences are replaced:
61 {{ "Hello World"|replace("Hello", "Goodbye") }}
64 {{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
69 if not environment.autoescape:
70 return unicode(s).replace(unicode(old), unicode(new), count)
71 if hasattr(old, '__html__') or hasattr(new, '__html__') and \
72 not hasattr(s, '__html__'):
76 return s.replace(soft_unicode(old), soft_unicode(new), count)
80 """Convert a value to uppercase."""
81 return soft_unicode(s).upper()
85 """Convert a value to lowercase."""
86 return soft_unicode(s).lower()
90 def do_xmlattr(_environment, d, autospace=True):
91 """Create an SGML/XML attribute string based on the items in a dict.
92 All values that are neither `none` nor `undefined` are automatically
95 .. sourcecode:: html+jinja
97 <ul{{ {'class': 'my_list', 'missing': none,
98 'id': 'list-%d'|format(variable)}|xmlattr }}>
102 Results in something like this:
106 <ul class="my_list" id="list-42">
110 As you can see it automatically prepends a space in front of the item
111 if the filter returned something unless the second parameter is false.
114 u'%s="%s"' % (escape(key), escape(value))
115 for key, value in d.iteritems()
116 if value is not None and not isinstance(value, Undefined)
120 if _environment.autoescape:
125 def do_capitalize(s):
126 """Capitalize a value. The first character will be uppercase, all others
129 return soft_unicode(s).capitalize()
133 """Return a titlecased version of the value. I.e. words will start with
134 uppercase letters, all remaining characters are lowercase.
136 return soft_unicode(s).title()
139 def do_dictsort(value, case_sensitive=False, by='key'):
140 """Sort a dict and yield (key, value) pairs. Because python dicts are
141 unsorted you may want to use this function to order them by either
144 .. sourcecode:: jinja
146 {% for item in mydict|dictsort %}
147 sort the dict by key, case insensitive
149 {% for item in mydict|dicsort(true) %}
150 sort the dict by key, case sensitive
152 {% for item in mydict|dictsort(false, 'value') %}
153 sort the dict by key, case insensitive, sorted
154 normally and ordered by value.
161 raise FilterArgumentError('You can only sort by either '
165 if isinstance(value, basestring) and not case_sensitive:
166 value = value.lower()
169 return sorted(value.items(), key=sort_func)
172 def do_sort(value, case_sensitive=False):
173 """Sort an iterable. If the iterable is made of strings the second
174 parameter can be used to control the case sensitiveness of the
175 comparison which is disabled by default.
177 .. sourcecode:: jinja
179 {% for item in iterable|sort %}
183 if not case_sensitive:
185 if isinstance(item, basestring):
190 return sorted(seq, key=sort_func)
193 def do_default(value, default_value=u'', boolean=False):
194 """If the value is undefined it will return the passed default value,
195 otherwise the value of the variable:
197 .. sourcecode:: jinja
199 {{ my_variable|default('my_variable is not defined') }}
201 This will output the value of ``my_variable`` if the variable was
202 defined, otherwise ``'my_variable is not defined'``. If you want
203 to use default with variables that evaluate to false you have to
204 set the second parameter to `true`:
206 .. sourcecode:: jinja
208 {{ ''|default('the string was empty', true) }}
210 if (boolean and not value) or isinstance(value, Undefined):
216 def do_join(environment, value, d=u''):
217 """Return a string which is the concatenation of the strings in the
218 sequence. The separator between elements is an empty string per
219 default, you can define it with the optional parameter:
221 .. sourcecode:: jinja
223 {{ [1, 2, 3]|join('|') }}
229 # no automatic escaping? joining is a lot eaiser then
230 if not environment.autoescape:
231 return unicode(d).join(imap(unicode, value))
233 # if the delimiter doesn't have an html representation we check
234 # if any of the items has. If yes we do a coercion to Markup
235 if not hasattr(d, '__html__'):
238 for idx, item in enumerate(value):
239 if hasattr(item, '__html__'):
242 value[idx] = unicode(item)
249 # no html involved, to normal joining
250 return soft_unicode(d).join(imap(soft_unicode, value))
253 def do_center(value, width=80):
254 """Centers the value in a field of a given width."""
255 return unicode(value).center(width)
259 def do_first(environment, seq):
260 """Return the first item of a sequence."""
262 return iter(seq).next()
263 except StopIteration:
264 return environment.undefined('No first item, sequence was empty.')
268 def do_last(environment, seq):
269 """Return the last item of a sequence."""
271 return iter(reversed(seq)).next()
272 except StopIteration:
273 return environment.undefined('No last item, sequence was empty.')
277 def do_random(environment, seq):
278 """Return a random item from the sequence."""
282 return environment.undefined('No random item, sequence was empty.')
285 def do_filesizeformat(value, binary=False):
286 """Format the value like a 'human-readable' file size (i.e. 13 KB,
287 4.1 MB, 102 bytes, etc). Per default decimal prefixes are used (mega,
288 giga, etc.), if the second parameter is set to `True` the binary
289 prefixes are used (mebi, gibi).
292 base = binary and 1024 or 1000
293 middle = binary and 'i' or ''
295 return "%d Byte%s" % (bytes, bytes != 1 and 's' or '')
296 elif bytes < base * base:
297 return "%.1f K%sB" % (bytes / base, middle)
298 elif bytes < base * base * base:
299 return "%.1f M%sB" % (bytes / (base * base), middle)
300 return "%.1f G%sB" % (bytes / (base * base * base), middle)
303 def do_pprint(value, verbose=False):
304 """Pretty print a variable. Useful for debugging.
306 With Jinja 1.2 onwards you can pass it a parameter. If this parameter
307 is truthy the output will be more verbose (this requires `pretty`)
309 return pformat(value, verbose=verbose)
313 def do_urlize(environment, value, trim_url_limit=None, nofollow=False):
314 """Converts URLs in plain text into clickable links.
316 If you pass the filter an additional integer it will shorten the urls
317 to that number. Also a third argument exists that makes the urls
320 .. sourcecode:: jinja
322 {{ mytext|urlize(40, true) }}
323 links are shortened to 40 chars and defined with rel="nofollow"
325 rv = urlize(value, trim_url_limit, nofollow)
326 if environment.autoescape:
331 def do_indent(s, width=4, indentfirst=False):
332 """Return a copy of the passed string, each line indented by
333 4 spaces. The first line is not indented. If you want to
334 change the number of spaces or indent the first line too
335 you can pass additional parameters to the filter:
337 .. sourcecode:: jinja
339 {{ mytext|indent(2, true) }}
340 indent by two spaces and indent the first line too.
342 indention = u' ' * width
343 rv = (u'\n' + indention).join(s.splitlines())
349 def do_truncate(s, length=255, killwords=False, end='...'):
350 """Return a truncated copy of the string. The length is specified
351 with the first parameter which defaults to ``255``. If the second
352 parameter is ``true`` the filter will cut the text at length. Otherwise
353 it will try to save the last word. If the text was in fact
354 truncated it will append an ellipsis sign (``"..."``). If you want a
355 different ellipsis sign than ``"..."`` you can specify it using the
358 .. sourcecode jinja::
360 {{ mytext|truncate(300, false, '»') }}
361 truncate mytext to 300 chars, don't split up words, use a
362 right pointing double arrow as ellipsis sign.
367 return s[:length] + end
377 return u' '.join(result)
380 def do_wordwrap(s, width=79, break_long_words=True):
382 Return a copy of the string passed to the filter wrapped after
383 ``79`` characters. You can override this default using the first
384 parameter. If you set the second parameter to `false` Jinja will not
385 split words apart if they are longer than `width`.
388 return u'\n'.join(textwrap.wrap(s, width=width, expand_tabs=False,
389 replace_whitespace=False,
390 break_long_words=break_long_words))
394 """Count the words in that string."""
395 return len(_word_re.findall(s))
398 def do_int(value, default=0):
399 """Convert the value into an integer. If the
400 conversion doesn't work it will return ``0``. You can
401 override this default using the first parameter.
405 except (TypeError, ValueError):
406 # this quirk is necessary so that "42.23"|int gives 42.
408 return int(float(value))
409 except (TypeError, ValueError):
413 def do_float(value, default=0.0):
414 """Convert the value into a floating point number. If the
415 conversion doesn't work it will return ``0.0``. You can
416 override this default using the first parameter.
420 except (TypeError, ValueError):
424 def do_format(value, *args, **kwargs):
426 Apply python string formatting on an object:
428 .. sourcecode:: jinja
430 {{ "%s - %s"|format("Hello?", "Foo!") }}
434 raise FilterArgumentError('can\'t handle positional and keyword '
435 'arguments at the same time')
436 return soft_unicode(value) % (kwargs or args)
440 """Strip leading and trailing whitespace."""
441 return soft_unicode(value).strip()
444 def do_striptags(value):
445 """Strip SGML/XML tags and replace adjacent whitespace by one space.
447 if hasattr(value, '__html__'):
448 value = value.__html__()
449 return Markup(unicode(value)).striptags()
452 def do_slice(value, slices, fill_with=None):
453 """Slice an iterator and return a list of lists containing
454 those items. Useful if you want to create a div containing
455 three ul tags that represent columns:
457 .. sourcecode:: html+jinja
459 <div class="columwrapper">
460 {%- for column in items|slice(3) %}
461 <ul class="column-{{ loop.index }}">
462 {%- for item in column %}
469 If you pass it a second argument it's used to fill missing
470 values on the last iteration.
474 items_per_slice = length // slices
475 slices_with_extra = length % slices
477 for slice_number in xrange(slices):
478 start = offset + slice_number * items_per_slice
479 if slice_number < slices_with_extra:
481 end = offset + (slice_number + 1) * items_per_slice
483 if fill_with is not None and slice_number >= slices_with_extra:
484 tmp.append(fill_with)
488 def do_batch(value, linecount, fill_with=None):
490 A filter that batches items. It works pretty much like `slice`
491 just the other way round. It returns a list of lists with the
492 given number of items. If you provide a second parameter this
493 is used to fill missing items. See this example:
495 .. sourcecode:: html+jinja
498 {%- for row in items|batch(3, ' ') %}
500 {%- for column in row %}
501 <td>{{ column }}</td>
510 if len(tmp) == linecount:
515 if fill_with is not None and len(tmp) < linecount:
516 tmp += [fill_with] * (linecount - len(tmp))
520 def do_round(value, precision=0, method='common'):
521 """Round the number to a given precision. The first
522 parameter specifies the precision (default is ``0``), the
523 second the rounding method:
525 - ``'common'`` rounds either up or down
526 - ``'ceil'`` always rounds up
527 - ``'floor'`` always rounds down
529 If you don't specify a method ``'common'`` is used.
531 .. sourcecode:: jinja
535 {{ 42.55|round(1, 'floor') }}
538 Note that even if rounded to 0 precision, a float is returned. If
539 you need a real integer, pipe it through `int`:
541 .. sourcecode:: jinja
543 {{ 42.55|round|int }}
546 if not method in ('common', 'ceil', 'floor'):
547 raise FilterArgumentError('method must be common, ceil or floor')
549 raise FilterArgumentError('precision must be a postive integer '
551 if method == 'common':
552 return round(value, precision)
553 func = getattr(math, method)
555 return func(value * 10 * precision) / (10 * precision)
560 def do_sort(value, reverse=False):
561 """Sort a sequence. Per default it sorts ascending, if you pass it
562 true as first argument it will reverse the sorting.
564 return sorted(value, reverse=reverse)
568 def do_groupby(environment, value, attribute):
569 """Group a sequence of objects by a common attribute.
571 If you for example have a list of dicts or objects that represent persons
572 with `gender`, `first_name` and `last_name` attributes and you want to
573 group all users by genders you can do something like the following
576 .. sourcecode:: html+jinja
579 {% for group in persons|groupby('gender') %}
580 <li>{{ group.grouper }}<ul>
581 {% for person in group.list %}
582 <li>{{ person.first_name }} {{ person.last_name }}</li>
583 {% endfor %}</ul></li>
587 Additionally it's possible to use tuple unpacking for the grouper and
590 .. sourcecode:: html+jinja
593 {% for grouper, list in persons|groupby('gender') %}
598 As you can see the item we're grouping by is stored in the `grouper`
599 attribute and the `list` contains all the objects that have this grouper
602 expr = lambda x: environment.getitem(x, attribute)
603 return sorted(map(_GroupTuple, groupby(sorted(value, key=expr), expr)))
606 class _GroupTuple(tuple):
608 grouper = property(itemgetter(0))
609 list = property(itemgetter(1))
611 def __new__(cls, (key, value)):
612 return tuple.__new__(cls, (key, list(value)))
616 """Convert the value into a list. If it was a string the returned list
617 will be a list of characters.
622 def do_mark_safe(value):
623 """Mark the value as safe which means that in an environment with automatic
624 escaping enabled this variable will not be escaped.
629 def do_mark_unsafe(value):
630 """Mark a value as unsafe. This is the reverse operation for :func:`safe`."""
631 return unicode(value)
634 def do_reverse(value):
635 """Reverse the object or return an iterator the iterates over it the other
638 if isinstance(value, basestring):
641 return reversed(value)
648 raise FilterArgumentError('argument must be iterable')
652 def do_attr(environment, obj, name):
653 """Get an attribute of an object. ``foo|attr("bar")`` works like
654 ``foo["bar"]`` just that always an attribute is returned and items are not
657 See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details.
665 value = getattr(obj, name)
666 except AttributeError:
669 if environment.sandboxed and not \
670 environment.is_safe_attribute(obj, name, value):
671 return environment.unsafe_undefined(obj, name)
673 return environment.undefined(obj=obj, name=name)
678 'replace': do_replace,
683 'forceescape': do_forceescape,
684 'capitalize': do_capitalize,
686 'default': do_default,
690 'dictsort': do_dictsort,
693 'reverse': do_reverse,
697 'capitalize': do_capitalize,
701 'filesizeformat': do_filesizeformat,
703 'truncate': do_truncate,
704 'wordwrap': do_wordwrap,
705 'wordcount': do_wordcount,
708 'string': soft_unicode,
713 'striptags': do_striptags,
720 'groupby': do_groupby,
721 'safe': do_mark_safe,
722 'xmlattr': do_xmlattr