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 jinja2.utils import Markup, escape, pformat, urlize
19 from jinja2.runtime import Undefined
23 _striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
27 """Decorator for marking context dependent filters. The current context
28 argument will be passed as first argument.
30 f.contextfilter = True
34 def do_replace(s, old, new, count=None):
36 Return a copy of the value with all occurrences of a substring
37 replaced with a new one. The first argument is the substring
38 that should be replaced, the second is the replacement string.
39 If the optional third argument ``count`` is given, only the first
40 ``count`` occurrences are replaced:
44 {{ "Hello World"|replace("Hello", "Goodbye") }}
47 {{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
50 if not isinstance(old, basestring) or \
51 not isinstance(new, basestring):
52 raise FilterArgumentError('the replace filter requires '
53 'string replacement arguments')
55 return s.replace(old, new)
56 if not isinstance(count, (int, long)):
57 raise FilterArgumentError('the count parameter of the '
58 'replace filter requires '
60 return s.replace(old, new, count)
64 """Convert a value to uppercase."""
65 return unicode(s).upper()
69 """Convert a value to lowercase."""
70 return unicode(s).lower()
73 def do_escape(s, attribute=False):
75 XML escape ``&``, ``<``, and ``>`` in a string of data. If the
76 optional parameter is `true` this filter will also convert
77 ``"`` to ``"``. This filter is just used if the environment
78 was configured with disabled `auto_escape`.
80 This method will have no effect it the value is already escaped.
82 return escape(unicode(s), attribute)
85 def do_xmlattr(d, autospace=False):
87 Create an SGML/XML attribute string based on the items in a dict.
88 All values that are neither `none` nor `undefined` are automatically
91 .. sourcecode:: html+jinja
93 <ul{{ {'class': 'my_list', 'missing': None,
94 'id': 'list-%d'|format(variable)}|xmlattr }}>
98 Results in something like this:
102 <ul class="my_list" id="list-42">
106 As you can see it automatically prepends a space in front of the item
107 if the filter returned something. You can disable this by passing
108 `false` as only argument to the filter.
112 if not hasattr(d, 'iteritems'):
113 raise TypeError('a dict is required')
115 for key, value in d.iteritems():
116 if value is not None and not isinstance(value, Undefined):
117 result.append(u'%s="%s"' % (
118 escape(env.to_unicode(key)),
119 escape(env.to_unicode(value), True)
121 rv = u' '.join(result)
127 def do_capitalize(s):
129 Capitalize a value. The first character will be uppercase, all others
132 return unicode(s).capitalize()
137 Return a titlecased version of the value. I.e. words will start with
138 uppercase letters, all remaining characters are lowercase.
140 return unicode(s).title()
143 def do_dictsort(value, case_sensitive=False, by='key'):
145 Sort a dict and yield (key, value) pairs. Because python dicts are
146 unsorted you may want to use this function to order them by either
149 .. sourcecode:: jinja
151 {% for item in mydict|dictsort %}
152 sort the dict by key, case insensitive
154 {% for item in mydict|dicsort(true) %}
155 sort the dict by key, case sensitive
157 {% for item in mydict|dictsort(false, 'value') %}
158 sort the dict by key, case insensitive, sorted
159 normally and ordered by value.
166 raise FilterArgumentError('You can only sort by either '
168 def sort_func(value):
169 if isinstance(value, basestring):
170 value = unicode(value)
171 if not case_sensitive:
172 value = value.lower()
175 items = value.items()
176 items.sort(lambda a, b: cmp(sort_func(a[pos]), sort_func(b[pos])))
180 def do_default(value, default_value=u'', boolean=False):
182 If the value is undefined it will return the passed default value,
183 otherwise the value of the variable:
185 .. sourcecode:: jinja
187 {{ my_variable|default('my_variable is not defined') }}
189 This will output the value of ``my_variable`` if the variable was
190 defined, otherwise ``'my_variable is not defined'``. If you want
191 to use default with variables that evaluate to false you have to
192 set the second parameter to `true`:
194 .. sourcecode:: jinja
196 {{ ''|default('the string was empty', true) }}
198 if (boolean and not value) or isinstance(value, Undefined):
203 def do_join(value, d=u''):
205 Return a string which is the concatenation of the strings in the
206 sequence. The separator between elements is an empty string per
207 default, you can define ith with the optional parameter:
209 .. sourcecode:: jinja
211 {{ [1, 2, 3]|join('|') }}
217 return unicode(d).join(unicode(x) for x in value)
220 def do_center(value, width=80):
222 Centers the value in a field of a given width.
224 return unicode(value).center(width)
228 def do_first(context, seq):
230 Return the frist item of a sequence.
233 return iter(seq).next()
234 except StopIteration:
235 return context.environment.undefined('seq|first',
236 extra='the sequence was empty')
240 def do_last(context, seq):
242 Return the last item of a sequence.
245 return iter(reversed(seq)).next()
246 except StopIteration:
247 return context.environment.undefined('seq|last',
248 extra='the sequence was empty')
252 def do_random(context, seq):
254 Return a random item from the sequence.
259 return context.environment.undefined('seq|random',
260 extra='the sequence was empty')
263 def do_jsonencode(value):
265 JSON dump a variable. just works if simplejson is installed.
267 .. sourcecode:: jinja
269 {{ 'Hello World'|jsonencode }}
277 return simplejson.dumps(value)
280 def do_filesizeformat(value):
282 Format the value like a 'human-readable' file size (i.e. 13 KB,
283 4.1 MB, 102 bytes, etc).
292 return "%d Byte%s" % (bytes, bytes != 1 and 's' or '')
293 elif bytes < 1024 * 1024:
294 return "%.1f KB" % (bytes / 1024)
295 elif bytes < 1024 * 1024 * 1024:
296 return "%.1f MB" % (bytes / (1024 * 1024))
297 return "%.1f GB" % (bytes / (1024 * 1024 * 1024))
300 def do_pprint(value, verbose=False):
302 Pretty print a variable. Useful for debugging.
304 With Jinja 1.2 onwards you can pass it a parameter. If this parameter
305 is truthy the output will be more verbose (this requires `pretty`)
307 return pformat(value, verbose=verbose)
310 def do_urlize(value, trim_url_limit=None, nofollow=False):
312 Converts URLs in plain text into clickable links.
314 If you pass the filter an additional integer it will shorten the urls
315 to that number. Also a third argument exists that makes the urls
318 .. sourcecode:: jinja
320 {{ mytext|urlize(40, True) }}
321 links are shortened to 40 chars and defined with rel="nofollow"
323 return urlize(unicode(value), trim_url_limit, nofollow)
326 def do_indent(s, width=4, indentfirst=False):
328 {{ s|indent[ width[ indentfirst[ usetab]]] }}
330 Return a copy of the passed string, each line indented by
331 4 spaces. The first line is not indented. If you want to
332 change the number of spaces or indent the first line too
333 you can pass additional parameters to the filter:
335 .. sourcecode:: jinja
337 {{ mytext|indent(2, True) }}
338 indent by two spaces and indent the first line too.
340 indention = ' ' * width
342 return u'\n'.join([indention + line for line in s.splitlines()])
343 return s.replace('\n', '\n' + indention)
346 def do_truncate(s, length=255, killwords=False, end='...'):
348 Return a truncated copy of the string. The length is specified
349 with the first parameter which defaults to ``255``. If the second
350 parameter is ``true`` the filter will cut the text at length. Otherwise
351 it will try to save the last word. If the text was in fact
352 truncated it will append an ellipsis sign (``"..."``). If you want a
353 different ellipsis sign than ``"..."`` you can specify it using the
356 .. sourcecode jinja::
358 {{ mytext|truncate(300, false, '»') }}
359 truncate mytext to 300 chars, don't split up words, use a
360 right pointing double arrow as ellipsis sign.
365 return s[:length] + end
375 return u' '.join(result)
378 def do_wordwrap(s, pos=79, hard=False):
380 Return a copy of the string passed to the filter wrapped after
381 ``79`` characters. You can override this default using the first
382 parameter. If you set the second parameter to `true` Jinja will
383 also split words apart (usually a bad idea because it makes
389 return u'\n'.join([s[idx:idx + pos] for idx in
390 xrange(0, len(s), pos)])
391 # code from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/148061
392 return reduce(lambda line, word, pos=pos: u'%s%s%s' %
393 (line, u' \n'[(len(line)-line.rfind('\n') - 1 +
394 len(word.split('\n', 1)[0]) >= pos)],
400 Count the words in that string.
402 return len([x for x in s.split() if x])
407 Prase the string using textile.
409 requires the `PyTextile`_ library.
411 .. _PyTextile: http://dealmeida.net/projects/textile/
413 from textile import textile
414 return textile(s.encode('utf-8')).decode('utf-8')
419 Parse the string using markdown.
421 requires the `Python-markdown`_ library.
423 .. _Python-markdown: http://www.freewisdom.org/projects/python-markdown/
425 from markdown import markdown
426 return markdown(s.encode('utf-8')).decode('utf-8')
431 Parse the string using the reStructuredText parser from the
434 requires `docutils`_.
436 .. _docutils: http://docutils.sourceforge.net/
438 from docutils.core import publish_parts
439 parts = publish_parts(source=s, writer_name='html4css1')
440 return parts['fragment']
443 def do_int(value, default=0):
445 Convert the value into an integer. If the
446 conversion doesn't work it will return ``0``. You can
447 override this default using the first parameter.
451 except (TypeError, ValueError):
453 return int(float(value))
454 except (TypeError, ValueError):
458 def do_float(value, default=0.0):
460 Convert the value into a floating point number. If the
461 conversion doesn't work it will return ``0.0``. You can
462 override this default using the first parameter.
466 except (TypeError, ValueError):
470 def do_string(value):
472 Convert the value into an string.
474 return unicode(value)
477 def do_format(value, *args, **kwargs):
479 Apply python string formatting on an object:
481 .. sourcecode:: jinja
483 {{ "%s - %s"|format("Hello?", "Foo!") }}
487 kwargs.update(idx, arg in enumerate(args))
489 return unicode(value) % args
494 Strip leading and trailing whitespace.
499 def do_striptags(value):
501 Strip SGML/XML tags and replace adjacent whitespace by one space.
505 return ' '.join(_striptags_re.sub('', value).split())
508 def do_slice(value, slices, fill_with=None):
510 Slice an iterator and return a list of lists containing
511 those items. Useful if you want to create a div containing
512 three div tags that represent columns:
514 .. sourcecode:: html+jinja
516 <div class="columwrapper">
517 {%- for column in items|slice(3) %}
518 <ul class="column-{{ loop.index }}">
519 {%- for item in column %}
526 If you pass it a second argument it's used to fill missing
527 values on the last iteration.
534 items_per_slice = length // slices
535 slices_with_extra = length % slices
537 for slice_number in xrange(slices):
538 start = offset + slice_number * items_per_slice
539 if slice_number < slices_with_extra:
541 end = offset + (slice_number + 1) * items_per_slice
543 if fill_with is not None and slice_number >= slices_with_extra:
544 tmp.append(fill_with)
549 def do_batch(value, linecount, fill_with=None):
551 A filter that batches items. It works pretty much like `slice`
552 just the other way round. It returns a list of lists with the
553 given number of items. If you provide a second parameter this
554 is used to fill missing items. See this example:
556 .. sourcecode:: html+jinja
559 {%- for row in items|batch(3, ' ') %}
561 {%- for column in row %}
562 <tr>{{ column }}</td>
573 if len(tmp) == linecount:
578 if fill_with is not None and len(tmp) < linecount:
579 tmp += [fill_with] * (linecount - len(tmp))
584 def do_round(precision=0, method='common'):
586 Round the number to a given precision. The first
587 parameter specifies the precision (default is ``0``), the
588 second the rounding method:
590 - ``'common'`` rounds either up or down
591 - ``'ceil'`` always rounds up
592 - ``'floor'`` always rounds down
594 If you don't specify a method ``'common'`` is used.
596 .. sourcecode:: jinja
600 {{ 42.55|round(1, 'floor') }}
605 if not method in ('common', 'ceil', 'floor'):
606 raise FilterArgumentError('method must be common, ceil or floor')
608 raise FilterArgumentError('precision must be a postive integer '
610 def wrapped(env, context, value):
611 if method == 'common':
612 return round(value, precision)
614 func = getattr(math, method)
616 return func(value * 10 * precision) / (10 * precision)
622 def do_sort(reverse=False):
624 Sort a sequence. Per default it sorts ascending, if you pass it
625 `True` as first argument it will reverse the sorting.
629 def wrapped(env, context, value):
630 return sorted(value, reverse=reverse)
634 def do_groupby(attribute):
636 Group a sequence of objects by a common attribute.
638 If you for example have a list of dicts or objects that represent persons
639 with `gender`, `first_name` and `last_name` attributes and you want to
640 group all users by genders you can do something like the following
643 .. sourcecode:: html+jinja
646 {% for group in persons|groupby('gender') %}
647 <li>{{ group.grouper }}<ul>
648 {% for person in group.list %}
649 <li>{{ person.first_name }} {{ person.last_name }}</li>
650 {% endfor %}</ul></li>
654 As you can see the item we're grouping by is stored in the `grouper`
655 attribute and the `list` contains all the objects that have this grouper
660 def wrapped(env, context, value):
661 expr = lambda x: env.get_attribute(x, attribute)
665 } for a, b in groupby(sorted(value, key=expr), expr)],
666 key=itemgetter('grouper'))
671 'replace': do_replace,
676 'xmlattr': do_xmlattr,
677 'capitalize': do_capitalize,
679 'default': do_default,
682 'dictsort': do_dictsort,
687 'capitalize': do_capitalize,
691 'jsonencode': do_jsonencode,
692 'filesizeformat': do_filesizeformat,
695 'truncate': do_truncate,
696 'wordwrap': do_wordwrap,
697 'wordcount': do_wordcount,
698 'textile': do_textile,
699 'markdown': do_markdown,
707 'striptags': do_striptags,
714 'groupby': do_groupby,