1 # -*- coding: utf-8 -*-
8 :copyright: 2007 by Armin Ronacher.
9 :license: BSD, see LICENSE for more details.
12 from random import choice
14 from operator import itemgetter
16 itemgetter = lambda a: lambda b: b[a]
17 from urllib import urlencode, quote
20 _striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
25 Decorator for filters that just work on unicode objects.
28 def wrapped(env, context, value):
30 for idx, var in enumerate(nargs):
31 if isinstance(var, str):
32 nargs[idx] = env.to_unicode(var)
33 return f(env.to_unicode(value), *nargs)
36 decorator.__doc__ = f.__doc__
37 decorator.__name__ = f.__name__
45 Decorator for simplifying filters. Filter arguments are passed
46 to the decorated function without environment and context. The
47 source value is the first argument. (like stringfilter but
48 without unicode conversion)
51 def wrapped(env, context, value):
52 return f(value, *args)
55 decorator.__doc__ = f.__doc__
56 decorator.__name__ = f.__name__
62 def do_replace(s, old, new, count=None):
64 Return a copy of the value with all occurrences of a substring
65 replaced with a new one. The first argument is the substring
66 that should be replaced, the second is the replacement string.
67 If the optional third argument ``count`` is given, only the first
68 ``count`` occurrences are replaced:
72 {{ "Hello World"|replace("Hello", "Goodbye") }}
75 {{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
78 if not isinstance(old, basestring) or \
79 not isinstance(new, basestring):
80 raise FilterArgumentError('the replace filter requires '
81 'string replacement arguments')
83 return s.replace(old, new)
84 if not isinstance(count, (int, long)):
85 raise FilterArgumentError('the count parameter of the '
86 'replace filter requires '
88 return s.replace(old, new, count)
89 do_replace = stringfilter(do_replace)
94 Convert a value to uppercase.
97 do_upper = stringfilter(do_upper)
102 Convert a value to lowercase.
105 do_lower = stringfilter(do_lower)
108 def do_escape(attribute=False):
110 XML escape ``&``, ``<``, and ``>`` in a string of data. If the
111 optional parameter is `true` this filter will also convert
112 ``"`` to ``"``. This filter is just used if the environment
113 was configured with disabled `auto_escape`.
115 This method will have no effect it the value is already escaped.
117 #: because filters are cached we can make a local alias to
118 #: speed things up a bit
120 def wrapped(env, context, s):
121 if isinstance(s, TemplateData):
123 elif hasattr(s, '__html__'):
125 #: small speedup, do not convert to unicode if we already
126 #: have an unicode object.
127 if s.__class__ is not unicode:
128 s = env.to_unicode(s)
129 return e(s, attribute)
133 def do_xmlattr(autospace=False):
135 Create an SGML/XML attribute string based on the items in a dict.
136 All values that are neither `none` nor `undefined` are automatically
139 .. sourcecode:: html+jinja
141 <ul{{ {'class': 'my_list', 'missing': None,
142 'id': 'list-%d'|format(variable)}|xmlattr }}>
146 Results in something like this:
150 <ul class="my_list" id="list-42">
154 As you can see it automatically prepends a space in front of the item
155 if the filter returned something. You can disable this by passing
156 `false` as only argument to the filter.
161 def wrapped(env, context, d):
162 if not hasattr(d, 'iteritems'):
163 raise TypeError('a dict is required')
165 for key, value in d.iteritems():
166 if value not in (None, env.undefined_singleton):
167 result.append(u'%s="%s"' % (
168 e(env.to_unicode(key)),
169 e(env.to_unicode(value), True)
171 rv = u' '.join(result)
178 def do_capitalize(s):
180 Capitalize a value. The first character will be uppercase, all others
183 return s.capitalize()
184 do_capitalize = stringfilter(do_capitalize)
189 Return a titlecased version of the value. I.e. words will start with
190 uppercase letters, all remaining characters are lowercase.
193 do_title = stringfilter(do_title)
196 def do_dictsort(case_sensitive=False, by='key'):
198 Sort a dict and yield (key, value) pairs. Because python dicts are
199 unsorted you may want to use this function to order them by either
202 .. sourcecode:: jinja
204 {% for item in mydict|dictsort %}
205 sort the dict by key, case insensitive
207 {% for item in mydict|dicsort(true) %}
208 sort the dict by key, case sensitive
210 {% for item in mydict|dictsort(false, 'value') %}
211 sort the dict by key, case insensitive, sorted
212 normally and ordered by value.
219 raise FilterArgumentError('You can only sort by either '
221 def sort_func(value, env):
222 if isinstance(value, basestring):
223 value = env.to_unicode(value)
224 if not case_sensitive:
225 value = value.lower()
228 def wrapped(env, context, value):
229 items = value.items()
230 items.sort(lambda a, b: cmp(sort_func(a[pos], env),
231 sort_func(b[pos], env)))
236 def do_default(default_value=u'', boolean=False):
238 If the value is undefined it will return the passed default value,
239 otherwise the value of the variable:
241 .. sourcecode:: jinja
243 {{ my_variable|default('my_variable is not defined') }}
245 This will output the value of ``my_variable`` if the variable was
246 defined, otherwise ``'my_variable is not defined'``. If you want
247 to use default with variables that evaluate to false you have to
248 set the second parameter to `true`:
250 .. sourcecode:: jinja
252 {{ ''|default('the string was empty', true) }}
254 def wrapped(env, context, value):
255 if (boolean and not value) or value in (env.undefined_singleton, None):
263 Return a string which is the concatenation of the strings in the
264 sequence. The separator between elements is an empty string per
265 default, you can define ith with the optional parameter:
267 .. sourcecode:: jinja
269 {{ [1, 2, 3]|join('|') }}
275 def wrapped(env, context, value):
276 return env.to_unicode(d).join([env.to_unicode(x) for x in value])
282 Return the length of the value. In case if getting an integer or float
283 it will convert it into a string an return the length of the new
284 string. If the object has no length it will of corse return 0.
286 def wrapped(env, context, value):
288 if type(value) in (int, float, long):
289 return len(str(value))
298 Return a reversed list of the sequence filtered. You can use this
299 for example for reverse iteration:
301 .. sourcecode:: jinja
303 {% for item in seq|reverse %}
307 def wrapped(env, context, value):
317 def do_center(value, width=80):
319 Centers the value in a field of a given width.
321 return value.center(width)
322 do_center = stringfilter(do_center)
327 Return the frist item of a sequence.
329 def wrapped(env, context, seq):
331 return iter(seq).next()
332 except StopIteration:
333 return env.undefined_singleton
339 Return the last item of a sequence.
341 def wrapped(env, context, seq):
343 return iter(reversed(seq)).next()
344 except StopIteration:
345 return env.undefined_singleton
351 Return a random item from the sequence.
353 def wrapped(env, context, seq):
357 return env.undefined_singleton
363 urlencode a string or directory.
365 .. sourcecode:: jinja
367 {{ {'foo': 'bar', 'blub': 'blah'}|urlencode }}
373 def wrapped(env, context, value):
374 if isinstance(value, dict):
376 for key, value in value.iteritems():
377 key = env.to_unicode(key).encode(env.charset)
378 value = env.to_unicode(value).encode(env.charset)
380 return urlencode(tmp)
382 return quote(env.to_unicode(value).encode(env.charset))
388 JSON dump a variable. just works if simplejson is installed.
390 .. sourcecode:: jinja
392 {{ 'Hello World'|jsonencode }}
400 return lambda e, c, v: simplejson.dumps(v)
403 def do_filesizeformat():
405 Format the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, 102
408 def wrapped(env, context, value):
416 return "%d Byte%s" % (bytes, bytes != 1 and 's' or '')
417 elif bytes < 1024 * 1024:
418 return "%.1f KB" % (bytes / 1024)
419 elif bytes < 1024 * 1024 * 1024:
420 return "%.1f MB" % (bytes / (1024 * 1024))
421 return "%.1f GB" % (bytes / (1024 * 1024 * 1024))
425 def do_pprint(verbose=False):
427 Pretty print a variable. Useful for debugging.
429 With Jinja 1.2 onwards you can pass it a parameter. If this parameter
430 is truthy the output will be more verbose (this requires `pretty`)
432 def wrapped(env, context, value):
433 return pformat(value, verbose=verbose)
437 def do_urlize(value, trim_url_limit=None, nofollow=False):
439 Converts URLs in plain text into clickable links.
441 If you pass the filter an additional integer it will shorten the urls
442 to that number. Also a third argument exists that makes the urls
445 .. sourcecode:: jinja
447 {{ mytext|urlize(40, True) }}
448 links are shortened to 40 chars and defined with rel="nofollow"
450 return urlize(value, trim_url_limit, nofollow)
451 do_urlize = stringfilter(do_urlize)
454 def do_indent(s, width=4, indentfirst=False):
456 {{ s|indent[ width[ indentfirst[ usetab]]] }}
458 Return a copy of the passed string, each line indented by
459 4 spaces. The first line is not indented. If you want to
460 change the number of spaces or indent the first line too
461 you can pass additional parameters to the filter:
463 .. sourcecode:: jinja
465 {{ mytext|indent(2, True) }}
466 indent by two spaces and indent the first line too.
468 indention = ' ' * width
470 return u'\n'.join([indention + line for line in s.splitlines()])
471 return s.replace('\n', '\n' + indention)
472 do_indent = stringfilter(do_indent)
475 def do_truncate(s, length=255, killwords=False, end='...'):
477 Return a truncated copy of the string. The length is specified
478 with the first parameter which defaults to ``255``. If the second
479 parameter is ``true`` the filter will cut the text at length. Otherwise
480 it will try to save the last word. If the text was in fact
481 truncated it will append an ellipsis sign (``"..."``). If you want a
482 different ellipsis sign than ``"..."`` you can specify it using the
485 .. sourcecode jinja::
487 {{ mytext|truncate(300, false, '»') }}
488 truncate mytext to 300 chars, don't split up words, use a
489 right pointing double arrow as ellipsis sign.
494 return s[:length] + end
504 return u' '.join(result)
505 do_truncate = stringfilter(do_truncate)
508 def do_wordwrap(s, pos=79, hard=False):
510 Return a copy of the string passed to the filter wrapped after
511 ``79`` characters. You can override this default using the first
512 parameter. If you set the second parameter to `true` Jinja will
513 also split words apart (usually a bad idea because it makes
519 return u'\n'.join([s[idx:idx + pos] for idx in
520 xrange(0, len(s), pos)])
521 # code from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/148061
522 return reduce(lambda line, word, pos=pos: u'%s%s%s' %
523 (line, u' \n'[(len(line)-line.rfind('\n') - 1 +
524 len(word.split('\n', 1)[0]) >= pos)],
526 do_wordwrap = stringfilter(do_wordwrap)
531 Count the words in that string.
533 return len([x for x in s.split() if x])
534 do_wordcount = stringfilter(do_wordcount)
539 Prase the string using textile.
541 requires the `PyTextile`_ library.
543 .. _PyTextile: http://dealmeida.net/projects/textile/
545 from textile import textile
546 return textile(s.encode('utf-8')).decode('utf-8')
547 do_textile = stringfilter(do_textile)
552 Parse the string using markdown.
554 requires the `Python-markdown`_ library.
556 .. _Python-markdown: http://www.freewisdom.org/projects/python-markdown/
558 from markdown import markdown
559 return markdown(s.encode('utf-8')).decode('utf-8')
560 do_markdown = stringfilter(do_markdown)
565 Parse the string using the reStructuredText parser from the
568 requires `docutils`_.
570 .. _docutils: http://docutils.sourceforge.net/
572 from docutils.core import publish_parts
573 parts = publish_parts(source=s, writer_name='html4css1')
574 return parts['fragment']
575 do_rst = stringfilter(do_rst)
578 def do_int(default=0):
580 Convert the value into an integer. If the
581 conversion doesn't work it will return ``0``. You can
582 override this default using the first parameter.
584 def wrapped(env, context, value):
587 except (TypeError, ValueError):
589 return int(float(value))
590 except (TypeError, ValueError):
595 def do_float(default=0.0):
597 Convert the value into a floating point number. If the
598 conversion doesn't work it will return ``0.0``. You can
599 override this default using the first parameter.
601 def wrapped(env, context, value):
604 except (TypeError, ValueError):
611 Convert the value into an string.
613 return lambda e, c, v: e.to_unicode(v)
616 def do_format(*args):
618 Apply python string formatting on an object:
620 .. sourcecode:: jinja
622 {{ "%s - %s"|format("Hello?", "Foo!") }}
625 Note that you cannot use the mapping syntax (``%(name)s``)
626 like in python. Use `|dformat` for that.
628 def wrapped(env, context, value):
629 return env.to_unicode(value) % args
635 Apply python mapping string formatting on an object:
637 .. sourcecode:: jinja
639 {{ "Hello %(username)s!"|dformat({'username': 'John Doe'}) }}
642 This is useful when adding variables to translateable
647 if not isinstance(d, dict):
648 raise FilterArgumentError('dict required')
649 def wrapped(env, context, value):
650 return env.to_unicode(value) % d
656 Strip leading and trailing whitespace.
659 do_trim = stringfilter(do_trim)
662 def do_capture(name='captured', clean=False):
664 Store the value in a variable called ``captured`` or a variable
665 with the name provided. Useful for filter blocks:
667 .. sourcecode:: jinja
669 {% filter capture('foo') %}
674 This will output "..." two times. One time from the filter block
675 and one time from the variable. If you don't want the filter to
676 output something you can use it in `clean` mode:
678 .. sourcecode:: jinja
680 {% filter capture('foo', True) %}
685 if not isinstance(name, basestring):
686 raise FilterArgumentError('You can only capture into variables')
687 def wrapped(env, context, value):
688 context[name] = value
690 return TemplateData()
695 def do_striptags(value):
697 Strip SGML/XML tags and replace adjacent whitespace by one space.
701 return ' '.join(_striptags_re.sub('', value).split())
702 do_striptags = stringfilter(do_striptags)
705 def do_slice(slices, fill_with=None):
707 Slice an iterator and return a list of lists containing
708 those items. Useful if you want to create a div containing
709 three div tags that represent columns:
711 .. sourcecode:: html+jinja
713 <div class="columwrapper">
714 {%- for column in items|slice(3) %}
715 <ul class="column-{{ loop.index }}">
716 {%- for item in column %}
723 If you pass it a second argument it's used to fill missing
724 values on the last iteration.
728 def wrapped(env, context, value):
732 items_per_slice = length // slices
733 slices_with_extra = length % slices
735 for slice_number in xrange(slices):
736 start = offset + slice_number * items_per_slice
737 if slice_number < slices_with_extra:
739 end = offset + (slice_number + 1) * items_per_slice
741 if fill_with is not None and slice_number >= slices_with_extra:
742 tmp.append(fill_with)
748 def do_batch(linecount, fill_with=None):
750 A filter that batches items. It works pretty much like `slice`
751 just the other way round. It returns a list of lists with the
752 given number of items. If you provide a second parameter this
753 is used to fill missing items. See this example:
755 .. sourcecode:: html+jinja
758 {%- for row in items|batch(3, ' ') %}
760 {%- for column in row %}
761 <tr>{{ column }}</td>
769 def wrapped(env, context, value):
773 if len(tmp) == linecount:
778 if fill_with is not None and len(tmp) < linecount:
779 tmp += [fill_with] * (linecount - len(tmp))
787 Sum up the given sequence of numbers.
791 def wrapped(env, context, value):
798 Return the absolute value of a number.
802 def wrapped(env, context, value):
807 def do_round(precision=0, method='common'):
809 Round the number to a given precision. The first
810 parameter specifies the precision (default is ``0``), the
811 second the rounding method:
813 - ``'common'`` rounds either up or down
814 - ``'ceil'`` always rounds up
815 - ``'floor'`` always rounds down
817 If you don't specify a method ``'common'`` is used.
819 .. sourcecode:: jinja
823 {{ 42.55|round(1, 'floor') }}
828 if not method in ('common', 'ceil', 'floor'):
829 raise FilterArgumentError('method must be common, ceil or floor')
831 raise FilterArgumentError('precision must be a postive integer '
833 def wrapped(env, context, value):
834 if method == 'common':
835 return round(value, precision)
837 func = getattr(math, method)
839 return func(value * 10 * precision) / (10 * precision)
845 def do_sort(reverse=False):
847 Sort a sequence. Per default it sorts ascending, if you pass it
848 `True` as first argument it will reverse the sorting.
852 def wrapped(env, context, value):
853 return sorted(value, reverse=reverse)
857 def do_groupby(attribute):
859 Group a sequence of objects by a common attribute.
861 If you for example have a list of dicts or objects that represent persons
862 with `gender`, `first_name` and `last_name` attributes and you want to
863 group all users by genders you can do something like the following
866 .. sourcecode:: html+jinja
869 {% for group in persons|groupby('gender') %}
870 <li>{{ group.grouper }}<ul>
871 {% for person in group.list %}
872 <li>{{ person.first_name }} {{ person.last_name }}</li>
873 {% endfor %}</ul></li>
877 As you can see the item we're grouping by is stored in the `grouper`
878 attribute and the `list` contains all the objects that have this grouper
883 def wrapped(env, context, value):
884 expr = lambda x: env.get_attribute(x, attribute)
888 } for a, b in groupby(sorted(value, key=expr), expr)],
889 key=itemgetter('grouper'))
893 def do_getattribute(attribute):
895 Get one attribute from an object. Normally you don't have to use this
896 filter because the attribute and subscript expressions try to either
897 get an attribute of an object or an item. In some situations it could
898 be that there is an item *and* an attribute with the same name. In that
899 situation only the item is returned, never the attribute.
901 .. sourcecode:: jinja
903 {{ foo.bar }} -> {{ foo|getattribute('bar') }}
907 def wrapped(env, context, value):
909 return get_attribute(value, attribute)
910 except (SecurityException, AttributeError):
911 return env.undefined_singleton
917 This filter basically works like the normal subscript expression but
918 it doesn't fall back to attribute lookup. If an item does not exist for
919 an object undefined is returned.
921 .. sourcecode:: jinja
923 {{ foo.bar }} -> {{ foo|getitem('bar') }}
927 def wrapped(env, context, value):
930 except (TypeError, KeyError, IndexError, AttributeError):
931 return env.undefined_singleton
936 'replace': do_replace,
941 'xmlattr': do_xmlattr,
942 'capitalize': do_capitalize,
944 'default': do_default,
947 'dictsort': do_dictsort,
949 'reverse': do_reverse,
952 'capitalize': do_capitalize,
956 'urlencode': do_urlencode,
957 'jsonencode': do_jsonencode,
958 'filesizeformat': do_filesizeformat,
961 'truncate': do_truncate,
962 'wordwrap': do_wordwrap,
963 'wordcount': do_wordcount,
964 'textile': do_textile,
965 'markdown': do_markdown,
972 'dformat': do_dformat,
973 'capture': do_capture,
975 'striptags': do_striptags,
982 'groupby': do_groupby,
983 'getattribute': do_getattribute,
984 'getitem': do_getitem