blob: 46a0e09dbf71babdd059d3d94d6207008ccfd533 [file] [log] [blame]
Armin Ronacher92f572f2007-02-26 22:17:32 +01001# -*- coding: utf-8 -*-
2"""
3 jinja.filters
4 ~~~~~~~~~~~~~
5
6 Bundled jinja filters.
7
Christoph Hack2751d942008-04-09 12:14:55 +02008 :copyright: 2008 by Armin Ronacher, Christoph Hack.
Armin Ronacher92f572f2007-02-26 22:17:32 +01009 :license: BSD, see LICENSE for more details.
10"""
Georg Brandlaf31e4d2007-04-15 00:47:37 +020011import re
Armin Ronacherfed86c12007-02-27 10:31:14 +010012from random import choice
Armin Ronacher1dcdac52007-12-09 22:53:46 +010013try:
14 from operator import itemgetter
15except ImportError:
16 itemgetter = lambda a: lambda b: b[a]
Armin Ronacherfed86c12007-02-27 10:31:14 +010017from urllib import urlencode, quote
Armin Ronacher18c6ca02008-04-17 10:03:29 +020018from jinja2.utils import Markup, escape, pformat, urlize
Christoph Hack80909862008-04-14 01:35:10 +020019from jinja2.runtime import Undefined
Christoph Hacke9e43bb2008-04-13 23:35:48 +020020
Armin Ronacherfed86c12007-02-27 10:31:14 +010021
22
Armin Ronachereaf493e2007-10-01 22:31:16 +020023_striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
Armin Ronacher9bcd4112007-05-29 14:17:24 +020024
25
Christoph Hack2751d942008-04-09 12:14:55 +020026def contextfilter(f):
Armin Ronacher8edbe492008-04-10 20:43:43 +020027 """Decorator for marking context dependent filters. The current context
Christoph Hack2751d942008-04-09 12:14:55 +020028 argument will be passed as first argument.
Armin Ronacher92f572f2007-02-26 22:17:32 +010029 """
Christoph Hack2751d942008-04-09 12:14:55 +020030 f.contextfilter = True
31 return f
Armin Ronacher9bcd4112007-05-29 14:17:24 +020032
33
Armin Ronacher92f572f2007-02-26 22:17:32 +010034def do_replace(s, old, new, count=None):
35 """
Armin Ronacher37a88512007-03-02 20:42:18 +010036 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:
Armin Ronacher92f572f2007-02-26 22:17:32 +010041
Armin Ronacher37a88512007-03-02 20:42:18 +010042 .. sourcecode:: jinja
43
44 {{ "Hello World"|replace("Hello", "Goodbye") }}
45 -> Goodbye World
46
47 {{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
48 -> d'oh, d'oh, aaargh
Armin Ronacher92f572f2007-02-26 22:17:32 +010049 """
Armin Ronacher2b765132007-03-13 16:48:10 +010050 if not isinstance(old, basestring) or \
51 not isinstance(new, basestring):
Armin Ronacherae16fd02007-03-27 21:31:24 +020052 raise FilterArgumentError('the replace filter requires '
53 'string replacement arguments')
Armin Ronacher2da479f2007-04-02 10:50:18 +020054 if count is None:
55 return s.replace(old, new)
56 if not isinstance(count, (int, long)):
Armin Ronacherae16fd02007-03-27 21:31:24 +020057 raise FilterArgumentError('the count parameter of the '
58 'replace filter requires '
59 'an integer')
Armin Ronacher92f572f2007-02-26 22:17:32 +010060 return s.replace(old, new, count)
Armin Ronacher92f572f2007-02-26 22:17:32 +010061
62
63def do_upper(s):
Armin Ronacher8edbe492008-04-10 20:43:43 +020064 """Convert a value to uppercase."""
65 return unicode(s).upper()
Armin Ronacher92f572f2007-02-26 22:17:32 +010066
67
Christoph Hack2751d942008-04-09 12:14:55 +020068def do_lower(s):
Armin Ronacher8edbe492008-04-10 20:43:43 +020069 """Convert a value to lowercase."""
70 return unicode(s).lower()
Armin Ronacher92f572f2007-02-26 22:17:32 +010071
72
Christoph Hack2751d942008-04-09 12:14:55 +020073def do_escape(s, attribute=False):
Armin Ronacher92f572f2007-02-26 22:17:32 +010074 """
Armin Ronacher37a88512007-03-02 20:42:18 +010075 XML escape ``&``, ``<``, and ``>`` in a string of data. If the
76 optional parameter is `true` this filter will also convert
77 ``"`` to ``&quot;``. This filter is just used if the environment
78 was configured with disabled `auto_escape`.
Armin Ronacher92f572f2007-02-26 22:17:32 +010079
Armin Ronacher37a88512007-03-02 20:42:18 +010080 This method will have no effect it the value is already escaped.
Armin Ronacher92f572f2007-02-26 22:17:32 +010081 """
Christoph Hackf4fdc722008-04-08 16:48:30 +020082 return escape(unicode(s), attribute)
Armin Ronacher92f572f2007-02-26 22:17:32 +010083
84
Christoph Hack2751d942008-04-09 12:14:55 +020085def do_xmlattr(d, autospace=False):
Armin Ronacher450756b2007-04-15 15:13:59 +020086 """
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
89 escaped:
90
Armin Ronacher8ca55df2007-04-15 15:16:08 +020091 .. sourcecode:: html+jinja
Armin Ronacher450756b2007-04-15 15:13:59 +020092
Armin Ronacherc7ddd1d2007-04-28 15:56:27 +020093 <ul{{ {'class': 'my_list', 'missing': None,
Armin Ronacherd459e272007-04-15 15:31:05 +020094 'id': 'list-%d'|format(variable)}|xmlattr }}>
Armin Ronacher450756b2007-04-15 15:13:59 +020095 ...
96 </ul>
97
98 Results in something like this:
99
Armin Ronacher8ca55df2007-04-15 15:16:08 +0200100 .. sourcecode:: html
101
Armin Ronacher450756b2007-04-15 15:13:59 +0200102 <ul class="my_list" id="list-42">
103 ...
104 </ul>
105
Armin Ronacher9bcd4112007-05-29 14:17:24 +0200106 As you can see it automatically prepends a space in front of the item
Armin Ronacherc7ddd1d2007-04-28 15:56:27 +0200107 if the filter returned something. You can disable this by passing
108 `false` as only argument to the filter.
109
Armin Ronacher450756b2007-04-15 15:13:59 +0200110 *New in Jinja 1.1*
111 """
Christoph Hack2751d942008-04-09 12:14:55 +0200112 if not hasattr(d, 'iteritems'):
113 raise TypeError('a dict is required')
114 result = []
115 for key, value in d.iteritems():
Armin Ronacher5f514882008-04-16 15:29:52 +0200116 if value is not None and not isinstance(value, Undefined):
Christoph Hack2751d942008-04-09 12:14:55 +0200117 result.append(u'%s="%s"' % (
118 escape(env.to_unicode(key)),
119 escape(env.to_unicode(value), True)
120 ))
121 rv = u' '.join(result)
122 if autospace:
123 rv = ' ' + rv
124 return rv
Armin Ronacher450756b2007-04-15 15:13:59 +0200125
126
Armin Ronacher92f572f2007-02-26 22:17:32 +0100127def do_capitalize(s):
128 """
Armin Ronacher37a88512007-03-02 20:42:18 +0100129 Capitalize a value. The first character will be uppercase, all others
130 lowercase.
Armin Ronacher92f572f2007-02-26 22:17:32 +0100131 """
Christoph Hack2751d942008-04-09 12:14:55 +0200132 return unicode(s).capitalize()
Armin Ronacher92f572f2007-02-26 22:17:32 +0100133
134
135def do_title(s):
136 """
Armin Ronacher37a88512007-03-02 20:42:18 +0100137 Return a titlecased version of the value. I.e. words will start with
138 uppercase letters, all remaining characters are lowercase.
Armin Ronacher92f572f2007-02-26 22:17:32 +0100139 """
Christoph Hack2751d942008-04-09 12:14:55 +0200140 return unicode(s).title()
Armin Ronacher92f572f2007-02-26 22:17:32 +0100141
142
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200143def do_dictsort(value, case_sensitive=False, by='key'):
Armin Ronacher2b765132007-03-13 16:48:10 +0100144 """
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
147 key or value:
148
149 .. sourcecode:: jinja
150
151 {% for item in mydict|dictsort %}
152 sort the dict by key, case insensitive
153
154 {% for item in mydict|dicsort(true) %}
155 sort the dict by key, case sensitive
156
157 {% for item in mydict|dictsort(false, 'value') %}
158 sort the dict by key, case insensitive, sorted
159 normally and ordered by value.
160 """
161 if by == 'key':
162 pos = 0
163 elif by == 'value':
164 pos = 1
165 else:
166 raise FilterArgumentError('You can only sort by either '
167 '"key" or "value"')
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200168 def sort_func(value):
Armin Ronacher2b765132007-03-13 16:48:10 +0100169 if isinstance(value, basestring):
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200170 value = unicode(value)
Armin Ronacher2b765132007-03-13 16:48:10 +0100171 if not case_sensitive:
172 value = value.lower()
173 return value
174
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200175 items = value.items()
176 items.sort(lambda a, b: cmp(sort_func(a[pos]), sort_func(b[pos])))
177 return items
Armin Ronacher2b765132007-03-13 16:48:10 +0100178
179
Christoph Hack2751d942008-04-09 12:14:55 +0200180def do_default(value, default_value=u'', boolean=False):
Armin Ronacher92f572f2007-02-26 22:17:32 +0100181 """
Armin Ronacher37a88512007-03-02 20:42:18 +0100182 If the value is undefined it will return the passed default value,
183 otherwise the value of the variable:
Armin Ronacher92f572f2007-02-26 22:17:32 +0100184
Armin Ronacher37a88512007-03-02 20:42:18 +0100185 .. sourcecode:: jinja
186
187 {{ my_variable|default('my_variable is not defined') }}
188
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`:
193
194 .. sourcecode:: jinja
195
196 {{ ''|default('the string was empty', true) }}
Armin Ronacher92f572f2007-02-26 22:17:32 +0100197 """
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200198 if (boolean and not value) or isinstance(value, Undefined):
Christoph Hack2751d942008-04-09 12:14:55 +0200199 return default_value
200 return value
Armin Ronacher92f572f2007-02-26 22:17:32 +0100201
202
Christoph Hack2751d942008-04-09 12:14:55 +0200203def do_join(value, d=u''):
Armin Ronacher92f572f2007-02-26 22:17:32 +0100204 """
Armin Ronacher92f572f2007-02-26 22:17:32 +0100205 Return a string which is the concatenation of the strings in the
Armin Ronacher37a88512007-03-02 20:42:18 +0100206 sequence. The separator between elements is an empty string per
207 default, you can define ith with the optional parameter:
208
209 .. sourcecode:: jinja
210
211 {{ [1, 2, 3]|join('|') }}
212 -> 1|2|3
213
214 {{ [1, 2, 3]|join }}
215 -> 123
Armin Ronacher92f572f2007-02-26 22:17:32 +0100216 """
Armin Ronacher5f514882008-04-16 15:29:52 +0200217 return unicode(d).join(unicode(x) for x in value)
Armin Ronacher92f572f2007-02-26 22:17:32 +0100218
219
Armin Ronacherfed86c12007-02-27 10:31:14 +0100220def do_center(value, width=80):
221 """
Armin Ronacherfed86c12007-02-27 10:31:14 +0100222 Centers the value in a field of a given width.
223 """
Christoph Hack2751d942008-04-09 12:14:55 +0200224 return unicode(value).center(width)
Armin Ronacherfed86c12007-02-27 10:31:14 +0100225
226
Armin Ronacher5f514882008-04-16 15:29:52 +0200227@contextfilter
228def do_first(context, seq):
Armin Ronacherfed86c12007-02-27 10:31:14 +0100229 """
Armin Ronacher37a88512007-03-02 20:42:18 +0100230 Return the frist item of a sequence.
Armin Ronacherfed86c12007-02-27 10:31:14 +0100231 """
Christoph Hack2751d942008-04-09 12:14:55 +0200232 try:
233 return iter(seq).next()
234 except StopIteration:
Armin Ronacher5f514882008-04-16 15:29:52 +0200235 return context.environment.undefined('seq|first',
236 extra='the sequence was empty')
Armin Ronacherfed86c12007-02-27 10:31:14 +0100237
238
Armin Ronacher5f514882008-04-16 15:29:52 +0200239@contextfilter
240def do_last(context, seq):
Armin Ronacherfed86c12007-02-27 10:31:14 +0100241 """
Armin Ronacherfed86c12007-02-27 10:31:14 +0100242 Return the last item of a sequence.
243 """
Christoph Hack2751d942008-04-09 12:14:55 +0200244 try:
245 return iter(reversed(seq)).next()
246 except StopIteration:
Armin Ronacher5f514882008-04-16 15:29:52 +0200247 return context.environment.undefined('seq|last',
248 extra='the sequence was empty')
Armin Ronacherfed86c12007-02-27 10:31:14 +0100249
250
Armin Ronacher5f514882008-04-16 15:29:52 +0200251@contextfilter
252def do_random(context, seq):
Armin Ronacherfed86c12007-02-27 10:31:14 +0100253 """
Armin Ronacherfed86c12007-02-27 10:31:14 +0100254 Return a random item from the sequence.
255 """
Christoph Hack2751d942008-04-09 12:14:55 +0200256 try:
257 return choice(seq)
258 except IndexError:
Armin Ronacher5f514882008-04-16 15:29:52 +0200259 return context.environment.undefined('seq|random',
260 extra='the sequence was empty')
Armin Ronacherfed86c12007-02-27 10:31:14 +0100261
262
Christoph Hack2751d942008-04-09 12:14:55 +0200263def do_jsonencode(value):
Armin Ronacherfed86c12007-02-27 10:31:14 +0100264 """
Armin Ronacherfed86c12007-02-27 10:31:14 +0100265 JSON dump a variable. just works if simplejson is installed.
Armin Ronacher37a88512007-03-02 20:42:18 +0100266
267 .. sourcecode:: jinja
268
269 {{ 'Hello World'|jsonencode }}
270 -> "Hello World"
Armin Ronacherfed86c12007-02-27 10:31:14 +0100271 """
272 global simplejson
273 try:
274 simplejson
275 except NameError:
276 import simplejson
Christoph Hack2751d942008-04-09 12:14:55 +0200277 return simplejson.dumps(value)
Armin Ronacherfed86c12007-02-27 10:31:14 +0100278
279
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200280def do_filesizeformat(value):
Armin Ronacher2b765132007-03-13 16:48:10 +0100281 """
Armin Ronacher5f514882008-04-16 15:29:52 +0200282 Format the value like a 'human-readable' file size (i.e. 13 KB,
283 4.1 MB, 102 bytes, etc).
Armin Ronacher2b765132007-03-13 16:48:10 +0100284 """
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200285 # fail silently
286 try:
287 bytes = float(value)
288 except TypeError:
289 bytes = 0
Armin Ronacher2b765132007-03-13 16:48:10 +0100290
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200291 if bytes < 1024:
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))
Armin Ronacher2b765132007-03-13 16:48:10 +0100298
299
Christoph Hack2751d942008-04-09 12:14:55 +0200300def do_pprint(value, verbose=False):
Armin Ronacher2b765132007-03-13 16:48:10 +0100301 """
302 Pretty print a variable. Useful for debugging.
Armin Ronacherf2ce1262007-10-21 21:51:51 +0200303
304 With Jinja 1.2 onwards you can pass it a parameter. If this parameter
Armin Ronacher5f3f1362007-10-21 22:15:04 +0200305 is truthy the output will be more verbose (this requires `pretty`)
Armin Ronacher2b765132007-03-13 16:48:10 +0100306 """
Christoph Hack2751d942008-04-09 12:14:55 +0200307 return pformat(value, verbose=verbose)
Armin Ronacher2b765132007-03-13 16:48:10 +0100308
309
310def do_urlize(value, trim_url_limit=None, nofollow=False):
311 """
312 Converts URLs in plain text into clickable links.
313
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
316 "nofollow":
317
318 .. sourcecode:: jinja
319
320 {{ mytext|urlize(40, True) }}
321 links are shortened to 40 chars and defined with rel="nofollow"
322 """
Christoph Hack2751d942008-04-09 12:14:55 +0200323 return urlize(unicode(value), trim_url_limit, nofollow)
Armin Ronacher2b765132007-03-13 16:48:10 +0100324
325
326def do_indent(s, width=4, indentfirst=False):
327 """
328 {{ s|indent[ width[ indentfirst[ usetab]]] }}
329
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:
334
335 .. sourcecode:: jinja
336
337 {{ mytext|indent(2, True) }}
338 indent by two spaces and indent the first line too.
339 """
340 indention = ' ' * width
341 if indentfirst:
342 return u'\n'.join([indention + line for line in s.splitlines()])
343 return s.replace('\n', '\n' + indention)
Armin Ronacher2b765132007-03-13 16:48:10 +0100344
345
346def do_truncate(s, length=255, killwords=False, end='...'):
347 """
Armin Ronacher2b765132007-03-13 16:48:10 +0100348 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
354 third parameter.
355
356 .. sourcecode jinja::
357
358 {{ mytext|truncate(300, false, '&raquo;') }}
359 truncate mytext to 300 chars, don't split up words, use a
360 right pointing double arrow as ellipsis sign.
361 """
362 if len(s) <= length:
363 return s
364 elif killwords:
365 return s[:length] + end
366 words = s.split(' ')
367 result = []
368 m = 0
369 for word in words:
370 m += len(word) + 1
371 if m > length:
372 break
373 result.append(word)
374 result.append(end)
375 return u' '.join(result)
Armin Ronacher2b765132007-03-13 16:48:10 +0100376
377
378def do_wordwrap(s, pos=79, hard=False):
379 """
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
384 reading hard).
385 """
386 if len(s) < pos:
387 return s
388 if hard:
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)],
395 word), s.split(' '))
Armin Ronacher2b765132007-03-13 16:48:10 +0100396
397
398def do_wordcount(s):
399 """
400 Count the words in that string.
401 """
402 return len([x for x in s.split() if x])
Armin Ronacher2b765132007-03-13 16:48:10 +0100403
404
405def do_textile(s):
406 """
407 Prase the string using textile.
408
409 requires the `PyTextile`_ library.
410
411 .. _PyTextile: http://dealmeida.net/projects/textile/
412 """
413 from textile import textile
Armin Ronacher8712dad2007-06-08 01:07:48 +0200414 return textile(s.encode('utf-8')).decode('utf-8')
Armin Ronacher2b765132007-03-13 16:48:10 +0100415
416
417def do_markdown(s):
418 """
419 Parse the string using markdown.
420
421 requires the `Python-markdown`_ library.
422
423 .. _Python-markdown: http://www.freewisdom.org/projects/python-markdown/
424 """
425 from markdown import markdown
Armin Ronacher8712dad2007-06-08 01:07:48 +0200426 return markdown(s.encode('utf-8')).decode('utf-8')
Armin Ronacher2b765132007-03-13 16:48:10 +0100427
428
429def do_rst(s):
430 """
431 Parse the string using the reStructuredText parser from the
432 docutils package.
433
434 requires `docutils`_.
435
Georg Brandlfde3ff22007-07-18 09:27:01 +0200436 .. _docutils: http://docutils.sourceforge.net/
Armin Ronacher2b765132007-03-13 16:48:10 +0100437 """
Armin Ronacher8712dad2007-06-08 01:07:48 +0200438 from docutils.core import publish_parts
439 parts = publish_parts(source=s, writer_name='html4css1')
440 return parts['fragment']
Armin Ronacher2b765132007-03-13 16:48:10 +0100441
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200442
443def do_int(value, default=0):
Armin Ronacher2b765132007-03-13 16:48:10 +0100444 """
Armin Ronacherab45b842007-03-18 20:47:50 +0100445 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.
Armin Ronacher2b765132007-03-13 16:48:10 +0100448 """
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200449 try:
450 return int(value)
451 except (TypeError, ValueError):
Armin Ronacherab45b842007-03-18 20:47:50 +0100452 try:
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200453 return int(float(value))
Armin Ronacherab45b842007-03-18 20:47:50 +0100454 except (TypeError, ValueError):
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200455 return default
Armin Ronacher2b765132007-03-13 16:48:10 +0100456
457
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200458def do_float(value, default=0.0):
Armin Ronacher2b765132007-03-13 16:48:10 +0100459 """
Armin Ronacherab45b842007-03-18 20:47:50 +0100460 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.
Armin Ronacher2b765132007-03-13 16:48:10 +0100463 """
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200464 try:
465 return float(value)
466 except (TypeError, ValueError):
467 return default
Armin Ronacher2b765132007-03-13 16:48:10 +0100468
469
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200470def do_string(value):
Armin Ronacher2b765132007-03-13 16:48:10 +0100471 """
472 Convert the value into an string.
473 """
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200474 return unicode(value)
Armin Ronacher2b765132007-03-13 16:48:10 +0100475
476
Armin Ronacher5f514882008-04-16 15:29:52 +0200477def do_format(value, *args, **kwargs):
Armin Ronacherf0f4deb2007-03-18 23:10:15 +0100478 """
479 Apply python string formatting on an object:
480
481 .. sourcecode:: jinja
482
483 {{ "%s - %s"|format("Hello?", "Foo!") }}
484 -> Hello? - Foo!
Armin Ronacherf0f4deb2007-03-18 23:10:15 +0100485 """
Armin Ronacher5f514882008-04-16 15:29:52 +0200486 if kwargs:
487 kwargs.update(idx, arg in enumerate(args))
488 args = kwargs
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200489 return unicode(value) % args
Armin Ronacherf0f4deb2007-03-18 23:10:15 +0100490
491
Armin Ronacher566295e2007-03-19 13:19:34 +0100492def do_trim(value):
493 """
494 Strip leading and trailing whitespace.
495 """
496 return value.strip()
Armin Ronacher566295e2007-03-19 13:19:34 +0100497
498
Armin Ronacher9bcd4112007-05-29 14:17:24 +0200499def do_striptags(value):
Georg Brandlaf31e4d2007-04-15 00:47:37 +0200500 """
501 Strip SGML/XML tags and replace adjacent whitespace by one space.
Armin Ronacher21580912007-04-17 17:13:10 +0200502
Georg Brandlaf31e4d2007-04-15 00:47:37 +0200503 *new in Jinja 1.1*
504 """
Armin Ronacher9bcd4112007-05-29 14:17:24 +0200505 return ' '.join(_striptags_re.sub('', value).split())
Georg Brandlaf31e4d2007-04-15 00:47:37 +0200506
507
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200508def do_slice(value, slices, fill_with=None):
Armin Ronacherd071f952007-04-13 22:32:11 +0200509 """
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:
513
Armin Ronacher89376072007-04-13 22:34:35 +0200514 .. sourcecode:: html+jinja
Armin Ronacherd071f952007-04-13 22:32:11 +0200515
516 <div class="columwrapper">
517 {%- for column in items|slice(3) %}
518 <ul class="column-{{ loop.index }}">
519 {%- for item in column %}
520 <li>{{ item }}</li>
521 {%- endfor %}
522 </ul>
523 {%- endfor %}
524 </div>
525
Armin Ronachereec31382007-04-14 14:50:45 +0200526 If you pass it a second argument it's used to fill missing
527 values on the last iteration.
528
529 *new in Jinja 1.1*
Armin Ronacherd071f952007-04-13 22:32:11 +0200530 """
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200531 result = []
532 seq = list(value)
533 length = len(seq)
534 items_per_slice = length // slices
535 slices_with_extra = length % slices
536 offset = 0
537 for slice_number in xrange(slices):
538 start = offset + slice_number * items_per_slice
539 if slice_number < slices_with_extra:
540 offset += 1
541 end = offset + (slice_number + 1) * items_per_slice
542 tmp = seq[start:end]
543 if fill_with is not None and slice_number >= slices_with_extra:
544 tmp.append(fill_with)
545 result.append(tmp)
546 return result
Armin Ronacherd071f952007-04-13 22:32:11 +0200547
548
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200549def do_batch(value, linecount, fill_with=None):
Armin Ronacherd071f952007-04-13 22:32:11 +0200550 """
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:
555
Armin Ronacher89376072007-04-13 22:34:35 +0200556 .. sourcecode:: html+jinja
Armin Ronacherd071f952007-04-13 22:32:11 +0200557
558 <table>
559 {%- for row in items|batch(3, '&nbsp;') %}
560 <tr>
561 {%- for column in row %}
562 <tr>{{ column }}</td>
563 {%- endfor %}
564 </tr>
565 {%- endfor %}
566 </table>
567
Armin Ronachereec31382007-04-14 14:50:45 +0200568 *new in Jinja 1.1*
Armin Ronacherd071f952007-04-13 22:32:11 +0200569 """
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200570 result = []
571 tmp = []
572 for item in value:
573 if len(tmp) == linecount:
Armin Ronacherd071f952007-04-13 22:32:11 +0200574 result.append(tmp)
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200575 tmp = []
576 tmp.append(item)
577 if tmp:
578 if fill_with is not None and len(tmp) < linecount:
579 tmp += [fill_with] * (linecount - len(tmp))
580 result.append(tmp)
581 return result
Armin Ronacherd071f952007-04-13 22:32:11 +0200582
583
Armin Ronachereec31382007-04-14 14:50:45 +0200584def do_round(precision=0, method='common'):
585 """
586 Round the number to a given precision. The first
587 parameter specifies the precision (default is ``0``), the
588 second the rounding method:
589
590 - ``'common'`` rounds either up or down
591 - ``'ceil'`` always rounds up
592 - ``'floor'`` always rounds down
593
594 If you don't specify a method ``'common'`` is used.
595
596 .. sourcecode:: jinja
597
598 {{ 42.55|round }}
599 -> 43
600 {{ 42.55|round(1, 'floor') }}
601 -> 42.5
Armin Ronachera38b3122007-04-15 00:49:13 +0200602
603 *new in Jinja 1.1*
Armin Ronachereec31382007-04-14 14:50:45 +0200604 """
605 if not method in ('common', 'ceil', 'floor'):
606 raise FilterArgumentError('method must be common, ceil or floor')
607 if precision < 0:
608 raise FilterArgumentError('precision must be a postive integer '
609 'or zero.')
610 def wrapped(env, context, value):
611 if method == 'common':
612 return round(value, precision)
613 import math
614 func = getattr(math, method)
Armin Ronacher21580912007-04-17 17:13:10 +0200615 if precision:
616 return func(value * 10 * precision) / (10 * precision)
617 else:
618 return func(value)
Armin Ronachereec31382007-04-14 14:50:45 +0200619 return wrapped
620
621
Armin Ronacher9bcd4112007-05-29 14:17:24 +0200622def do_sort(reverse=False):
623 """
624 Sort a sequence. Per default it sorts ascending, if you pass it
625 `True` as first argument it will reverse the sorting.
626
627 *new in Jinja 1.1*
628 """
629 def wrapped(env, context, value):
630 return sorted(value, reverse=reverse)
631 return wrapped
632
633
Armin Ronachere39a5d22007-06-23 21:11:53 +0200634def do_groupby(attribute):
635 """
636 Group a sequence of objects by a common attribute.
637
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
641 snippet:
642
643 .. sourcecode:: html+jinja
644
645 <ul>
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>
651 {% endfor %}
652 </ul>
653
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
656 in common.
Armin Ronacher69ddc582007-06-24 12:37:13 +0200657
658 *New in Jinja 1.2*
Armin Ronachere39a5d22007-06-23 21:11:53 +0200659 """
660 def wrapped(env, context, value):
661 expr = lambda x: env.get_attribute(x, attribute)
Armin Ronacher30ffab12007-07-10 20:51:47 +0200662 return sorted([{
Armin Ronachere39a5d22007-06-23 21:11:53 +0200663 'grouper': a,
664 'list': list(b)
Armin Ronacher30ffab12007-07-10 20:51:47 +0200665 } for a, b in groupby(sorted(value, key=expr), expr)],
666 key=itemgetter('grouper'))
Armin Ronachere39a5d22007-06-23 21:11:53 +0200667 return wrapped
668
669
Armin Ronacher92f572f2007-02-26 22:17:32 +0100670FILTERS = {
671 'replace': do_replace,
672 'upper': do_upper,
673 'lower': do_lower,
674 'escape': do_escape,
675 'e': do_escape,
Armin Ronacher450756b2007-04-15 15:13:59 +0200676 'xmlattr': do_xmlattr,
Armin Ronacher92f572f2007-02-26 22:17:32 +0100677 'capitalize': do_capitalize,
678 'title': do_title,
679 'default': do_default,
680 'join': do_join,
Armin Ronacher5f514882008-04-16 15:29:52 +0200681 'count': len,
Armin Ronacher2b765132007-03-13 16:48:10 +0100682 'dictsort': do_dictsort,
Armin Ronacher5f514882008-04-16 15:29:52 +0200683 'length': len,
684 'reverse': reversed,
Armin Ronacherfed86c12007-02-27 10:31:14 +0100685 'center': do_center,
686 'title': do_title,
687 'capitalize': do_capitalize,
688 'first': do_first,
689 'last': do_last,
690 'random': do_random,
Armin Ronacher2b765132007-03-13 16:48:10 +0100691 'jsonencode': do_jsonencode,
692 'filesizeformat': do_filesizeformat,
693 'pprint': do_pprint,
694 'indent': do_indent,
695 'truncate': do_truncate,
696 'wordwrap': do_wordwrap,
697 'wordcount': do_wordcount,
698 'textile': do_textile,
699 'markdown': do_markdown,
700 'rst': do_rst,
701 'int': do_int,
702 'float': do_float,
Tassilo Schweyer934cb712007-03-14 18:04:07 +0100703 'string': do_string,
Armin Ronacherf0f4deb2007-03-18 23:10:15 +0100704 'urlize': do_urlize,
705 'format': do_format,
Armin Ronacherd071f952007-04-13 22:32:11 +0200706 'trim': do_trim,
Georg Brandlaf31e4d2007-04-15 00:47:37 +0200707 'striptags': do_striptags,
Armin Ronacherd071f952007-04-13 22:32:11 +0200708 'slice': do_slice,
Armin Ronachereec31382007-04-14 14:50:45 +0200709 'batch': do_batch,
Armin Ronacher5f514882008-04-16 15:29:52 +0200710 'sum': sum,
711 'abs': abs,
Armin Ronacher9bcd4112007-05-29 14:17:24 +0200712 'round': do_round,
Armin Ronachere39a5d22007-06-23 21:11:53 +0200713 'sort': do_sort,
Armin Ronacher18c6ca02008-04-17 10:03:29 +0200714 'groupby': do_groupby,
715 'safe': Markup
Armin Ronacher92f572f2007-02-26 22:17:32 +0100716}