blob: 300e0cd88da0c5a6bb4ecb65886d6def43a7ccc8 [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
Christoph Hack80909862008-04-14 01:35:10 +020018from jinja2.utils import escape, pformat, urlize
19from 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():
116 if value not in (None, env.undefined_singleton):
117 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 """
Christoph Hack2751d942008-04-09 12:14:55 +0200217 return unicode(d).join([unicode(x) for x in value])
Armin Ronacher92f572f2007-02-26 22:17:32 +0100218
219
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200220def do_count(value):
Armin Ronacher92f572f2007-02-26 22:17:32 +0100221 """
Armin Ronacher37a88512007-03-02 20:42:18 +0100222 Return the length of the value. In case if getting an integer or float
Armin Ronacher92f572f2007-02-26 22:17:32 +0100223 it will convert it into a string an return the length of the new
Armin Ronacher37a88512007-03-02 20:42:18 +0100224 string. If the object has no length it will of corse return 0.
Armin Ronacher92f572f2007-02-26 22:17:32 +0100225 """
Christoph Hack2751d942008-04-09 12:14:55 +0200226 try:
227 if type(value) in (int, float, long):
228 return len(str(value))
229 return len(value)
230 except TypeError:
231 return 0
Armin Ronacher92f572f2007-02-26 22:17:32 +0100232
233
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200234def do_reverse(value):
Armin Ronacher92f572f2007-02-26 22:17:32 +0100235 """
Armin Ronacher37a88512007-03-02 20:42:18 +0100236 Return a reversed list of the sequence filtered. You can use this
237 for example for reverse iteration:
Armin Ronacher92f572f2007-02-26 22:17:32 +0100238
Armin Ronacher37a88512007-03-02 20:42:18 +0100239 .. sourcecode:: jinja
240
Armin Ronacherdbc945d2007-03-05 18:03:32 +0100241 {% for item in seq|reverse %}
Armin Ronacher37a88512007-03-02 20:42:18 +0100242 {{ item|e }}
243 {% endfor %}
Armin Ronacher92f572f2007-02-26 22:17:32 +0100244 """
Christoph Hack2751d942008-04-09 12:14:55 +0200245 try:
246 return value[::-1]
247 except:
248 l = list(value)
249 l.reverse()
250 return l
Armin Ronacher92f572f2007-02-26 22:17:32 +0100251
252
Armin Ronacherfed86c12007-02-27 10:31:14 +0100253def do_center(value, width=80):
254 """
Armin Ronacherfed86c12007-02-27 10:31:14 +0100255 Centers the value in a field of a given width.
256 """
Christoph Hack2751d942008-04-09 12:14:55 +0200257 return unicode(value).center(width)
Armin Ronacherfed86c12007-02-27 10:31:14 +0100258
259
Christoph Hack2751d942008-04-09 12:14:55 +0200260def do_first(seq):
Armin Ronacherfed86c12007-02-27 10:31:14 +0100261 """
Armin Ronacher37a88512007-03-02 20:42:18 +0100262 Return the frist item of a sequence.
Armin Ronacherfed86c12007-02-27 10:31:14 +0100263 """
Christoph Hack2751d942008-04-09 12:14:55 +0200264 try:
265 return iter(seq).next()
266 except StopIteration:
267 return env.undefined_singleton
Armin Ronacherfed86c12007-02-27 10:31:14 +0100268
269
Christoph Hack2751d942008-04-09 12:14:55 +0200270def do_last(seq):
Armin Ronacherfed86c12007-02-27 10:31:14 +0100271 """
Armin Ronacherfed86c12007-02-27 10:31:14 +0100272 Return the last item of a sequence.
273 """
Christoph Hack2751d942008-04-09 12:14:55 +0200274 try:
275 return iter(reversed(seq)).next()
276 except StopIteration:
277 return env.undefined_singleton
Armin Ronacherfed86c12007-02-27 10:31:14 +0100278
279
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200280def do_random(seq):
Armin Ronacherfed86c12007-02-27 10:31:14 +0100281 """
Armin Ronacherfed86c12007-02-27 10:31:14 +0100282 Return a random item from the sequence.
283 """
Christoph Hack2751d942008-04-09 12:14:55 +0200284 try:
285 return choice(seq)
286 except IndexError:
287 return env.undefined_singleton
Armin Ronacherfed86c12007-02-27 10:31:14 +0100288
289
Christoph Hack2751d942008-04-09 12:14:55 +0200290def do_jsonencode(value):
Armin Ronacherfed86c12007-02-27 10:31:14 +0100291 """
Armin Ronacherfed86c12007-02-27 10:31:14 +0100292 JSON dump a variable. just works if simplejson is installed.
Armin Ronacher37a88512007-03-02 20:42:18 +0100293
294 .. sourcecode:: jinja
295
296 {{ 'Hello World'|jsonencode }}
297 -> "Hello World"
Armin Ronacherfed86c12007-02-27 10:31:14 +0100298 """
299 global simplejson
300 try:
301 simplejson
302 except NameError:
303 import simplejson
Christoph Hack2751d942008-04-09 12:14:55 +0200304 return simplejson.dumps(value)
Armin Ronacherfed86c12007-02-27 10:31:14 +0100305
306
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200307def do_filesizeformat(value):
Armin Ronacher2b765132007-03-13 16:48:10 +0100308 """
309 Format the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, 102
310 bytes, etc).
311 """
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200312 # fail silently
313 try:
314 bytes = float(value)
315 except TypeError:
316 bytes = 0
Armin Ronacher2b765132007-03-13 16:48:10 +0100317
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200318 if bytes < 1024:
319 return "%d Byte%s" % (bytes, bytes != 1 and 's' or '')
320 elif bytes < 1024 * 1024:
321 return "%.1f KB" % (bytes / 1024)
322 elif bytes < 1024 * 1024 * 1024:
323 return "%.1f MB" % (bytes / (1024 * 1024))
324 return "%.1f GB" % (bytes / (1024 * 1024 * 1024))
Armin Ronacher2b765132007-03-13 16:48:10 +0100325
326
Christoph Hack2751d942008-04-09 12:14:55 +0200327def do_pprint(value, verbose=False):
Armin Ronacher2b765132007-03-13 16:48:10 +0100328 """
329 Pretty print a variable. Useful for debugging.
Armin Ronacherf2ce1262007-10-21 21:51:51 +0200330
331 With Jinja 1.2 onwards you can pass it a parameter. If this parameter
Armin Ronacher5f3f1362007-10-21 22:15:04 +0200332 is truthy the output will be more verbose (this requires `pretty`)
Armin Ronacher2b765132007-03-13 16:48:10 +0100333 """
Christoph Hack2751d942008-04-09 12:14:55 +0200334 return pformat(value, verbose=verbose)
Armin Ronacher2b765132007-03-13 16:48:10 +0100335
336
337def do_urlize(value, trim_url_limit=None, nofollow=False):
338 """
339 Converts URLs in plain text into clickable links.
340
341 If you pass the filter an additional integer it will shorten the urls
342 to that number. Also a third argument exists that makes the urls
343 "nofollow":
344
345 .. sourcecode:: jinja
346
347 {{ mytext|urlize(40, True) }}
348 links are shortened to 40 chars and defined with rel="nofollow"
349 """
Christoph Hack2751d942008-04-09 12:14:55 +0200350 return urlize(unicode(value), trim_url_limit, nofollow)
Armin Ronacher2b765132007-03-13 16:48:10 +0100351
352
353def do_indent(s, width=4, indentfirst=False):
354 """
355 {{ s|indent[ width[ indentfirst[ usetab]]] }}
356
357 Return a copy of the passed string, each line indented by
358 4 spaces. The first line is not indented. If you want to
359 change the number of spaces or indent the first line too
360 you can pass additional parameters to the filter:
361
362 .. sourcecode:: jinja
363
364 {{ mytext|indent(2, True) }}
365 indent by two spaces and indent the first line too.
366 """
367 indention = ' ' * width
368 if indentfirst:
369 return u'\n'.join([indention + line for line in s.splitlines()])
370 return s.replace('\n', '\n' + indention)
Armin Ronacher2b765132007-03-13 16:48:10 +0100371
372
373def do_truncate(s, length=255, killwords=False, end='...'):
374 """
Armin Ronacher2b765132007-03-13 16:48:10 +0100375 Return a truncated copy of the string. The length is specified
376 with the first parameter which defaults to ``255``. If the second
377 parameter is ``true`` the filter will cut the text at length. Otherwise
378 it will try to save the last word. If the text was in fact
379 truncated it will append an ellipsis sign (``"..."``). If you want a
380 different ellipsis sign than ``"..."`` you can specify it using the
381 third parameter.
382
383 .. sourcecode jinja::
384
385 {{ mytext|truncate(300, false, '&raquo;') }}
386 truncate mytext to 300 chars, don't split up words, use a
387 right pointing double arrow as ellipsis sign.
388 """
389 if len(s) <= length:
390 return s
391 elif killwords:
392 return s[:length] + end
393 words = s.split(' ')
394 result = []
395 m = 0
396 for word in words:
397 m += len(word) + 1
398 if m > length:
399 break
400 result.append(word)
401 result.append(end)
402 return u' '.join(result)
Armin Ronacher2b765132007-03-13 16:48:10 +0100403
404
405def do_wordwrap(s, pos=79, hard=False):
406 """
407 Return a copy of the string passed to the filter wrapped after
408 ``79`` characters. You can override this default using the first
409 parameter. If you set the second parameter to `true` Jinja will
410 also split words apart (usually a bad idea because it makes
411 reading hard).
412 """
413 if len(s) < pos:
414 return s
415 if hard:
416 return u'\n'.join([s[idx:idx + pos] for idx in
417 xrange(0, len(s), pos)])
418 # code from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/148061
419 return reduce(lambda line, word, pos=pos: u'%s%s%s' %
420 (line, u' \n'[(len(line)-line.rfind('\n') - 1 +
421 len(word.split('\n', 1)[0]) >= pos)],
422 word), s.split(' '))
Armin Ronacher2b765132007-03-13 16:48:10 +0100423
424
425def do_wordcount(s):
426 """
427 Count the words in that string.
428 """
429 return len([x for x in s.split() if x])
Armin Ronacher2b765132007-03-13 16:48:10 +0100430
431
432def do_textile(s):
433 """
434 Prase the string using textile.
435
436 requires the `PyTextile`_ library.
437
438 .. _PyTextile: http://dealmeida.net/projects/textile/
439 """
440 from textile import textile
Armin Ronacher8712dad2007-06-08 01:07:48 +0200441 return textile(s.encode('utf-8')).decode('utf-8')
Armin Ronacher2b765132007-03-13 16:48:10 +0100442
443
444def do_markdown(s):
445 """
446 Parse the string using markdown.
447
448 requires the `Python-markdown`_ library.
449
450 .. _Python-markdown: http://www.freewisdom.org/projects/python-markdown/
451 """
452 from markdown import markdown
Armin Ronacher8712dad2007-06-08 01:07:48 +0200453 return markdown(s.encode('utf-8')).decode('utf-8')
Armin Ronacher2b765132007-03-13 16:48:10 +0100454
455
456def do_rst(s):
457 """
458 Parse the string using the reStructuredText parser from the
459 docutils package.
460
461 requires `docutils`_.
462
Georg Brandlfde3ff22007-07-18 09:27:01 +0200463 .. _docutils: http://docutils.sourceforge.net/
Armin Ronacher2b765132007-03-13 16:48:10 +0100464 """
Armin Ronacher8712dad2007-06-08 01:07:48 +0200465 from docutils.core import publish_parts
466 parts = publish_parts(source=s, writer_name='html4css1')
467 return parts['fragment']
Armin Ronacher2b765132007-03-13 16:48:10 +0100468
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200469
470def do_int(value, default=0):
Armin Ronacher2b765132007-03-13 16:48:10 +0100471 """
Armin Ronacherab45b842007-03-18 20:47:50 +0100472 Convert the value into an integer. If the
473 conversion doesn't work it will return ``0``. You can
474 override this default using the first parameter.
Armin Ronacher2b765132007-03-13 16:48:10 +0100475 """
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200476 try:
477 return int(value)
478 except (TypeError, ValueError):
Armin Ronacherab45b842007-03-18 20:47:50 +0100479 try:
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200480 return int(float(value))
Armin Ronacherab45b842007-03-18 20:47:50 +0100481 except (TypeError, ValueError):
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200482 return default
Armin Ronacher2b765132007-03-13 16:48:10 +0100483
484
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200485def do_float(value, default=0.0):
Armin Ronacher2b765132007-03-13 16:48:10 +0100486 """
Armin Ronacherab45b842007-03-18 20:47:50 +0100487 Convert the value into a floating point number. If the
488 conversion doesn't work it will return ``0.0``. You can
489 override this default using the first parameter.
Armin Ronacher2b765132007-03-13 16:48:10 +0100490 """
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200491 try:
492 return float(value)
493 except (TypeError, ValueError):
494 return default
Armin Ronacher2b765132007-03-13 16:48:10 +0100495
496
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200497def do_string(value):
Armin Ronacher2b765132007-03-13 16:48:10 +0100498 """
499 Convert the value into an string.
500 """
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200501 return unicode(value)
Armin Ronacher2b765132007-03-13 16:48:10 +0100502
503
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200504def do_format(value, *args):
Armin Ronacherf0f4deb2007-03-18 23:10:15 +0100505 """
506 Apply python string formatting on an object:
507
508 .. sourcecode:: jinja
509
510 {{ "%s - %s"|format("Hello?", "Foo!") }}
511 -> Hello? - Foo!
512
513 Note that you cannot use the mapping syntax (``%(name)s``)
Armin Ronacher49659872007-05-12 23:29:33 +0200514 like in python. Use `|dformat` for that.
Armin Ronacherf0f4deb2007-03-18 23:10:15 +0100515 """
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200516 return unicode(value) % args
Armin Ronacherf0f4deb2007-03-18 23:10:15 +0100517
518
Armin Ronacher49659872007-05-12 23:29:33 +0200519def do_dformat(d):
520 """
521 Apply python mapping string formatting on an object:
522
523 .. sourcecode:: jinja
524
525 {{ "Hello %(username)s!"|dformat({'username': 'John Doe'}) }}
526 -> Hello John Doe!
527
528 This is useful when adding variables to translateable
529 string expressions.
530
531 *New in Jinja 1.1*
532 """
533 if not isinstance(d, dict):
534 raise FilterArgumentError('dict required')
535 def wrapped(env, context, value):
536 return env.to_unicode(value) % d
537 return wrapped
538
539
Armin Ronacher566295e2007-03-19 13:19:34 +0100540def do_trim(value):
541 """
542 Strip leading and trailing whitespace.
543 """
544 return value.strip()
Armin Ronacher566295e2007-03-19 13:19:34 +0100545
546
Armin Ronacher9bcd4112007-05-29 14:17:24 +0200547def do_striptags(value):
Georg Brandlaf31e4d2007-04-15 00:47:37 +0200548 """
549 Strip SGML/XML tags and replace adjacent whitespace by one space.
Armin Ronacher21580912007-04-17 17:13:10 +0200550
Georg Brandlaf31e4d2007-04-15 00:47:37 +0200551 *new in Jinja 1.1*
552 """
Armin Ronacher9bcd4112007-05-29 14:17:24 +0200553 return ' '.join(_striptags_re.sub('', value).split())
Georg Brandlaf31e4d2007-04-15 00:47:37 +0200554
555
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200556def do_slice(value, slices, fill_with=None):
Armin Ronacherd071f952007-04-13 22:32:11 +0200557 """
558 Slice an iterator and return a list of lists containing
559 those items. Useful if you want to create a div containing
560 three div tags that represent columns:
561
Armin Ronacher89376072007-04-13 22:34:35 +0200562 .. sourcecode:: html+jinja
Armin Ronacherd071f952007-04-13 22:32:11 +0200563
564 <div class="columwrapper">
565 {%- for column in items|slice(3) %}
566 <ul class="column-{{ loop.index }}">
567 {%- for item in column %}
568 <li>{{ item }}</li>
569 {%- endfor %}
570 </ul>
571 {%- endfor %}
572 </div>
573
Armin Ronachereec31382007-04-14 14:50:45 +0200574 If you pass it a second argument it's used to fill missing
575 values on the last iteration.
576
577 *new in Jinja 1.1*
Armin Ronacherd071f952007-04-13 22:32:11 +0200578 """
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200579 result = []
580 seq = list(value)
581 length = len(seq)
582 items_per_slice = length // slices
583 slices_with_extra = length % slices
584 offset = 0
585 for slice_number in xrange(slices):
586 start = offset + slice_number * items_per_slice
587 if slice_number < slices_with_extra:
588 offset += 1
589 end = offset + (slice_number + 1) * items_per_slice
590 tmp = seq[start:end]
591 if fill_with is not None and slice_number >= slices_with_extra:
592 tmp.append(fill_with)
593 result.append(tmp)
594 return result
Armin Ronacherd071f952007-04-13 22:32:11 +0200595
596
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200597def do_batch(value, linecount, fill_with=None):
Armin Ronacherd071f952007-04-13 22:32:11 +0200598 """
599 A filter that batches items. It works pretty much like `slice`
600 just the other way round. It returns a list of lists with the
601 given number of items. If you provide a second parameter this
602 is used to fill missing items. See this example:
603
Armin Ronacher89376072007-04-13 22:34:35 +0200604 .. sourcecode:: html+jinja
Armin Ronacherd071f952007-04-13 22:32:11 +0200605
606 <table>
607 {%- for row in items|batch(3, '&nbsp;') %}
608 <tr>
609 {%- for column in row %}
610 <tr>{{ column }}</td>
611 {%- endfor %}
612 </tr>
613 {%- endfor %}
614 </table>
615
Armin Ronachereec31382007-04-14 14:50:45 +0200616 *new in Jinja 1.1*
Armin Ronacherd071f952007-04-13 22:32:11 +0200617 """
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200618 result = []
619 tmp = []
620 for item in value:
621 if len(tmp) == linecount:
Armin Ronacherd071f952007-04-13 22:32:11 +0200622 result.append(tmp)
Christoph Hacke9e43bb2008-04-13 23:35:48 +0200623 tmp = []
624 tmp.append(item)
625 if tmp:
626 if fill_with is not None and len(tmp) < linecount:
627 tmp += [fill_with] * (linecount - len(tmp))
628 result.append(tmp)
629 return result
Armin Ronacherd071f952007-04-13 22:32:11 +0200630
631
Armin Ronachereec31382007-04-14 14:50:45 +0200632def do_sum():
633 """
634 Sum up the given sequence of numbers.
Armin Ronachera38b3122007-04-15 00:49:13 +0200635
636 *new in Jinja 1.1*
Armin Ronachereec31382007-04-14 14:50:45 +0200637 """
638 def wrapped(env, context, value):
639 return sum(value)
640 return wrapped
641
642
643def do_abs():
644 """
645 Return the absolute value of a number.
Armin Ronachera38b3122007-04-15 00:49:13 +0200646
647 *new in Jinja 1.1*
Armin Ronachereec31382007-04-14 14:50:45 +0200648 """
649 def wrapped(env, context, value):
650 return abs(value)
651 return wrapped
652
653
654def do_round(precision=0, method='common'):
655 """
656 Round the number to a given precision. The first
657 parameter specifies the precision (default is ``0``), the
658 second the rounding method:
659
660 - ``'common'`` rounds either up or down
661 - ``'ceil'`` always rounds up
662 - ``'floor'`` always rounds down
663
664 If you don't specify a method ``'common'`` is used.
665
666 .. sourcecode:: jinja
667
668 {{ 42.55|round }}
669 -> 43
670 {{ 42.55|round(1, 'floor') }}
671 -> 42.5
Armin Ronachera38b3122007-04-15 00:49:13 +0200672
673 *new in Jinja 1.1*
Armin Ronachereec31382007-04-14 14:50:45 +0200674 """
675 if not method in ('common', 'ceil', 'floor'):
676 raise FilterArgumentError('method must be common, ceil or floor')
677 if precision < 0:
678 raise FilterArgumentError('precision must be a postive integer '
679 'or zero.')
680 def wrapped(env, context, value):
681 if method == 'common':
682 return round(value, precision)
683 import math
684 func = getattr(math, method)
Armin Ronacher21580912007-04-17 17:13:10 +0200685 if precision:
686 return func(value * 10 * precision) / (10 * precision)
687 else:
688 return func(value)
Armin Ronachereec31382007-04-14 14:50:45 +0200689 return wrapped
690
691
Armin Ronacher9bcd4112007-05-29 14:17:24 +0200692def do_sort(reverse=False):
693 """
694 Sort a sequence. Per default it sorts ascending, if you pass it
695 `True` as first argument it will reverse the sorting.
696
697 *new in Jinja 1.1*
698 """
699 def wrapped(env, context, value):
700 return sorted(value, reverse=reverse)
701 return wrapped
702
703
Armin Ronachere39a5d22007-06-23 21:11:53 +0200704def do_groupby(attribute):
705 """
706 Group a sequence of objects by a common attribute.
707
708 If you for example have a list of dicts or objects that represent persons
709 with `gender`, `first_name` and `last_name` attributes and you want to
710 group all users by genders you can do something like the following
711 snippet:
712
713 .. sourcecode:: html+jinja
714
715 <ul>
716 {% for group in persons|groupby('gender') %}
717 <li>{{ group.grouper }}<ul>
718 {% for person in group.list %}
719 <li>{{ person.first_name }} {{ person.last_name }}</li>
720 {% endfor %}</ul></li>
721 {% endfor %}
722 </ul>
723
724 As you can see the item we're grouping by is stored in the `grouper`
725 attribute and the `list` contains all the objects that have this grouper
726 in common.
Armin Ronacher69ddc582007-06-24 12:37:13 +0200727
728 *New in Jinja 1.2*
Armin Ronachere39a5d22007-06-23 21:11:53 +0200729 """
730 def wrapped(env, context, value):
731 expr = lambda x: env.get_attribute(x, attribute)
Armin Ronacher30ffab12007-07-10 20:51:47 +0200732 return sorted([{
Armin Ronachere39a5d22007-06-23 21:11:53 +0200733 'grouper': a,
734 'list': list(b)
Armin Ronacher30ffab12007-07-10 20:51:47 +0200735 } for a, b in groupby(sorted(value, key=expr), expr)],
736 key=itemgetter('grouper'))
Armin Ronachere39a5d22007-06-23 21:11:53 +0200737 return wrapped
738
739
Armin Ronacher1cc232c2007-09-07 17:52:41 +0200740def do_getattribute(attribute):
741 """
742 Get one attribute from an object. Normally you don't have to use this
743 filter because the attribute and subscript expressions try to either
744 get an attribute of an object or an item. In some situations it could
745 be that there is an item *and* an attribute with the same name. In that
746 situation only the item is returned, never the attribute.
747
748 .. sourcecode:: jinja
749
750 {{ foo.bar }} -> {{ foo|getattribute('bar') }}
751
752 *New in Jinja 1.2*
753 """
754 def wrapped(env, context, value):
755 try:
756 return get_attribute(value, attribute)
757 except (SecurityException, AttributeError):
758 return env.undefined_singleton
759 return wrapped
760
761
762def do_getitem(key):
763 """
764 This filter basically works like the normal subscript expression but
765 it doesn't fall back to attribute lookup. If an item does not exist for
766 an object undefined is returned.
767
768 .. sourcecode:: jinja
769
770 {{ foo.bar }} -> {{ foo|getitem('bar') }}
771
772 *New in Jinja 1.2*
773 """
774 def wrapped(env, context, value):
775 try:
776 return value[key]
777 except (TypeError, KeyError, IndexError, AttributeError):
778 return env.undefined_singleton
779 return wrapped
780
781
Armin Ronacher92f572f2007-02-26 22:17:32 +0100782FILTERS = {
783 'replace': do_replace,
784 'upper': do_upper,
785 'lower': do_lower,
786 'escape': do_escape,
787 'e': do_escape,
Armin Ronacher450756b2007-04-15 15:13:59 +0200788 'xmlattr': do_xmlattr,
Armin Ronacher92f572f2007-02-26 22:17:32 +0100789 'capitalize': do_capitalize,
790 'title': do_title,
791 'default': do_default,
792 'join': do_join,
793 'count': do_count,
Armin Ronacher2b765132007-03-13 16:48:10 +0100794 'dictsort': do_dictsort,
Armin Ronacher68c87252007-03-06 17:35:54 +0100795 'length': do_count,
Armin Ronacherdbc945d2007-03-05 18:03:32 +0100796 'reverse': do_reverse,
Armin Ronacherfed86c12007-02-27 10:31:14 +0100797 'center': do_center,
798 'title': do_title,
799 'capitalize': do_capitalize,
800 'first': do_first,
801 'last': do_last,
802 'random': do_random,
Armin Ronacher2b765132007-03-13 16:48:10 +0100803 'jsonencode': do_jsonencode,
804 'filesizeformat': do_filesizeformat,
805 'pprint': do_pprint,
806 'indent': do_indent,
807 'truncate': do_truncate,
808 'wordwrap': do_wordwrap,
809 'wordcount': do_wordcount,
810 'textile': do_textile,
811 'markdown': do_markdown,
812 'rst': do_rst,
813 'int': do_int,
814 'float': do_float,
Tassilo Schweyer934cb712007-03-14 18:04:07 +0100815 'string': do_string,
Armin Ronacherf0f4deb2007-03-18 23:10:15 +0100816 'urlize': do_urlize,
817 'format': do_format,
Armin Ronacher49659872007-05-12 23:29:33 +0200818 'dformat': do_dformat,
Armin Ronacherd071f952007-04-13 22:32:11 +0200819 'trim': do_trim,
Georg Brandlaf31e4d2007-04-15 00:47:37 +0200820 'striptags': do_striptags,
Armin Ronacherd071f952007-04-13 22:32:11 +0200821 'slice': do_slice,
Armin Ronachereec31382007-04-14 14:50:45 +0200822 'batch': do_batch,
823 'sum': do_sum,
824 'abs': do_abs,
Armin Ronacher9bcd4112007-05-29 14:17:24 +0200825 'round': do_round,
Armin Ronachere39a5d22007-06-23 21:11:53 +0200826 'sort': do_sort,
Armin Ronacher1cc232c2007-09-07 17:52:41 +0200827 'groupby': do_groupby,
828 'getattribute': do_getattribute,
829 'getitem': do_getitem
Armin Ronacher92f572f2007-02-26 22:17:32 +0100830}