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 make_attrgetter(environment
, attribute
):
52 """Returns a callable that looks up the given attribute from a
53 passed object with the rules of the environment. Dots are allowed
54 to access attributes of attributes.
56 if not isinstance(attribute
, basestring
) or '.' not in attribute
:
57 return lambda x
: environment
.getitem(x
, attribute
)
58 attribute
= attribute
.split('.')
60 for part
in attribute
:
61 item
= environment
.getitem(item
, part
)
66 def do_forceescape(value
):
67 """Enforce HTML escaping. This will probably double escape variables."""
68 if hasattr(value
, '__html__'):
69 value
= value
.__html
__()
70 return escape(unicode(value
))
74 def do_replace(eval_ctx
, s
, old
, new
, count
=None):
75 """Return a copy of the value with all occurrences of a substring
76 replaced with a new one. The first argument is the substring
77 that should be replaced, the second is the replacement string.
78 If the optional third argument ``count`` is given, only the first
79 ``count`` occurrences are replaced:
83 {{ "Hello World"|replace("Hello", "Goodbye") }}
86 {{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
91 if not eval_ctx
.autoescape
:
92 return unicode(s
).replace(unicode(old
), unicode(new
), count
)
93 if hasattr(old
, '__html__') or hasattr(new
, '__html__') and \
94 not hasattr(s
, '__html__'):
98 return s
.replace(soft_unicode(old
), soft_unicode(new
), count
)
102 """Convert a value to uppercase."""
103 return soft_unicode(s
).upper()
107 """Convert a value to lowercase."""
108 return soft_unicode(s
).lower()
112 def do_xmlattr(_eval_ctx
, d
, autospace
=True):
113 """Create an SGML/XML attribute string based on the items in a dict.
114 All values that are neither `none` nor `undefined` are automatically
117 .. sourcecode:: html+jinja
119 <ul{{ {'class': 'my_list', 'missing': none,
120 'id': 'list-%d'|format(variable)}|xmlattr }}>
124 Results in something like this:
128 <ul class="my_list" id="list-42">
132 As you can see it automatically prepends a space in front of the item
133 if the filter returned something unless the second parameter is false.
136 u
'%s="%s"' % (escape(key
), escape(value
))
137 for key
, value
in d
.iteritems()
138 if value
is not None and not isinstance(value
, Undefined
)
142 if _eval_ctx
.autoescape
:
147 def do_capitalize(s
):
148 """Capitalize a value. The first character will be uppercase, all others
151 return soft_unicode(s
).capitalize()
155 """Return a titlecased version of the value. I.e. words will start with
156 uppercase letters, all remaining characters are lowercase.
158 return soft_unicode(s
).title()
161 def do_dictsort(value
, case_sensitive
=False, by
='key'):
162 """Sort a dict and yield (key, value) pairs. Because python dicts are
163 unsorted you may want to use this function to order them by either
166 .. sourcecode:: jinja
168 {% for item in mydict|dictsort %}
169 sort the dict by key, case insensitive
171 {% for item in mydict|dicsort(true) %}
172 sort the dict by key, case sensitive
174 {% for item in mydict|dictsort(false, 'value') %}
175 sort the dict by key, case insensitive, sorted
176 normally and ordered by value.
183 raise FilterArgumentError('You can only sort by either '
187 if isinstance(value
, basestring
) and not case_sensitive
:
188 value
= value
.lower()
191 return sorted(value
.items(), key
=sort_func
)
195 def do_sort(environment
, value
, reverse
=False, case_sensitive
=False,
197 """Sort an iterable. Per default it sorts ascending, if you pass it
198 true as first argument it will reverse the sorting.
200 If the iterable is made of strings the third parameter can be used to
201 control the case sensitiveness of the comparison which is disabled by
204 .. sourcecode:: jinja
206 {% for item in iterable|sort %}
210 It is also possible to sort by an attribute (for example to sort
211 by the date of an object) by specifying the `attribute` parameter:
213 .. sourcecode:: jinja
215 {% for item in iterable|sort(attribute='date') %}
219 .. versionchanged:: 2.6
220 The `attribute` parameter was added.
222 if not case_sensitive
:
224 if isinstance(item
, basestring
):
229 if attribute
is not None:
230 getter
= make_attrgetter(environment
, attribute
)
231 def sort_func(item
, processor
=sort_func
or (lambda x
: x
)):
232 return processor(getter(item
))
233 return sorted(value
, key
=sort_func
, reverse
=reverse
)
236 def do_default(value
, default_value
=u
'', boolean
=False):
237 """If the value is undefined it will return the passed default value,
238 otherwise the value of the variable:
240 .. sourcecode:: jinja
242 {{ my_variable|default('my_variable is not defined') }}
244 This will output the value of ``my_variable`` if the variable was
245 defined, otherwise ``'my_variable is not defined'``. If you want
246 to use default with variables that evaluate to false you have to
247 set the second parameter to `true`:
249 .. sourcecode:: jinja
251 {{ ''|default('the string was empty', true) }}
253 if (boolean
and not value
) or isinstance(value
, Undefined
):
259 def do_join(eval_ctx
, value
, d
=u
'', attribute
=None):
260 """Return a string which is the concatenation of the strings in the
261 sequence. The separator between elements is an empty string per
262 default, you can define it with the optional parameter:
264 .. sourcecode:: jinja
266 {{ [1, 2, 3]|join('|') }}
272 It is also possible to join certain attributes of an object:
274 .. sourcecode:: jinja
276 {{ users|join(', ', attribute='username') }}
278 .. versionadded:: 2.6
279 The `attribute` parameter was added.
281 if attribute
is not None:
282 value
= imap(make_attrgetter(eval_ctx
.environment
, attribute
), value
)
284 # no automatic escaping? joining is a lot eaiser then
285 if not eval_ctx
.autoescape
:
286 return unicode(d
).join(imap(unicode, value
))
288 # if the delimiter doesn't have an html representation we check
289 # if any of the items has. If yes we do a coercion to Markup
290 if not hasattr(d
, '__html__'):
293 for idx
, item
in enumerate(value
):
294 if hasattr(item
, '__html__'):
297 value
[idx
] = unicode(item
)
304 # no html involved, to normal joining
305 return soft_unicode(d
).join(imap(soft_unicode
, value
))
308 def do_center(value
, width
=80):
309 """Centers the value in a field of a given width."""
310 return unicode(value
).center(width
)
314 def do_first(environment
, seq
):
315 """Return the first item of a sequence."""
317 return iter(seq
).next()
318 except StopIteration:
319 return environment
.undefined('No first item, sequence was empty.')
323 def do_last(environment
, seq
):
324 """Return the last item of a sequence."""
326 return iter(reversed(seq
)).next()
327 except StopIteration:
328 return environment
.undefined('No last item, sequence was empty.')
332 def do_random(environment
, seq
):
333 """Return a random item from the sequence."""
337 return environment
.undefined('No random item, sequence was empty.')
340 def do_filesizeformat(value
, binary
=False):
341 """Format the value like a 'human-readable' file size (i.e. 13 kB,
342 4.1 MB, 102 Bytes, etc). Per default decimal prefixes are used (Mega,
343 Giga, etc.), if the second parameter is set to `True` the binary
344 prefixes are used (Mebi, Gibi).
347 base
= binary
and 1024 or 1000
349 (binary
and "KiB" or "kB"),
350 (binary
and "MiB" or "MB"),
351 (binary
and "GiB" or "GB"),
352 (binary
and "TiB" or "TB"),
353 (binary
and "PiB" or "PB"),
354 (binary
and "EiB" or "EB"),
355 (binary
and "ZiB" or "ZB"),
356 (binary
and "YiB" or "YB")
361 return "%d Bytes" % bytes
363 for i
, prefix
in enumerate(prefixes
):
364 unit
= base
* base
** (i
+ 1)
366 return "%.1f %s" % ((bytes
/ unit
), prefix
)
367 return "%.1f %s" % ((bytes
/ unit
), prefix
)
370 def do_pprint(value
, verbose
=False):
371 """Pretty print a variable. Useful for debugging.
373 With Jinja 1.2 onwards you can pass it a parameter. If this parameter
374 is truthy the output will be more verbose (this requires `pretty`)
376 return pformat(value
, verbose
=verbose
)
380 def do_urlize(eval_ctx
, value
, trim_url_limit
=None, nofollow
=False):
381 """Converts URLs in plain text into clickable links.
383 If you pass the filter an additional integer it will shorten the urls
384 to that number. Also a third argument exists that makes the urls
387 .. sourcecode:: jinja
389 {{ mytext|urlize(40, true) }}
390 links are shortened to 40 chars and defined with rel="nofollow"
392 rv
= urlize(value
, trim_url_limit
, nofollow
)
393 if eval_ctx
.autoescape
:
398 def do_indent(s
, width
=4, indentfirst
=False):
399 """Return a copy of the passed string, each line indented by
400 4 spaces. The first line is not indented. If you want to
401 change the number of spaces or indent the first line too
402 you can pass additional parameters to the filter:
404 .. sourcecode:: jinja
406 {{ mytext|indent(2, true) }}
407 indent by two spaces and indent the first line too.
409 indention
= u
' ' * width
410 rv
= (u
'\n' + indention
).join(s
.splitlines())
416 def do_truncate(s
, length
=255, killwords
=False, end
='...'):
417 """Return a truncated copy of the string. The length is specified
418 with the first parameter which defaults to ``255``. If the second
419 parameter is ``true`` the filter will cut the text at length. Otherwise
420 it will try to save the last word. If the text was in fact
421 truncated it will append an ellipsis sign (``"..."``). If you want a
422 different ellipsis sign than ``"..."`` you can specify it using the
425 .. sourcecode jinja::
427 {{ mytext|truncate(300, false, '»') }}
428 truncate mytext to 300 chars, don't split up words, use a
429 right pointing double arrow as ellipsis sign.
434 return s
[:length
] + end
444 return u
' '.join(result
)
447 def do_wordwrap(environment
, s
, width
=79, break_long_words
=True):
449 Return a copy of the string passed to the filter wrapped after
450 ``79`` characters. You can override this default using the first
451 parameter. If you set the second parameter to `false` Jinja will not
452 split words apart if they are longer than `width`.
455 return environment
.newline_sequence
.join(textwrap
.wrap(s
, width
=width
, expand_tabs
=False,
456 replace_whitespace
=False,
457 break_long_words
=break_long_words
))
461 """Count the words in that string."""
462 return len(_word_re
.findall(s
))
465 def do_int(value
, default
=0):
466 """Convert the value into an integer. If the
467 conversion doesn't work it will return ``0``. You can
468 override this default using the first parameter.
472 except (TypeError, ValueError):
473 # this quirk is necessary so that "42.23"|int gives 42.
475 return int(float(value
))
476 except (TypeError, ValueError):
480 def do_float(value
, default
=0.0):
481 """Convert the value into a floating point number. If the
482 conversion doesn't work it will return ``0.0``. You can
483 override this default using the first parameter.
487 except (TypeError, ValueError):
491 def do_format(value
, *args
, **kwargs
):
493 Apply python string formatting on an object:
495 .. sourcecode:: jinja
497 {{ "%s - %s"|format("Hello?", "Foo!") }}
501 raise FilterArgumentError('can\'t handle positional and keyword '
502 'arguments at the same time')
503 return soft_unicode(value
) % (kwargs
or args
)
507 """Strip leading and trailing whitespace."""
508 return soft_unicode(value
).strip()
511 def do_striptags(value
):
512 """Strip SGML/XML tags and replace adjacent whitespace by one space.
514 if hasattr(value
, '__html__'):
515 value
= value
.__html
__()
516 return Markup(unicode(value
)).striptags()
519 def do_slice(value
, slices
, fill_with
=None):
520 """Slice an iterator and return a list of lists containing
521 those items. Useful if you want to create a div containing
522 three ul tags that represent columns:
524 .. sourcecode:: html+jinja
526 <div class="columwrapper">
527 {%- for column in items|slice(3) %}
528 <ul class="column-{{ loop.index }}">
529 {%- for item in column %}
536 If you pass it a second argument it's used to fill missing
537 values on the last iteration.
541 items_per_slice
= length
// slices
542 slices_with_extra
= length
% slices
544 for slice_number
in xrange(slices
):
545 start
= offset
+ slice_number
* items_per_slice
546 if slice_number
< slices_with_extra
:
548 end
= offset
+ (slice_number
+ 1) * items_per_slice
550 if fill_with
is not None and slice_number
>= slices_with_extra
:
551 tmp
.append(fill_with
)
555 def do_batch(value
, linecount
, fill_with
=None):
557 A filter that batches items. It works pretty much like `slice`
558 just the other way round. It returns a list of lists with the
559 given number of items. If you provide a second parameter this
560 is used to fill missing items. See this example:
562 .. sourcecode:: html+jinja
565 {%- for row in items|batch(3, ' ') %}
567 {%- for column in row %}
568 <td>{{ column }}</td>
577 if len(tmp
) == linecount
:
582 if fill_with
is not None and len(tmp
) < linecount
:
583 tmp
+= [fill_with
] * (linecount
- len(tmp
))
587 def do_round(value
, precision
=0, method
='common'):
588 """Round the number to a given precision. The first
589 parameter specifies the precision (default is ``0``), the
590 second the rounding method:
592 - ``'common'`` rounds either up or down
593 - ``'ceil'`` always rounds up
594 - ``'floor'`` always rounds down
596 If you don't specify a method ``'common'`` is used.
598 .. sourcecode:: jinja
602 {{ 42.55|round(1, 'floor') }}
605 Note that even if rounded to 0 precision, a float is returned. If
606 you need a real integer, pipe it through `int`:
608 .. sourcecode:: jinja
610 {{ 42.55|round|int }}
613 if not method
in ('common', 'ceil', 'floor'):
614 raise FilterArgumentError('method must be common, ceil or floor')
615 if method
== 'common':
616 return round(value
, precision
)
617 func
= getattr(math
, method
)
618 return func(value
* (10 ** precision
)) / (10 ** precision
)
622 def do_groupby(environment
, value
, attribute
):
623 """Group a sequence of objects by a common attribute.
625 If you for example have a list of dicts or objects that represent persons
626 with `gender`, `first_name` and `last_name` attributes and you want to
627 group all users by genders you can do something like the following
630 .. sourcecode:: html+jinja
633 {% for group in persons|groupby('gender') %}
634 <li>{{ group.grouper }}<ul>
635 {% for person in group.list %}
636 <li>{{ person.first_name }} {{ person.last_name }}</li>
637 {% endfor %}</ul></li>
641 Additionally it's possible to use tuple unpacking for the grouper and
644 .. sourcecode:: html+jinja
647 {% for grouper, list in persons|groupby('gender') %}
652 As you can see the item we're grouping by is stored in the `grouper`
653 attribute and the `list` contains all the objects that have this grouper
656 .. versionchanged:: 2.6
657 It's now possible to use dotted notation to group by the child
658 attribute of another attribute.
660 expr
= make_attrgetter(environment
, attribute
)
661 return sorted(map(_GroupTuple
, groupby(sorted(value
, key
=expr
), expr
)))
664 class _GroupTuple(tuple):
666 grouper
= property(itemgetter(0))
667 list = property(itemgetter(1))
669 def __new__(cls
, (key
, value
)):
670 return tuple.__new
__(cls
, (key
, list(value
)))
674 def do_sum(environment
, iterable
, attribute
=None, start
=0):
675 """Returns the sum of a sequence of numbers plus the value of parameter
676 'start' (which defaults to 0). When the sequence is empty it returns
679 It is also possible to sum up only certain attributes:
681 .. sourcecode:: jinja
683 Total: {{ items|sum(attribute='price') }}
685 .. versionchanged:: 2.6
686 The `attribute` parameter was added to allow suming up over
687 attributes. Also the `start` parameter was moved on to the right.
689 if attribute
is not None:
690 iterable
= imap(make_attrgetter(environment
, attribute
), iterable
)
691 return sum(iterable
, start
)
695 """Convert the value into a list. If it was a string the returned list
696 will be a list of characters.
701 def do_mark_safe(value
):
702 """Mark the value as safe which means that in an environment with automatic
703 escaping enabled this variable will not be escaped.
708 def do_mark_unsafe(value
):
709 """Mark a value as unsafe. This is the reverse operation for :func:`safe`."""
710 return unicode(value
)
713 def do_reverse(value
):
714 """Reverse the object or return an iterator the iterates over it the other
717 if isinstance(value
, basestring
):
720 return reversed(value
)
727 raise FilterArgumentError('argument must be iterable')
731 def do_attr(environment
, obj
, name
):
732 """Get an attribute of an object. ``foo|attr("bar")`` works like
733 ``foo["bar"]`` just that always an attribute is returned and items are not
736 See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details.
744 value
= getattr(obj
, name
)
745 except AttributeError:
748 if environment
.sandboxed
and not \
749 environment
.is_safe_attribute(obj
, name
, value
):
750 return environment
.unsafe_undefined(obj
, name
)
752 return environment
.undefined(obj
=obj
, name
=name
)
757 'replace': do_replace
,
762 'forceescape': do_forceescape
,
763 'capitalize': do_capitalize
,
765 'default': do_default
,
769 'dictsort': do_dictsort
,
772 'reverse': do_reverse
,
776 'capitalize': do_capitalize
,
780 'filesizeformat': do_filesizeformat
,
782 'truncate': do_truncate
,
783 'wordwrap': do_wordwrap
,
784 'wordcount': do_wordcount
,
787 'string': soft_unicode
,
792 'striptags': do_striptags
,
798 'groupby': do_groupby
,
799 'safe': do_mark_safe
,
800 'xmlattr': do_xmlattr