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
18 from jinja.utils import escape
21 _striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
26 Decorator for filters that just work on unicode objects.
29 def wrapped(env, context, value):
31 for idx, var in enumerate(nargs):
32 if isinstance(var, str):
33 nargs[idx] = env.to_unicode(var)
34 return f(env.to_unicode(value), *nargs)
37 decorator.__doc__ = f.__doc__
38 decorator.__name__ = f.__name__
46 Decorator for simplifying filters. Filter arguments are passed
47 to the decorated function without environment and context. The
48 source value is the first argument. (like stringfilter but
49 without unicode conversion)
52 def wrapped(env, context, value):
53 return f(value, *args)
56 decorator.__doc__ = f.__doc__
57 decorator.__name__ = f.__name__
63 def do_replace(s, old, new, count=None):
65 Return a copy of the value with all occurrences of a substring
66 replaced with a new one. The first argument is the substring
67 that should be replaced, the second is the replacement string.
68 If the optional third argument ``count`` is given, only the first
69 ``count`` occurrences are replaced:
73 {{ "Hello World"|replace("Hello", "Goodbye") }}
76 {{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
79 if not isinstance(old, basestring) or \
80 not isinstance(new, basestring):
81 raise FilterArgumentError('the replace filter requires '
82 'string replacement arguments')
84 return s.replace(old, new)
85 if not isinstance(count, (int, long)):
86 raise FilterArgumentError('the count parameter of the '
87 'replace filter requires '
89 return s.replace(old, new, count)
90 do_replace = stringfilter(do_replace)
95 Convert a value to uppercase.
100 def do_lower(env, s):
102 Convert a value to lowercase.
107 def do_escape(env, s, attribute=False):
109 XML escape ``&``, ``<``, and ``>`` in a string of data. If the
110 optional parameter is `true` this filter will also convert
111 ``"`` to ``"``. This filter is just used if the environment
112 was configured with disabled `auto_escape`.
114 This method will have no effect it the value is already escaped.
116 # XXX: Does this still exists?
117 #if isinstance(s, TemplateData):
119 if hasattr(s, '__html__'):
121 return escape(unicode(s), attribute)
124 def do_xmlattr(autospace=False):
126 Create an SGML/XML attribute string based on the items in a dict.
127 All values that are neither `none` nor `undefined` are automatically
130 .. sourcecode:: html+jinja
132 <ul{{ {'class': 'my_list', 'missing': None,
133 'id': 'list-%d'|format(variable)}|xmlattr }}>
137 Results in something like this:
141 <ul class="my_list" id="list-42">
145 As you can see it automatically prepends a space in front of the item
146 if the filter returned something. You can disable this by passing
147 `false` as only argument to the filter.
152 def wrapped(env, context, d):
153 if not hasattr(d, 'iteritems'):
154 raise TypeError('a dict is required')
156 for key, value in d.iteritems():
157 if value not in (None, env.undefined_singleton):
158 result.append(u'%s="%s"' % (
159 e(env.to_unicode(key)),
160 e(env.to_unicode(value), True)
162 rv = u' '.join(result)
169 def do_capitalize(s):
171 Capitalize a value. The first character will be uppercase, all others
174 return s.capitalize()
175 do_capitalize = stringfilter(do_capitalize)
180 Return a titlecased version of the value. I.e. words will start with
181 uppercase letters, all remaining characters are lowercase.
184 do_title = stringfilter(do_title)
187 def do_dictsort(case_sensitive=False, by='key'):
189 Sort a dict and yield (key, value) pairs. Because python dicts are
190 unsorted you may want to use this function to order them by either
193 .. sourcecode:: jinja
195 {% for item in mydict|dictsort %}
196 sort the dict by key, case insensitive
198 {% for item in mydict|dicsort(true) %}
199 sort the dict by key, case sensitive
201 {% for item in mydict|dictsort(false, 'value') %}
202 sort the dict by key, case insensitive, sorted
203 normally and ordered by value.
210 raise FilterArgumentError('You can only sort by either '
212 def sort_func(value, env):
213 if isinstance(value, basestring):
214 value = env.to_unicode(value)
215 if not case_sensitive:
216 value = value.lower()
219 def wrapped(env, context, value):
220 items = value.items()
221 items.sort(lambda a, b: cmp(sort_func(a[pos], env),
222 sort_func(b[pos], env)))
227 def do_default(default_value=u'', boolean=False):
229 If the value is undefined it will return the passed default value,
230 otherwise the value of the variable:
232 .. sourcecode:: jinja
234 {{ my_variable|default('my_variable is not defined') }}
236 This will output the value of ``my_variable`` if the variable was
237 defined, otherwise ``'my_variable is not defined'``. If you want
238 to use default with variables that evaluate to false you have to
239 set the second parameter to `true`:
241 .. sourcecode:: jinja
243 {{ ''|default('the string was empty', true) }}
245 def wrapped(env, context, value):
246 if (boolean and not value) or value in (env.undefined_singleton, None):
254 Return a string which is the concatenation of the strings in the
255 sequence. The separator between elements is an empty string per
256 default, you can define ith with the optional parameter:
258 .. sourcecode:: jinja
260 {{ [1, 2, 3]|join('|') }}
266 def wrapped(env, context, value):
267 return env.to_unicode(d).join([env.to_unicode(x) for x in value])
273 Return the length of the value. In case if getting an integer or float
274 it will convert it into a string an return the length of the new
275 string. If the object has no length it will of corse return 0.
277 def wrapped(env, context, value):
279 if type(value) in (int, float, long):
280 return len(str(value))
289 Return a reversed list of the sequence filtered. You can use this
290 for example for reverse iteration:
292 .. sourcecode:: jinja
294 {% for item in seq|reverse %}
298 def wrapped(env, context, value):
308 def do_center(value, width=80):
310 Centers the value in a field of a given width.
312 return value.center(width)
313 do_center = stringfilter(do_center)
318 Return the frist item of a sequence.
320 def wrapped(env, context, seq):
322 return iter(seq).next()
323 except StopIteration:
324 return env.undefined_singleton
330 Return the last item of a sequence.
332 def wrapped(env, context, seq):
334 return iter(reversed(seq)).next()
335 except StopIteration:
336 return env.undefined_singleton
342 Return a random item from the sequence.
344 def wrapped(env, context, seq):
348 return env.undefined_singleton
354 urlencode a string or directory.
356 .. sourcecode:: jinja
358 {{ {'foo': 'bar', 'blub': 'blah'}|urlencode }}
364 def wrapped(env, context, value):
365 if isinstance(value, dict):
367 for key, value in value.iteritems():
368 key = env.to_unicode(key).encode(env.charset)
369 value = env.to_unicode(value).encode(env.charset)
371 return urlencode(tmp)
373 return quote(env.to_unicode(value).encode(env.charset))
379 JSON dump a variable. just works if simplejson is installed.
381 .. sourcecode:: jinja
383 {{ 'Hello World'|jsonencode }}
391 return lambda e, c, v: simplejson.dumps(v)
394 def do_filesizeformat():
396 Format the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, 102
399 def wrapped(env, context, value):
407 return "%d Byte%s" % (bytes, bytes != 1 and 's' or '')
408 elif bytes < 1024 * 1024:
409 return "%.1f KB" % (bytes / 1024)
410 elif bytes < 1024 * 1024 * 1024:
411 return "%.1f MB" % (bytes / (1024 * 1024))
412 return "%.1f GB" % (bytes / (1024 * 1024 * 1024))
416 def do_pprint(verbose=False):
418 Pretty print a variable. Useful for debugging.
420 With Jinja 1.2 onwards you can pass it a parameter. If this parameter
421 is truthy the output will be more verbose (this requires `pretty`)
423 def wrapped(env, context, value):
424 return pformat(value, verbose=verbose)
428 def do_urlize(value, trim_url_limit=None, nofollow=False):
430 Converts URLs in plain text into clickable links.
432 If you pass the filter an additional integer it will shorten the urls
433 to that number. Also a third argument exists that makes the urls
436 .. sourcecode:: jinja
438 {{ mytext|urlize(40, True) }}
439 links are shortened to 40 chars and defined with rel="nofollow"
441 return urlize(value, trim_url_limit, nofollow)
442 do_urlize = stringfilter(do_urlize)
445 def do_indent(s, width=4, indentfirst=False):
447 {{ s|indent[ width[ indentfirst[ usetab]]] }}
449 Return a copy of the passed string, each line indented by
450 4 spaces. The first line is not indented. If you want to
451 change the number of spaces or indent the first line too
452 you can pass additional parameters to the filter:
454 .. sourcecode:: jinja
456 {{ mytext|indent(2, True) }}
457 indent by two spaces and indent the first line too.
459 indention = ' ' * width
461 return u'\n'.join([indention + line for line in s.splitlines()])
462 return s.replace('\n', '\n' + indention)
463 do_indent = stringfilter(do_indent)
466 def do_truncate(s, length=255, killwords=False, end='...'):
468 Return a truncated copy of the string. The length is specified
469 with the first parameter which defaults to ``255``. If the second
470 parameter is ``true`` the filter will cut the text at length. Otherwise
471 it will try to save the last word. If the text was in fact
472 truncated it will append an ellipsis sign (``"..."``). If you want a
473 different ellipsis sign than ``"..."`` you can specify it using the
476 .. sourcecode jinja::
478 {{ mytext|truncate(300, false, '»') }}
479 truncate mytext to 300 chars, don't split up words, use a
480 right pointing double arrow as ellipsis sign.
485 return s[:length] + end
495 return u' '.join(result)
496 do_truncate = stringfilter(do_truncate)
499 def do_wordwrap(s, pos=79, hard=False):
501 Return a copy of the string passed to the filter wrapped after
502 ``79`` characters. You can override this default using the first
503 parameter. If you set the second parameter to `true` Jinja will
504 also split words apart (usually a bad idea because it makes
510 return u'\n'.join([s[idx:idx + pos] for idx in
511 xrange(0, len(s), pos)])
512 # code from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/148061
513 return reduce(lambda line, word, pos=pos: u'%s%s%s' %
514 (line, u' \n'[(len(line)-line.rfind('\n') - 1 +
515 len(word.split('\n', 1)[0]) >= pos)],
517 do_wordwrap = stringfilter(do_wordwrap)
522 Count the words in that string.
524 return len([x for x in s.split() if x])
525 do_wordcount = stringfilter(do_wordcount)
530 Prase the string using textile.
532 requires the `PyTextile`_ library.
534 .. _PyTextile: http://dealmeida.net/projects/textile/
536 from textile import textile
537 return textile(s.encode('utf-8')).decode('utf-8')
538 do_textile = stringfilter(do_textile)
543 Parse the string using markdown.
545 requires the `Python-markdown`_ library.
547 .. _Python-markdown: http://www.freewisdom.org/projects/python-markdown/
549 from markdown import markdown
550 return markdown(s.encode('utf-8')).decode('utf-8')
551 do_markdown = stringfilter(do_markdown)
556 Parse the string using the reStructuredText parser from the
559 requires `docutils`_.
561 .. _docutils: http://docutils.sourceforge.net/
563 from docutils.core import publish_parts
564 parts = publish_parts(source=s, writer_name='html4css1')
565 return parts['fragment']
566 do_rst = stringfilter(do_rst)
569 def do_int(default=0):
571 Convert the value into an integer. If the
572 conversion doesn't work it will return ``0``. You can
573 override this default using the first parameter.
575 def wrapped(env, context, value):
578 except (TypeError, ValueError):
580 return int(float(value))
581 except (TypeError, ValueError):
586 def do_float(default=0.0):
588 Convert the value into a floating point number. If the
589 conversion doesn't work it will return ``0.0``. You can
590 override this default using the first parameter.
592 def wrapped(env, context, value):
595 except (TypeError, ValueError):
602 Convert the value into an string.
604 return lambda e, c, v: e.to_unicode(v)
607 def do_format(*args):
609 Apply python string formatting on an object:
611 .. sourcecode:: jinja
613 {{ "%s - %s"|format("Hello?", "Foo!") }}
616 Note that you cannot use the mapping syntax (``%(name)s``)
617 like in python. Use `|dformat` for that.
619 def wrapped(env, context, value):
620 return env.to_unicode(value) % args
626 Apply python mapping string formatting on an object:
628 .. sourcecode:: jinja
630 {{ "Hello %(username)s!"|dformat({'username': 'John Doe'}) }}
633 This is useful when adding variables to translateable
638 if not isinstance(d, dict):
639 raise FilterArgumentError('dict required')
640 def wrapped(env, context, value):
641 return env.to_unicode(value) % d
647 Strip leading and trailing whitespace.
650 do_trim = stringfilter(do_trim)
653 def do_capture(name='captured', clean=False):
655 Store the value in a variable called ``captured`` or a variable
656 with the name provided. Useful for filter blocks:
658 .. sourcecode:: jinja
660 {% filter capture('foo') %}
665 This will output "..." two times. One time from the filter block
666 and one time from the variable. If you don't want the filter to
667 output something you can use it in `clean` mode:
669 .. sourcecode:: jinja
671 {% filter capture('foo', True) %}
676 if not isinstance(name, basestring):
677 raise FilterArgumentError('You can only capture into variables')
678 def wrapped(env, context, value):
679 context[name] = value
681 return TemplateData()
686 def do_striptags(value):
688 Strip SGML/XML tags and replace adjacent whitespace by one space.
692 return ' '.join(_striptags_re.sub('', value).split())
693 do_striptags = stringfilter(do_striptags)
696 def do_slice(slices, fill_with=None):
698 Slice an iterator and return a list of lists containing
699 those items. Useful if you want to create a div containing
700 three div tags that represent columns:
702 .. sourcecode:: html+jinja
704 <div class="columwrapper">
705 {%- for column in items|slice(3) %}
706 <ul class="column-{{ loop.index }}">
707 {%- for item in column %}
714 If you pass it a second argument it's used to fill missing
715 values on the last iteration.
719 def wrapped(env, context, value):
723 items_per_slice = length // slices
724 slices_with_extra = length % slices
726 for slice_number in xrange(slices):
727 start = offset + slice_number * items_per_slice
728 if slice_number < slices_with_extra:
730 end = offset + (slice_number + 1) * items_per_slice
732 if fill_with is not None and slice_number >= slices_with_extra:
733 tmp.append(fill_with)
739 def do_batch(linecount, fill_with=None):
741 A filter that batches items. It works pretty much like `slice`
742 just the other way round. It returns a list of lists with the
743 given number of items. If you provide a second parameter this
744 is used to fill missing items. See this example:
746 .. sourcecode:: html+jinja
749 {%- for row in items|batch(3, ' ') %}
751 {%- for column in row %}
752 <tr>{{ column }}</td>
760 def wrapped(env, context, value):
764 if len(tmp) == linecount:
769 if fill_with is not None and len(tmp) < linecount:
770 tmp += [fill_with] * (linecount - len(tmp))
778 Sum up the given sequence of numbers.
782 def wrapped(env, context, value):
789 Return the absolute value of a number.
793 def wrapped(env, context, value):
798 def do_round(precision=0, method='common'):
800 Round the number to a given precision. The first
801 parameter specifies the precision (default is ``0``), the
802 second the rounding method:
804 - ``'common'`` rounds either up or down
805 - ``'ceil'`` always rounds up
806 - ``'floor'`` always rounds down
808 If you don't specify a method ``'common'`` is used.
810 .. sourcecode:: jinja
814 {{ 42.55|round(1, 'floor') }}
819 if not method in ('common', 'ceil', 'floor'):
820 raise FilterArgumentError('method must be common, ceil or floor')
822 raise FilterArgumentError('precision must be a postive integer '
824 def wrapped(env, context, value):
825 if method == 'common':
826 return round(value, precision)
828 func = getattr(math, method)
830 return func(value * 10 * precision) / (10 * precision)
836 def do_sort(reverse=False):
838 Sort a sequence. Per default it sorts ascending, if you pass it
839 `True` as first argument it will reverse the sorting.
843 def wrapped(env, context, value):
844 return sorted(value, reverse=reverse)
848 def do_groupby(attribute):
850 Group a sequence of objects by a common attribute.
852 If you for example have a list of dicts or objects that represent persons
853 with `gender`, `first_name` and `last_name` attributes and you want to
854 group all users by genders you can do something like the following
857 .. sourcecode:: html+jinja
860 {% for group in persons|groupby('gender') %}
861 <li>{{ group.grouper }}<ul>
862 {% for person in group.list %}
863 <li>{{ person.first_name }} {{ person.last_name }}</li>
864 {% endfor %}</ul></li>
868 As you can see the item we're grouping by is stored in the `grouper`
869 attribute and the `list` contains all the objects that have this grouper
874 def wrapped(env, context, value):
875 expr = lambda x: env.get_attribute(x, attribute)
879 } for a, b in groupby(sorted(value, key=expr), expr)],
880 key=itemgetter('grouper'))
884 def do_getattribute(attribute):
886 Get one attribute from an object. Normally you don't have to use this
887 filter because the attribute and subscript expressions try to either
888 get an attribute of an object or an item. In some situations it could
889 be that there is an item *and* an attribute with the same name. In that
890 situation only the item is returned, never the attribute.
892 .. sourcecode:: jinja
894 {{ foo.bar }} -> {{ foo|getattribute('bar') }}
898 def wrapped(env, context, value):
900 return get_attribute(value, attribute)
901 except (SecurityException, AttributeError):
902 return env.undefined_singleton
908 This filter basically works like the normal subscript expression but
909 it doesn't fall back to attribute lookup. If an item does not exist for
910 an object undefined is returned.
912 .. sourcecode:: jinja
914 {{ foo.bar }} -> {{ foo|getitem('bar') }}
918 def wrapped(env, context, value):
921 except (TypeError, KeyError, IndexError, AttributeError):
922 return env.undefined_singleton
927 'replace': do_replace,
932 'xmlattr': do_xmlattr,
933 'capitalize': do_capitalize,
935 'default': do_default,
938 'dictsort': do_dictsort,
940 'reverse': do_reverse,
943 'capitalize': do_capitalize,
947 'urlencode': do_urlencode,
948 'jsonencode': do_jsonencode,
949 'filesizeformat': do_filesizeformat,
952 'truncate': do_truncate,
953 'wordwrap': do_wordwrap,
954 'wordcount': do_wordcount,
955 'textile': do_textile,
956 'markdown': do_markdown,
963 'dformat': do_dformat,
964 'capture': do_capture,
966 'striptags': do_striptags,
973 'groupby': do_groupby,
974 'getattribute': do_getattribute,
975 'getitem': do_getitem