1 # -*- coding: utf-8 -*-
8 :copyright: 2008 by Armin Ronacher, Christoph Hack.
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 marking context dependent filters. The current context
27 argument will be passed as first argument.
29 f.contextfilter = True
33 def do_replace(s, old, new, count=None):
35 Return a copy of the value with all occurrences of a substring
36 replaced with a new one. The first argument is the substring
37 that should be replaced, the second is the replacement string.
38 If the optional third argument ``count`` is given, only the first
39 ``count`` occurrences are replaced:
43 {{ "Hello World"|replace("Hello", "Goodbye") }}
46 {{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
49 if not isinstance(old, basestring) or \
50 not isinstance(new, basestring):
51 raise FilterArgumentError('the replace filter requires '
52 'string replacement arguments')
54 return s.replace(old, new)
55 if not isinstance(count, (int, long)):
56 raise FilterArgumentError('the count parameter of the '
57 'replace filter requires '
59 return s.replace(old, new, count)
64 Convert a value to uppercase.
71 Convert a value to lowercase.
76 def do_escape(s, attribute=False):
78 XML escape ``&``, ``<``, and ``>`` in a string of data. If the
79 optional parameter is `true` this filter will also convert
80 ``"`` to ``"``. This filter is just used if the environment
81 was configured with disabled `auto_escape`.
83 This method will have no effect it the value is already escaped.
85 # XXX: Does this still exists?
86 #if isinstance(s, TemplateData):
88 if hasattr(s, '__html__'):
90 return escape(unicode(s), attribute)
93 def do_xmlattr(d, autospace=False):
95 Create an SGML/XML attribute string based on the items in a dict.
96 All values that are neither `none` nor `undefined` are automatically
99 .. sourcecode:: html+jinja
101 <ul{{ {'class': 'my_list', 'missing': None,
102 'id': 'list-%d'|format(variable)}|xmlattr }}>
106 Results in something like this:
110 <ul class="my_list" id="list-42">
114 As you can see it automatically prepends a space in front of the item
115 if the filter returned something. You can disable this by passing
116 `false` as only argument to the filter.
120 if not hasattr(d, 'iteritems'):
121 raise TypeError('a dict is required')
123 for key, value in d.iteritems():
124 if value not in (None, env.undefined_singleton):
125 result.append(u'%s="%s"' % (
126 escape(env.to_unicode(key)),
127 escape(env.to_unicode(value), True)
129 rv = u' '.join(result)
135 def do_capitalize(s):
137 Capitalize a value. The first character will be uppercase, all others
140 return unicode(s).capitalize()
145 Return a titlecased version of the value. I.e. words will start with
146 uppercase letters, all remaining characters are lowercase.
148 return unicode(s).title()
151 def do_dictsort(case_sensitive=False, by='key'):
153 Sort a dict and yield (key, value) pairs. Because python dicts are
154 unsorted you may want to use this function to order them by either
157 .. sourcecode:: jinja
159 {% for item in mydict|dictsort %}
160 sort the dict by key, case insensitive
162 {% for item in mydict|dicsort(true) %}
163 sort the dict by key, case sensitive
165 {% for item in mydict|dictsort(false, 'value') %}
166 sort the dict by key, case insensitive, sorted
167 normally and ordered by value.
174 raise FilterArgumentError('You can only sort by either '
176 def sort_func(value, env):
177 if isinstance(value, basestring):
178 value = env.to_unicode(value)
179 if not case_sensitive:
180 value = value.lower()
183 def wrapped(env, context, value):
184 items = value.items()
185 items.sort(lambda a, b: cmp(sort_func(a[pos], env),
186 sort_func(b[pos], env)))
191 def do_default(value, default_value=u'', boolean=False):
193 If the value is undefined it will return the passed default value,
194 otherwise the value of the variable:
196 .. sourcecode:: jinja
198 {{ my_variable|default('my_variable is not defined') }}
200 This will output the value of ``my_variable`` if the variable was
201 defined, otherwise ``'my_variable is not defined'``. If you want
202 to use default with variables that evaluate to false you have to
203 set the second parameter to `true`:
205 .. sourcecode:: jinja
207 {{ ''|default('the string was empty', true) }}
209 # XXX: undefined_sigleton
210 if (boolean and not value) or value in (env.undefined_singleton, None):
215 def do_join(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 ith with the optional parameter:
221 .. sourcecode:: jinja
223 {{ [1, 2, 3]|join('|') }}
229 return unicode(d).join([unicode(x) for x in value])
234 Return the length of the value. In case if getting an integer or float
235 it will convert it into a string an return the length of the new
236 string. If the object has no length it will of corse return 0.
239 if type(value) in (int, float, long):
240 return len(str(value))
248 Return a reversed list of the sequence filtered. You can use this
249 for example for reverse iteration:
251 .. sourcecode:: jinja
253 {% for item in seq|reverse %}
265 def do_center(value, width=80):
267 Centers the value in a field of a given width.
269 return unicode(value).center(width)
274 Return the frist item of a sequence.
277 return iter(seq).next()
278 except StopIteration:
279 return env.undefined_singleton
284 Return the last item of a sequence.
287 return iter(reversed(seq)).next()
288 except StopIteration:
289 return env.undefined_singleton
294 Return a random item from the sequence.
299 return env.undefined_singleton
302 def do_urlencode(value):
304 urlencode a string or directory.
306 .. sourcecode:: jinja
308 {{ {'foo': 'bar', 'blub': 'blah'}|urlencode }}
314 if isinstance(value, dict):
316 for key, value in value.iteritems():
318 key = unicode(key).encode(env.charset)
319 value = unicode(value).encode(env.charset)
321 return urlencode(tmp)
324 return quote(unicode(value).encode(env.charset))
327 def do_jsonencode(value):
329 JSON dump a variable. just works if simplejson is installed.
331 .. sourcecode:: jinja
333 {{ 'Hello World'|jsonencode }}
341 return simplejson.dumps(value)
344 def do_filesizeformat():
346 Format the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, 102
349 def wrapped(env, context, value):
357 return "%d Byte%s" % (bytes, bytes != 1 and 's' or '')
358 elif bytes < 1024 * 1024:
359 return "%.1f KB" % (bytes / 1024)
360 elif bytes < 1024 * 1024 * 1024:
361 return "%.1f MB" % (bytes / (1024 * 1024))
362 return "%.1f GB" % (bytes / (1024 * 1024 * 1024))
366 def do_pprint(value, verbose=False):
368 Pretty print a variable. Useful for debugging.
370 With Jinja 1.2 onwards you can pass it a parameter. If this parameter
371 is truthy the output will be more verbose (this requires `pretty`)
373 return pformat(value, verbose=verbose)
376 def do_urlize(value, trim_url_limit=None, nofollow=False):
378 Converts URLs in plain text into clickable links.
380 If you pass the filter an additional integer it will shorten the urls
381 to that number. Also a third argument exists that makes the urls
384 .. sourcecode:: jinja
386 {{ mytext|urlize(40, True) }}
387 links are shortened to 40 chars and defined with rel="nofollow"
389 return urlize(unicode(value), trim_url_limit, nofollow)
392 def do_indent(s, width=4, indentfirst=False):
394 {{ s|indent[ width[ indentfirst[ usetab]]] }}
396 Return a copy of the passed string, each line indented by
397 4 spaces. The first line is not indented. If you want to
398 change the number of spaces or indent the first line too
399 you can pass additional parameters to the filter:
401 .. sourcecode:: jinja
403 {{ mytext|indent(2, True) }}
404 indent by two spaces and indent the first line too.
406 indention = ' ' * width
408 return u'\n'.join([indention + line for line in s.splitlines()])
409 return s.replace('\n', '\n' + indention)
412 def do_truncate(s, length=255, killwords=False, end='...'):
414 Return a truncated copy of the string. The length is specified
415 with the first parameter which defaults to ``255``. If the second
416 parameter is ``true`` the filter will cut the text at length. Otherwise
417 it will try to save the last word. If the text was in fact
418 truncated it will append an ellipsis sign (``"..."``). If you want a
419 different ellipsis sign than ``"..."`` you can specify it using the
422 .. sourcecode jinja::
424 {{ mytext|truncate(300, false, '»') }}
425 truncate mytext to 300 chars, don't split up words, use a
426 right pointing double arrow as ellipsis sign.
431 return s[:length] + end
441 return u' '.join(result)
444 def do_wordwrap(s, pos=79, hard=False):
446 Return a copy of the string passed to the filter wrapped after
447 ``79`` characters. You can override this default using the first
448 parameter. If you set the second parameter to `true` Jinja will
449 also split words apart (usually a bad idea because it makes
455 return u'\n'.join([s[idx:idx + pos] for idx in
456 xrange(0, len(s), pos)])
457 # code from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/148061
458 return reduce(lambda line, word, pos=pos: u'%s%s%s' %
459 (line, u' \n'[(len(line)-line.rfind('\n') - 1 +
460 len(word.split('\n', 1)[0]) >= pos)],
466 Count the words in that string.
468 return len([x for x in s.split() if x])
473 Prase the string using textile.
475 requires the `PyTextile`_ library.
477 .. _PyTextile: http://dealmeida.net/projects/textile/
479 from textile import textile
480 return textile(s.encode('utf-8')).decode('utf-8')
485 Parse the string using markdown.
487 requires the `Python-markdown`_ library.
489 .. _Python-markdown: http://www.freewisdom.org/projects/python-markdown/
491 from markdown import markdown
492 return markdown(s.encode('utf-8')).decode('utf-8')
497 Parse the string using the reStructuredText parser from the
500 requires `docutils`_.
502 .. _docutils: http://docutils.sourceforge.net/
504 from docutils.core import publish_parts
505 parts = publish_parts(source=s, writer_name='html4css1')
506 return parts['fragment']
508 def do_int(default=0):
510 Convert the value into an integer. If the
511 conversion doesn't work it will return ``0``. You can
512 override this default using the first parameter.
514 def wrapped(env, context, value):
517 except (TypeError, ValueError):
519 return int(float(value))
520 except (TypeError, ValueError):
525 def do_float(default=0.0):
527 Convert the value into a floating point number. If the
528 conversion doesn't work it will return ``0.0``. You can
529 override this default using the first parameter.
531 def wrapped(env, context, value):
534 except (TypeError, ValueError):
541 Convert the value into an string.
543 return lambda e, c, v: e.to_unicode(v)
546 def do_format(*args):
548 Apply python string formatting on an object:
550 .. sourcecode:: jinja
552 {{ "%s - %s"|format("Hello?", "Foo!") }}
555 Note that you cannot use the mapping syntax (``%(name)s``)
556 like in python. Use `|dformat` for that.
558 def wrapped(env, context, value):
559 return env.to_unicode(value) % args
565 Apply python mapping string formatting on an object:
567 .. sourcecode:: jinja
569 {{ "Hello %(username)s!"|dformat({'username': 'John Doe'}) }}
572 This is useful when adding variables to translateable
577 if not isinstance(d, dict):
578 raise FilterArgumentError('dict required')
579 def wrapped(env, context, value):
580 return env.to_unicode(value) % d
586 Strip leading and trailing whitespace.
591 def do_capture(name='captured', clean=False):
593 Store the value in a variable called ``captured`` or a variable
594 with the name provided. Useful for filter blocks:
596 .. sourcecode:: jinja
598 {% filter capture('foo') %}
603 This will output "..." two times. One time from the filter block
604 and one time from the variable. If you don't want the filter to
605 output something you can use it in `clean` mode:
607 .. sourcecode:: jinja
609 {% filter capture('foo', True) %}
614 if not isinstance(name, basestring):
615 raise FilterArgumentError('You can only capture into variables')
616 def wrapped(env, context, value):
617 context[name] = value
619 return TemplateData()
624 def do_striptags(value):
626 Strip SGML/XML tags and replace adjacent whitespace by one space.
630 return ' '.join(_striptags_re.sub('', value).split())
633 def do_slice(slices, fill_with=None):
635 Slice an iterator and return a list of lists containing
636 those items. Useful if you want to create a div containing
637 three div tags that represent columns:
639 .. sourcecode:: html+jinja
641 <div class="columwrapper">
642 {%- for column in items|slice(3) %}
643 <ul class="column-{{ loop.index }}">
644 {%- for item in column %}
651 If you pass it a second argument it's used to fill missing
652 values on the last iteration.
656 def wrapped(env, context, value):
660 items_per_slice = length // slices
661 slices_with_extra = length % slices
663 for slice_number in xrange(slices):
664 start = offset + slice_number * items_per_slice
665 if slice_number < slices_with_extra:
667 end = offset + (slice_number + 1) * items_per_slice
669 if fill_with is not None and slice_number >= slices_with_extra:
670 tmp.append(fill_with)
676 def do_batch(linecount, fill_with=None):
678 A filter that batches items. It works pretty much like `slice`
679 just the other way round. It returns a list of lists with the
680 given number of items. If you provide a second parameter this
681 is used to fill missing items. See this example:
683 .. sourcecode:: html+jinja
686 {%- for row in items|batch(3, ' ') %}
688 {%- for column in row %}
689 <tr>{{ column }}</td>
697 def wrapped(env, context, value):
701 if len(tmp) == linecount:
706 if fill_with is not None and len(tmp) < linecount:
707 tmp += [fill_with] * (linecount - len(tmp))
715 Sum up the given sequence of numbers.
719 def wrapped(env, context, value):
726 Return the absolute value of a number.
730 def wrapped(env, context, value):
735 def do_round(precision=0, method='common'):
737 Round the number to a given precision. The first
738 parameter specifies the precision (default is ``0``), the
739 second the rounding method:
741 - ``'common'`` rounds either up or down
742 - ``'ceil'`` always rounds up
743 - ``'floor'`` always rounds down
745 If you don't specify a method ``'common'`` is used.
747 .. sourcecode:: jinja
751 {{ 42.55|round(1, 'floor') }}
756 if not method in ('common', 'ceil', 'floor'):
757 raise FilterArgumentError('method must be common, ceil or floor')
759 raise FilterArgumentError('precision must be a postive integer '
761 def wrapped(env, context, value):
762 if method == 'common':
763 return round(value, precision)
765 func = getattr(math, method)
767 return func(value * 10 * precision) / (10 * precision)
773 def do_sort(reverse=False):
775 Sort a sequence. Per default it sorts ascending, if you pass it
776 `True` as first argument it will reverse the sorting.
780 def wrapped(env, context, value):
781 return sorted(value, reverse=reverse)
785 def do_groupby(attribute):
787 Group a sequence of objects by a common attribute.
789 If you for example have a list of dicts or objects that represent persons
790 with `gender`, `first_name` and `last_name` attributes and you want to
791 group all users by genders you can do something like the following
794 .. sourcecode:: html+jinja
797 {% for group in persons|groupby('gender') %}
798 <li>{{ group.grouper }}<ul>
799 {% for person in group.list %}
800 <li>{{ person.first_name }} {{ person.last_name }}</li>
801 {% endfor %}</ul></li>
805 As you can see the item we're grouping by is stored in the `grouper`
806 attribute and the `list` contains all the objects that have this grouper
811 def wrapped(env, context, value):
812 expr = lambda x: env.get_attribute(x, attribute)
816 } for a, b in groupby(sorted(value, key=expr), expr)],
817 key=itemgetter('grouper'))
821 def do_getattribute(attribute):
823 Get one attribute from an object. Normally you don't have to use this
824 filter because the attribute and subscript expressions try to either
825 get an attribute of an object or an item. In some situations it could
826 be that there is an item *and* an attribute with the same name. In that
827 situation only the item is returned, never the attribute.
829 .. sourcecode:: jinja
831 {{ foo.bar }} -> {{ foo|getattribute('bar') }}
835 def wrapped(env, context, value):
837 return get_attribute(value, attribute)
838 except (SecurityException, AttributeError):
839 return env.undefined_singleton
845 This filter basically works like the normal subscript expression but
846 it doesn't fall back to attribute lookup. If an item does not exist for
847 an object undefined is returned.
849 .. sourcecode:: jinja
851 {{ foo.bar }} -> {{ foo|getitem('bar') }}
855 def wrapped(env, context, value):
858 except (TypeError, KeyError, IndexError, AttributeError):
859 return env.undefined_singleton
864 'replace': do_replace,
869 'xmlattr': do_xmlattr,
870 'capitalize': do_capitalize,
872 'default': do_default,
875 'dictsort': do_dictsort,
877 'reverse': do_reverse,
880 'capitalize': do_capitalize,
884 'urlencode': do_urlencode,
885 'jsonencode': do_jsonencode,
886 'filesizeformat': do_filesizeformat,
889 'truncate': do_truncate,
890 'wordwrap': do_wordwrap,
891 'wordcount': do_wordcount,
892 'textile': do_textile,
893 'markdown': do_markdown,
900 'dformat': do_dformat,
901 'capture': do_capture,
903 'striptags': do_striptags,
910 'groupby': do_groupby,
911 'getattribute': do_getattribute,
912 'getitem': do_getitem