1 # -*- coding: utf-8 -*-
8 :copyright: (c) 2010 by the Jinja Team.
9 :license: BSD, see LICENSE for more details.
14 from random
import choice
15 from operator
import itemgetter
16 from itertools
import groupby
17 from jinja2
.utils
import Markup
, escape
, pformat
, urlize
, soft_unicode
, \
19 from jinja2
.runtime
import Undefined
20 from jinja2
.exceptions
import FilterArgumentError
21 from jinja2
._compat
import next
, imap
, string_types
, text_type
, iteritems
24 _word_re
= re
.compile(r
'\w+(?u)')
28 """Decorator for marking context dependent filters. The current
29 :class:`Context` will be passed as first argument.
31 f
.contextfilter
= True
35 def evalcontextfilter(f
):
36 """Decorator for marking eval-context dependent filters. An eval
37 context object is passed as first argument. For more information
38 about the eval context, see :ref:`eval-context`.
42 f
.evalcontextfilter
= True
46 def environmentfilter(f
):
47 """Decorator for marking evironment dependent filters. The current
48 :class:`Environment` is passed to the filter as first argument.
50 f
.environmentfilter
= True
54 def make_attrgetter(environment
, attribute
):
55 """Returns a callable that looks up the given attribute from a
56 passed object with the rules of the environment. Dots are allowed
57 to access attributes of attributes. Integer parts in paths are
58 looked up as integers.
60 if not isinstance(attribute
, string_types
) \
61 or ('.' not in attribute
and not attribute
.isdigit()):
62 return lambda x
: environment
.getitem(x
, attribute
)
63 attribute
= attribute
.split('.')
65 for part
in attribute
:
68 item
= environment
.getitem(item
, part
)
73 def do_forceescape(value
):
74 """Enforce HTML escaping. This will probably double escape variables."""
75 if hasattr(value
, '__html__'):
76 value
= value
.__html
__()
77 return escape(text_type(value
))
80 def do_urlencode(value
):
81 """Escape strings for use in URLs (uses UTF-8 encoding). It accepts both
82 dictionaries and regular strings as well as pairwise iterables.
87 if isinstance(value
, dict):
88 itemiter
= iteritems(value
)
89 elif not isinstance(value
, string_types
):
91 itemiter
= iter(value
)
95 return unicode_urlencode(value
)
96 return u
'&'.join(unicode_urlencode(k
) + '=' +
97 unicode_urlencode(v
) for k
, v
in itemiter
)
101 def do_replace(eval_ctx
, s
, old
, new
, count
=None):
102 """Return a copy of the value with all occurrences of a substring
103 replaced with a new one. The first argument is the substring
104 that should be replaced, the second is the replacement string.
105 If the optional third argument ``count`` is given, only the first
106 ``count`` occurrences are replaced:
108 .. sourcecode:: jinja
110 {{ "Hello World"|replace("Hello", "Goodbye") }}
113 {{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
114 -> d'oh, d'oh, aaargh
118 if not eval_ctx
.autoescape
:
119 return text_type(s
).replace(text_type(old
), text_type(new
), count
)
120 if hasattr(old
, '__html__') or hasattr(new
, '__html__') and \
121 not hasattr(s
, '__html__'):
125 return s
.replace(soft_unicode(old
), soft_unicode(new
), count
)
129 """Convert a value to uppercase."""
130 return soft_unicode(s
).upper()
134 """Convert a value to lowercase."""
135 return soft_unicode(s
).lower()
139 def do_xmlattr(_eval_ctx
, d
, autospace
=True):
140 """Create an SGML/XML attribute string based on the items in a dict.
141 All values that are neither `none` nor `undefined` are automatically
144 .. sourcecode:: html+jinja
146 <ul{{ {'class': 'my_list', 'missing': none,
147 'id': 'list-%d'|format(variable)}|xmlattr }}>
151 Results in something like this:
155 <ul class="my_list" id="list-42">
159 As you can see it automatically prepends a space in front of the item
160 if the filter returned something unless the second parameter is false.
163 u
'%s="%s"' % (escape(key
), escape(value
))
164 for key
, value
in iteritems(d
)
165 if value
is not None and not isinstance(value
, Undefined
)
169 if _eval_ctx
.autoescape
:
174 def do_capitalize(s
):
175 """Capitalize a value. The first character will be uppercase, all others
178 return soft_unicode(s
).capitalize()
182 """Return a titlecased version of the value. I.e. words will start with
183 uppercase letters, all remaining characters are lowercase.
186 for item
in re
.compile(r
'([-\s]+)(?u)').split(s
):
189 rv
.append(item
[0].upper() + item
[1:].lower())
193 def do_dictsort(value
, case_sensitive
=False, by
='key'):
194 """Sort a dict and yield (key, value) pairs. Because python dicts are
195 unsorted you may want to use this function to order them by either
198 .. sourcecode:: jinja
200 {% for item in mydict|dictsort %}
201 sort the dict by key, case insensitive
203 {% for item in mydict|dictsort(true) %}
204 sort the dict by key, case sensitive
206 {% for item in mydict|dictsort(false, 'value') %}
207 sort the dict by key, case insensitive, sorted
208 normally and ordered by value.
215 raise FilterArgumentError('You can only sort by either '
219 if isinstance(value
, string_types
) and not case_sensitive
:
220 value
= value
.lower()
223 return sorted(value
.items(), key
=sort_func
)
227 def do_sort(environment
, value
, reverse
=False, case_sensitive
=False,
229 """Sort an iterable. Per default it sorts ascending, if you pass it
230 true as first argument it will reverse the sorting.
232 If the iterable is made of strings the third parameter can be used to
233 control the case sensitiveness of the comparison which is disabled by
236 .. sourcecode:: jinja
238 {% for item in iterable|sort %}
242 It is also possible to sort by an attribute (for example to sort
243 by the date of an object) by specifying the `attribute` parameter:
245 .. sourcecode:: jinja
247 {% for item in iterable|sort(attribute='date') %}
251 .. versionchanged:: 2.6
252 The `attribute` parameter was added.
254 if not case_sensitive
:
256 if isinstance(item
, string_types
):
261 if attribute
is not None:
262 getter
= make_attrgetter(environment
, attribute
)
263 def sort_func(item
, processor
=sort_func
or (lambda x
: x
)):
264 return processor(getter(item
))
265 return sorted(value
, key
=sort_func
, reverse
=reverse
)
268 def do_default(value
, default_value
=u
'', boolean
=False):
269 """If the value is undefined it will return the passed default value,
270 otherwise the value of the variable:
272 .. sourcecode:: jinja
274 {{ my_variable|default('my_variable is not defined') }}
276 This will output the value of ``my_variable`` if the variable was
277 defined, otherwise ``'my_variable is not defined'``. If you want
278 to use default with variables that evaluate to false you have to
279 set the second parameter to `true`:
281 .. sourcecode:: jinja
283 {{ ''|default('the string was empty', true) }}
285 if isinstance(value
, Undefined
) or (boolean
and not value
):
291 def do_join(eval_ctx
, value
, d
=u
'', attribute
=None):
292 """Return a string which is the concatenation of the strings in the
293 sequence. The separator between elements is an empty string per
294 default, you can define it with the optional parameter:
296 .. sourcecode:: jinja
298 {{ [1, 2, 3]|join('|') }}
304 It is also possible to join certain attributes of an object:
306 .. sourcecode:: jinja
308 {{ users|join(', ', attribute='username') }}
310 .. versionadded:: 2.6
311 The `attribute` parameter was added.
313 if attribute
is not None:
314 value
= imap(make_attrgetter(eval_ctx
.environment
, attribute
), value
)
316 # no automatic escaping? joining is a lot eaiser then
317 if not eval_ctx
.autoescape
:
318 return text_type(d
).join(imap(text_type
, value
))
320 # if the delimiter doesn't have an html representation we check
321 # if any of the items has. If yes we do a coercion to Markup
322 if not hasattr(d
, '__html__'):
325 for idx
, item
in enumerate(value
):
326 if hasattr(item
, '__html__'):
329 value
[idx
] = text_type(item
)
336 # no html involved, to normal joining
337 return soft_unicode(d
).join(imap(soft_unicode
, value
))
340 def do_center(value
, width
=80):
341 """Centers the value in a field of a given width."""
342 return text_type(value
).center(width
)
346 def do_first(environment
, seq
):
347 """Return the first item of a sequence."""
349 return next(iter(seq
))
350 except StopIteration:
351 return environment
.undefined('No first item, sequence was empty.')
355 def do_last(environment
, seq
):
356 """Return the last item of a sequence."""
358 return next(iter(reversed(seq
)))
359 except StopIteration:
360 return environment
.undefined('No last item, sequence was empty.')
364 def do_random(environment
, seq
):
365 """Return a random item from the sequence."""
369 return environment
.undefined('No random item, sequence was empty.')
372 def do_filesizeformat(value
, binary
=False):
373 """Format the value like a 'human-readable' file size (i.e. 13 kB,
374 4.1 MB, 102 Bytes, etc). Per default decimal prefixes are used (Mega,
375 Giga, etc.), if the second parameter is set to `True` the binary
376 prefixes are used (Mebi, Gibi).
379 base
= binary
and 1024 or 1000
381 (binary
and 'KiB' or 'kB'),
382 (binary
and 'MiB' or 'MB'),
383 (binary
and 'GiB' or 'GB'),
384 (binary
and 'TiB' or 'TB'),
385 (binary
and 'PiB' or 'PB'),
386 (binary
and 'EiB' or 'EB'),
387 (binary
and 'ZiB' or 'ZB'),
388 (binary
and 'YiB' or 'YB')
393 return '%d Bytes' % bytes
395 for i
, prefix
in enumerate(prefixes
):
396 unit
= base
** (i
+ 2)
398 return '%.1f %s' % ((base
* bytes
/ unit
), prefix
)
399 return '%.1f %s' % ((base
* bytes
/ unit
), prefix
)
402 def do_pprint(value
, verbose
=False):
403 """Pretty print a variable. Useful for debugging.
405 With Jinja 1.2 onwards you can pass it a parameter. If this parameter
406 is truthy the output will be more verbose (this requires `pretty`)
408 return pformat(value
, verbose
=verbose
)
412 def do_urlize(eval_ctx
, value
, trim_url_limit
=None, nofollow
=False):
413 """Converts URLs in plain text into clickable links.
415 If you pass the filter an additional integer it will shorten the urls
416 to that number. Also a third argument exists that makes the urls
419 .. sourcecode:: jinja
421 {{ mytext|urlize(40, true) }}
422 links are shortened to 40 chars and defined with rel="nofollow"
424 rv
= urlize(value
, trim_url_limit
, nofollow
)
425 if eval_ctx
.autoescape
:
430 def do_indent(s
, width
=4, indentfirst
=False):
431 """Return a copy of the passed string, each line indented by
432 4 spaces. The first line is not indented. If you want to
433 change the number of spaces or indent the first line too
434 you can pass additional parameters to the filter:
436 .. sourcecode:: jinja
438 {{ mytext|indent(2, true) }}
439 indent by two spaces and indent the first line too.
441 indention
= u
' ' * width
442 rv
= (u
'\n' + indention
).join(s
.splitlines())
448 def do_truncate(s
, length
=255, killwords
=False, end
='...'):
449 """Return a truncated copy of the string. The length is specified
450 with the first parameter which defaults to ``255``. If the second
451 parameter is ``true`` the filter will cut the text at length. Otherwise
452 it will discard the last word. If the text was in fact
453 truncated it will append an ellipsis sign (``"..."``). If you want a
454 different ellipsis sign than ``"..."`` you can specify it using the
457 .. sourcecode:: jinja
459 {{ "foo bar"|truncate(5) }}
461 {{ "foo bar"|truncate(5, True) }}
467 return s
[:length
] + end
477 return u
' '.join(result
)
480 def do_wordwrap(environment
, s
, width
=79, break_long_words
=True,
483 Return a copy of the string passed to the filter wrapped after
484 ``79`` characters. You can override this default using the first
485 parameter. If you set the second parameter to `false` Jinja will not
486 split words apart if they are longer than `width`. By default, the newlines
487 will be the default newlines for the environment, but this can be changed
488 using the wrapstring keyword argument.
490 .. versionadded:: 2.7
491 Added support for the `wrapstring` parameter.
494 wrapstring
= environment
.newline_sequence
496 return wrapstring
.join(textwrap
.wrap(s
, width
=width
, expand_tabs
=False,
497 replace_whitespace
=False,
498 break_long_words
=break_long_words
))
502 """Count the words in that string."""
503 return len(_word_re
.findall(s
))
506 def do_int(value
, default
=0):
507 """Convert the value into an integer. If the
508 conversion doesn't work it will return ``0``. You can
509 override this default using the first parameter.
513 except (TypeError, ValueError):
514 # this quirk is necessary so that "42.23"|int gives 42.
516 return int(float(value
))
517 except (TypeError, ValueError):
521 def do_float(value
, default
=0.0):
522 """Convert the value into a floating point number. If the
523 conversion doesn't work it will return ``0.0``. You can
524 override this default using the first parameter.
528 except (TypeError, ValueError):
532 def do_format(value
, *args
, **kwargs
):
534 Apply python string formatting on an object:
536 .. sourcecode:: jinja
538 {{ "%s - %s"|format("Hello?", "Foo!") }}
542 raise FilterArgumentError('can\'t handle positional and keyword '
543 'arguments at the same time')
544 return soft_unicode(value
) % (kwargs
or args
)
548 """Strip leading and trailing whitespace."""
549 return soft_unicode(value
).strip()
552 def do_striptags(value
):
553 """Strip SGML/XML tags and replace adjacent whitespace by one space.
555 if hasattr(value
, '__html__'):
556 value
= value
.__html
__()
557 return Markup(text_type(value
)).striptags()
560 def do_slice(value
, slices
, fill_with
=None):
561 """Slice an iterator and return a list of lists containing
562 those items. Useful if you want to create a div containing
563 three ul tags that represent columns:
565 .. sourcecode:: html+jinja
567 <div class="columwrapper">
568 {%- for column in items|slice(3) %}
569 <ul class="column-{{ loop.index }}">
570 {%- for item in column %}
577 If you pass it a second argument it's used to fill missing
578 values on the last iteration.
582 items_per_slice
= length
// slices
583 slices_with_extra
= length
% slices
585 for slice_number
in range(slices
):
586 start
= offset
+ slice_number
* items_per_slice
587 if slice_number
< slices_with_extra
:
589 end
= offset
+ (slice_number
+ 1) * items_per_slice
591 if fill_with
is not None and slice_number
>= slices_with_extra
:
592 tmp
.append(fill_with
)
596 def do_batch(value
, linecount
, fill_with
=None):
598 A filter that batches items. It works pretty much like `slice`
599 just the other way round. It returns a list of lists with the
600 given number of items. If you provide a second parameter this
601 is used to fill up missing items. See this example:
603 .. sourcecode:: html+jinja
606 {%- for row in items|batch(3, ' ') %}
608 {%- for column in row %}
609 <td>{{ column }}</td>
618 if len(tmp
) == linecount
:
623 if fill_with
is not None and len(tmp
) < linecount
:
624 tmp
+= [fill_with
] * (linecount
- len(tmp
))
628 def do_round(value
, precision
=0, method
='common'):
629 """Round the number to a given precision. The first
630 parameter specifies the precision (default is ``0``), the
631 second the rounding method:
633 - ``'common'`` rounds either up or down
634 - ``'ceil'`` always rounds up
635 - ``'floor'`` always rounds down
637 If you don't specify a method ``'common'`` is used.
639 .. sourcecode:: jinja
643 {{ 42.55|round(1, 'floor') }}
646 Note that even if rounded to 0 precision, a float is returned. If
647 you need a real integer, pipe it through `int`:
649 .. sourcecode:: jinja
651 {{ 42.55|round|int }}
654 if not method
in ('common', 'ceil', 'floor'):
655 raise FilterArgumentError('method must be common, ceil or floor')
656 if method
== 'common':
657 return round(value
, precision
)
658 func
= getattr(math
, method
)
659 return func(value
* (10 ** precision
)) / (10 ** precision
)
663 def do_groupby(environment
, value
, attribute
):
664 """Group a sequence of objects by a common attribute.
666 If you for example have a list of dicts or objects that represent persons
667 with `gender`, `first_name` and `last_name` attributes and you want to
668 group all users by genders you can do something like the following
671 .. sourcecode:: html+jinja
674 {% for group in persons|groupby('gender') %}
675 <li>{{ group.grouper }}<ul>
676 {% for person in group.list %}
677 <li>{{ person.first_name }} {{ person.last_name }}</li>
678 {% endfor %}</ul></li>
682 Additionally it's possible to use tuple unpacking for the grouper and
685 .. sourcecode:: html+jinja
688 {% for grouper, list in persons|groupby('gender') %}
693 As you can see the item we're grouping by is stored in the `grouper`
694 attribute and the `list` contains all the objects that have this grouper
697 .. versionchanged:: 2.6
698 It's now possible to use dotted notation to group by the child
699 attribute of another attribute.
701 expr
= make_attrgetter(environment
, attribute
)
702 return sorted(map(_GroupTuple
, groupby(sorted(value
, key
=expr
), expr
)))
705 class _GroupTuple(tuple):
707 grouper
= property(itemgetter(0))
708 list = property(itemgetter(1))
710 def __new__(cls
, xxx_todo_changeme
):
711 (key
, value
) = xxx_todo_changeme
712 return tuple.__new
__(cls
, (key
, list(value
)))
716 def do_sum(environment
, iterable
, attribute
=None, start
=0):
717 """Returns the sum of a sequence of numbers plus the value of parameter
718 'start' (which defaults to 0). When the sequence is empty it returns
721 It is also possible to sum up only certain attributes:
723 .. sourcecode:: jinja
725 Total: {{ items|sum(attribute='price') }}
727 .. versionchanged:: 2.6
728 The `attribute` parameter was added to allow suming up over
729 attributes. Also the `start` parameter was moved on to the right.
731 if attribute
is not None:
732 iterable
= imap(make_attrgetter(environment
, attribute
), iterable
)
733 return sum(iterable
, start
)
737 """Convert the value into a list. If it was a string the returned list
738 will be a list of characters.
743 def do_mark_safe(value
):
744 """Mark the value as safe which means that in an environment with automatic
745 escaping enabled this variable will not be escaped.
750 def do_mark_unsafe(value
):
751 """Mark a value as unsafe. This is the reverse operation for :func:`safe`."""
752 return text_type(value
)
755 def do_reverse(value
):
756 """Reverse the object or return an iterator the iterates over it the other
759 if isinstance(value
, string_types
):
762 return reversed(value
)
769 raise FilterArgumentError('argument must be iterable')
773 def do_attr(environment
, obj
, name
):
774 """Get an attribute of an object. ``foo|attr("bar")`` works like
775 ``foo["bar"]`` just that always an attribute is returned and items are not
778 See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details.
786 value
= getattr(obj
, name
)
787 except AttributeError:
790 if environment
.sandboxed
and not \
791 environment
.is_safe_attribute(obj
, name
, value
):
792 return environment
.unsafe_undefined(obj
, name
)
794 return environment
.undefined(obj
=obj
, name
=name
)
798 def do_map(*args
, **kwargs
):
799 """Applies a filter on a sequence of objects or looks up an attribute.
800 This is useful when dealing with lists of objects but you are really
801 only interested in a certain value of it.
803 The basic usage is mapping on an attribute. Imagine you have a list
804 of users but you are only interested in a list of usernames:
806 .. sourcecode:: jinja
808 Users on this page: {{ users|map(attribute='username')|join(', ') }}
810 Alternatively you can let it invoke a filter by passing the name of the
811 filter and the arguments afterwards. A good example would be applying a
812 text conversion filter on a sequence:
814 .. sourcecode:: jinja
816 Users on this page: {{ titles|map('lower')|join(', ') }}
818 .. versionadded:: 2.7
823 if len(args
) == 2 and 'attribute' in kwargs
:
824 attribute
= kwargs
.pop('attribute')
826 raise FilterArgumentError('Unexpected keyword argument %r' %
828 func
= make_attrgetter(context
.environment
, attribute
)
834 raise FilterArgumentError('map requires a filter argument')
835 func
= lambda item
: context
.environment
.call_filter(
836 name
, item
, args
, kwargs
, context
=context
)
844 def do_select(*args
, **kwargs
):
845 """Filters a sequence of objects by appying a test to either the object
846 or the attribute and only selecting the ones with the test succeeding.
850 .. sourcecode:: jinja
852 {{ numbers|select("odd") }}
854 .. versionadded:: 2.7
856 return _select_or_reject(args
, kwargs
, lambda x
: x
, False)
860 def do_reject(*args
, **kwargs
):
861 """Filters a sequence of objects by appying a test to either the object
862 or the attribute and rejecting the ones with the test succeeding.
866 .. sourcecode:: jinja
868 {{ numbers|reject("odd") }}
870 .. versionadded:: 2.7
872 return _select_or_reject(args
, kwargs
, lambda x
: not x
, False)
876 def do_selectattr(*args
, **kwargs
):
877 """Filters a sequence of objects by appying a test to either the object
878 or the attribute and only selecting the ones with the test succeeding.
882 .. sourcecode:: jinja
884 {{ users|selectattr("is_active") }}
885 {{ users|selectattr("email", "none") }}
887 .. versionadded:: 2.7
889 return _select_or_reject(args
, kwargs
, lambda x
: x
, True)
893 def do_rejectattr(*args
, **kwargs
):
894 """Filters a sequence of objects by appying a test to either the object
895 or the attribute and rejecting the ones with the test succeeding.
897 .. sourcecode:: jinja
899 {{ users|rejectattr("is_active") }}
900 {{ users|rejectattr("email", "none") }}
902 .. versionadded:: 2.7
904 return _select_or_reject(args
, kwargs
, lambda x
: not x
, True)
907 def _select_or_reject(args
, kwargs
, modfunc
, lookup_attr
):
914 raise FilterArgumentError('Missing parameter for attribute name')
915 transfunc
= make_attrgetter(context
.environment
, attr
)
919 transfunc
= lambda x
: x
923 args
= args
[3 + off
:]
924 func
= lambda item
: context
.environment
.call_test(
925 name
, item
, args
, kwargs
)
931 if modfunc(func(transfunc(item
))):
937 'replace': do_replace
,
942 'forceescape': do_forceescape
,
943 'capitalize': do_capitalize
,
945 'default': do_default
,
949 'dictsort': do_dictsort
,
952 'reverse': do_reverse
,
956 'capitalize': do_capitalize
,
962 'rejectattr': do_rejectattr
,
963 'filesizeformat': do_filesizeformat
,
965 'truncate': do_truncate
,
966 'wordwrap': do_wordwrap
,
967 'wordcount': do_wordcount
,
970 'string': soft_unicode
,
975 'striptags': do_striptags
,
977 'selectattr': do_selectattr
,
983 'groupby': do_groupby
,
984 'safe': do_mark_safe
,
985 'xmlattr': do_xmlattr
,
986 'urlencode': do_urlencode