blob: 8b66ce807958f2ce5ff9c5ccc3d8029a005c75bb [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 Hackf4fdc722008-04-08 16:48:30 +020018from jinja.utils import escape
Armin Ronacherfed86c12007-02-27 10:31:14 +010019
20
Armin Ronachereaf493e2007-10-01 22:31:16 +020021_striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
Armin Ronacher9bcd4112007-05-29 14:17:24 +020022
23
Christoph Hack2751d942008-04-09 12:14:55 +020024def contextfilter(f):
Armin Ronacher92f572f2007-02-26 22:17:32 +010025 """
Christoph Hack2751d942008-04-09 12:14:55 +020026 Decorator for marking context dependent filters. The current context
27 argument will be passed as first argument.
Armin Ronacher92f572f2007-02-26 22:17:32 +010028 """
Christoph Hack2751d942008-04-09 12:14:55 +020029 f.contextfilter = True
30 return f
Armin Ronacher9bcd4112007-05-29 14:17:24 +020031
32
Armin Ronacher92f572f2007-02-26 22:17:32 +010033def do_replace(s, old, new, count=None):
34 """
Armin Ronacher37a88512007-03-02 20:42:18 +010035 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:
Armin Ronacher92f572f2007-02-26 22:17:32 +010040
Armin Ronacher37a88512007-03-02 20:42:18 +010041 .. sourcecode:: jinja
42
43 {{ "Hello World"|replace("Hello", "Goodbye") }}
44 -> Goodbye World
45
46 {{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
47 -> d'oh, d'oh, aaargh
Armin Ronacher92f572f2007-02-26 22:17:32 +010048 """
Armin Ronacher2b765132007-03-13 16:48:10 +010049 if not isinstance(old, basestring) or \
50 not isinstance(new, basestring):
Armin Ronacherae16fd02007-03-27 21:31:24 +020051 raise FilterArgumentError('the replace filter requires '
52 'string replacement arguments')
Armin Ronacher2da479f2007-04-02 10:50:18 +020053 if count is None:
54 return s.replace(old, new)
55 if not isinstance(count, (int, long)):
Armin Ronacherae16fd02007-03-27 21:31:24 +020056 raise FilterArgumentError('the count parameter of the '
57 'replace filter requires '
58 'an integer')
Armin Ronacher92f572f2007-02-26 22:17:32 +010059 return s.replace(old, new, count)
Armin Ronacher92f572f2007-02-26 22:17:32 +010060
61
62def do_upper(s):
63 """
Armin Ronacher37a88512007-03-02 20:42:18 +010064 Convert a value to uppercase.
Armin Ronacher92f572f2007-02-26 22:17:32 +010065 """
66 return s.upper()
Armin Ronacher92f572f2007-02-26 22:17:32 +010067
68
Christoph Hack2751d942008-04-09 12:14:55 +020069def do_lower(s):
Armin Ronacher92f572f2007-02-26 22:17:32 +010070 """
Armin Ronacher37a88512007-03-02 20:42:18 +010071 Convert a value to lowercase.
Armin Ronacher92f572f2007-02-26 22:17:32 +010072 """
73 return s.lower()
Armin Ronacher92f572f2007-02-26 22:17:32 +010074
75
Christoph Hack2751d942008-04-09 12:14:55 +020076def do_escape(s, attribute=False):
Armin Ronacher92f572f2007-02-26 22:17:32 +010077 """
Armin Ronacher37a88512007-03-02 20:42:18 +010078 XML escape ``&``, ``<``, and ``>`` in a string of data. If the
79 optional parameter is `true` this filter will also convert
80 ``"`` to ``&quot;``. This filter is just used if the environment
81 was configured with disabled `auto_escape`.
Armin Ronacher92f572f2007-02-26 22:17:32 +010082
Armin Ronacher37a88512007-03-02 20:42:18 +010083 This method will have no effect it the value is already escaped.
Armin Ronacher92f572f2007-02-26 22:17:32 +010084 """
Christoph Hackf4fdc722008-04-08 16:48:30 +020085 # XXX: Does this still exists?
86 #if isinstance(s, TemplateData):
87 # return s
88 if hasattr(s, '__html__'):
89 return s.__html__()
90 return escape(unicode(s), attribute)
Armin Ronacher92f572f2007-02-26 22:17:32 +010091
92
Christoph Hack2751d942008-04-09 12:14:55 +020093def do_xmlattr(d, autospace=False):
Armin Ronacher450756b2007-04-15 15:13:59 +020094 """
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
97 escaped:
98
Armin Ronacher8ca55df2007-04-15 15:16:08 +020099 .. sourcecode:: html+jinja
Armin Ronacher450756b2007-04-15 15:13:59 +0200100
Armin Ronacherc7ddd1d2007-04-28 15:56:27 +0200101 <ul{{ {'class': 'my_list', 'missing': None,
Armin Ronacherd459e272007-04-15 15:31:05 +0200102 'id': 'list-%d'|format(variable)}|xmlattr }}>
Armin Ronacher450756b2007-04-15 15:13:59 +0200103 ...
104 </ul>
105
106 Results in something like this:
107
Armin Ronacher8ca55df2007-04-15 15:16:08 +0200108 .. sourcecode:: html
109
Armin Ronacher450756b2007-04-15 15:13:59 +0200110 <ul class="my_list" id="list-42">
111 ...
112 </ul>
113
Armin Ronacher9bcd4112007-05-29 14:17:24 +0200114 As you can see it automatically prepends a space in front of the item
Armin Ronacherc7ddd1d2007-04-28 15:56:27 +0200115 if the filter returned something. You can disable this by passing
116 `false` as only argument to the filter.
117
Armin Ronacher450756b2007-04-15 15:13:59 +0200118 *New in Jinja 1.1*
119 """
Christoph Hack2751d942008-04-09 12:14:55 +0200120 if not hasattr(d, 'iteritems'):
121 raise TypeError('a dict is required')
122 result = []
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)
128 ))
129 rv = u' '.join(result)
130 if autospace:
131 rv = ' ' + rv
132 return rv
Armin Ronacher450756b2007-04-15 15:13:59 +0200133
134
Armin Ronacher92f572f2007-02-26 22:17:32 +0100135def do_capitalize(s):
136 """
Armin Ronacher37a88512007-03-02 20:42:18 +0100137 Capitalize a value. The first character will be uppercase, all others
138 lowercase.
Armin Ronacher92f572f2007-02-26 22:17:32 +0100139 """
Christoph Hack2751d942008-04-09 12:14:55 +0200140 return unicode(s).capitalize()
Armin Ronacher92f572f2007-02-26 22:17:32 +0100141
142
143def do_title(s):
144 """
Armin Ronacher37a88512007-03-02 20:42:18 +0100145 Return a titlecased version of the value. I.e. words will start with
146 uppercase letters, all remaining characters are lowercase.
Armin Ronacher92f572f2007-02-26 22:17:32 +0100147 """
Christoph Hack2751d942008-04-09 12:14:55 +0200148 return unicode(s).title()
Armin Ronacher92f572f2007-02-26 22:17:32 +0100149
150
Armin Ronacher2b765132007-03-13 16:48:10 +0100151def do_dictsort(case_sensitive=False, by='key'):
152 """
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
155 key or value:
156
157 .. sourcecode:: jinja
158
159 {% for item in mydict|dictsort %}
160 sort the dict by key, case insensitive
161
162 {% for item in mydict|dicsort(true) %}
163 sort the dict by key, case sensitive
164
165 {% for item in mydict|dictsort(false, 'value') %}
166 sort the dict by key, case insensitive, sorted
167 normally and ordered by value.
168 """
169 if by == 'key':
170 pos = 0
171 elif by == 'value':
172 pos = 1
173 else:
174 raise FilterArgumentError('You can only sort by either '
175 '"key" or "value"')
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()
181 return value
182
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)))
187 return items
188 return wrapped
189
190
Christoph Hack2751d942008-04-09 12:14:55 +0200191def do_default(value, default_value=u'', boolean=False):
Armin Ronacher92f572f2007-02-26 22:17:32 +0100192 """
Armin Ronacher37a88512007-03-02 20:42:18 +0100193 If the value is undefined it will return the passed default value,
194 otherwise the value of the variable:
Armin Ronacher92f572f2007-02-26 22:17:32 +0100195
Armin Ronacher37a88512007-03-02 20:42:18 +0100196 .. sourcecode:: jinja
197
198 {{ my_variable|default('my_variable is not defined') }}
199
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`:
204
205 .. sourcecode:: jinja
206
207 {{ ''|default('the string was empty', true) }}
Armin Ronacher92f572f2007-02-26 22:17:32 +0100208 """
Christoph Hack2751d942008-04-09 12:14:55 +0200209 # XXX: undefined_sigleton
210 if (boolean and not value) or value in (env.undefined_singleton, None):
211 return default_value
212 return value
Armin Ronacher92f572f2007-02-26 22:17:32 +0100213
214
Christoph Hack2751d942008-04-09 12:14:55 +0200215def do_join(value, d=u''):
Armin Ronacher92f572f2007-02-26 22:17:32 +0100216 """
Armin Ronacher92f572f2007-02-26 22:17:32 +0100217 Return a string which is the concatenation of the strings in the
Armin Ronacher37a88512007-03-02 20:42:18 +0100218 sequence. The separator between elements is an empty string per
219 default, you can define ith with the optional parameter:
220
221 .. sourcecode:: jinja
222
223 {{ [1, 2, 3]|join('|') }}
224 -> 1|2|3
225
226 {{ [1, 2, 3]|join }}
227 -> 123
Armin Ronacher92f572f2007-02-26 22:17:32 +0100228 """
Christoph Hack2751d942008-04-09 12:14:55 +0200229 return unicode(d).join([unicode(x) for x in value])
Armin Ronacher92f572f2007-02-26 22:17:32 +0100230
231
232def do_count():
233 """
Armin Ronacher37a88512007-03-02 20:42:18 +0100234 Return the length of the value. In case if getting an integer or float
Armin Ronacher92f572f2007-02-26 22:17:32 +0100235 it will convert it into a string an return the length of the new
Armin Ronacher37a88512007-03-02 20:42:18 +0100236 string. If the object has no length it will of corse return 0.
Armin Ronacher92f572f2007-02-26 22:17:32 +0100237 """
Christoph Hack2751d942008-04-09 12:14:55 +0200238 try:
239 if type(value) in (int, float, long):
240 return len(str(value))
241 return len(value)
242 except TypeError:
243 return 0
Armin Ronacher92f572f2007-02-26 22:17:32 +0100244
245
Christoph Hack2751d942008-04-09 12:14:55 +0200246def do_reverse(l):
Armin Ronacher92f572f2007-02-26 22:17:32 +0100247 """
Armin Ronacher37a88512007-03-02 20:42:18 +0100248 Return a reversed list of the sequence filtered. You can use this
249 for example for reverse iteration:
Armin Ronacher92f572f2007-02-26 22:17:32 +0100250
Armin Ronacher37a88512007-03-02 20:42:18 +0100251 .. sourcecode:: jinja
252
Armin Ronacherdbc945d2007-03-05 18:03:32 +0100253 {% for item in seq|reverse %}
Armin Ronacher37a88512007-03-02 20:42:18 +0100254 {{ item|e }}
255 {% endfor %}
Armin Ronacher92f572f2007-02-26 22:17:32 +0100256 """
Christoph Hack2751d942008-04-09 12:14:55 +0200257 try:
258 return value[::-1]
259 except:
260 l = list(value)
261 l.reverse()
262 return l
Armin Ronacher92f572f2007-02-26 22:17:32 +0100263
264
Armin Ronacherfed86c12007-02-27 10:31:14 +0100265def do_center(value, width=80):
266 """
Armin Ronacherfed86c12007-02-27 10:31:14 +0100267 Centers the value in a field of a given width.
268 """
Christoph Hack2751d942008-04-09 12:14:55 +0200269 return unicode(value).center(width)
Armin Ronacherfed86c12007-02-27 10:31:14 +0100270
271
Christoph Hack2751d942008-04-09 12:14:55 +0200272def do_first(seq):
Armin Ronacherfed86c12007-02-27 10:31:14 +0100273 """
Armin Ronacher37a88512007-03-02 20:42:18 +0100274 Return the frist item of a sequence.
Armin Ronacherfed86c12007-02-27 10:31:14 +0100275 """
Christoph Hack2751d942008-04-09 12:14:55 +0200276 try:
277 return iter(seq).next()
278 except StopIteration:
279 return env.undefined_singleton
Armin Ronacherfed86c12007-02-27 10:31:14 +0100280
281
Christoph Hack2751d942008-04-09 12:14:55 +0200282def do_last(seq):
Armin Ronacherfed86c12007-02-27 10:31:14 +0100283 """
Armin Ronacherfed86c12007-02-27 10:31:14 +0100284 Return the last item of a sequence.
285 """
Christoph Hack2751d942008-04-09 12:14:55 +0200286 try:
287 return iter(reversed(seq)).next()
288 except StopIteration:
289 return env.undefined_singleton
Armin Ronacherfed86c12007-02-27 10:31:14 +0100290
291
292def do_random():
293 """
Armin Ronacherfed86c12007-02-27 10:31:14 +0100294 Return a random item from the sequence.
295 """
Christoph Hack2751d942008-04-09 12:14:55 +0200296 try:
297 return choice(seq)
298 except IndexError:
299 return env.undefined_singleton
Armin Ronacherfed86c12007-02-27 10:31:14 +0100300
301
Christoph Hack2751d942008-04-09 12:14:55 +0200302def do_urlencode(value):
Armin Ronacherfed86c12007-02-27 10:31:14 +0100303 """
Armin Ronacherfed86c12007-02-27 10:31:14 +0100304 urlencode a string or directory.
Armin Ronacher37a88512007-03-02 20:42:18 +0100305
306 .. sourcecode:: jinja
307
308 {{ {'foo': 'bar', 'blub': 'blah'}|urlencode }}
309 -> foo=bar&blub=blah
310
311 {{ 'Hello World' }}
312 -> Hello%20World
Armin Ronacherfed86c12007-02-27 10:31:14 +0100313 """
Christoph Hack2751d942008-04-09 12:14:55 +0200314 if isinstance(value, dict):
315 tmp = {}
316 for key, value in value.iteritems():
317 # XXX env.charset?
318 key = unicode(key).encode(env.charset)
319 value = unicode(value).encode(env.charset)
320 tmp[key] = value
321 return urlencode(tmp)
322 else:
323 # XXX: env.charset?
324 return quote(unicode(value).encode(env.charset))
Armin Ronacherfed86c12007-02-27 10:31:14 +0100325
326
Christoph Hack2751d942008-04-09 12:14:55 +0200327def do_jsonencode(value):
Armin Ronacherfed86c12007-02-27 10:31:14 +0100328 """
Armin Ronacherfed86c12007-02-27 10:31:14 +0100329 JSON dump a variable. just works if simplejson is installed.
Armin Ronacher37a88512007-03-02 20:42:18 +0100330
331 .. sourcecode:: jinja
332
333 {{ 'Hello World'|jsonencode }}
334 -> "Hello World"
Armin Ronacherfed86c12007-02-27 10:31:14 +0100335 """
336 global simplejson
337 try:
338 simplejson
339 except NameError:
340 import simplejson
Christoph Hack2751d942008-04-09 12:14:55 +0200341 return simplejson.dumps(value)
Armin Ronacherfed86c12007-02-27 10:31:14 +0100342
343
Armin Ronacher2b765132007-03-13 16:48:10 +0100344def do_filesizeformat():
345 """
346 Format the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, 102
347 bytes, etc).
348 """
349 def wrapped(env, context, value):
350 # fail silently
351 try:
352 bytes = float(value)
353 except TypeError:
354 bytes = 0
355
356 if bytes < 1024:
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))
363 return wrapped
364
365
Christoph Hack2751d942008-04-09 12:14:55 +0200366def do_pprint(value, verbose=False):
Armin Ronacher2b765132007-03-13 16:48:10 +0100367 """
368 Pretty print a variable. Useful for debugging.
Armin Ronacherf2ce1262007-10-21 21:51:51 +0200369
370 With Jinja 1.2 onwards you can pass it a parameter. If this parameter
Armin Ronacher5f3f1362007-10-21 22:15:04 +0200371 is truthy the output will be more verbose (this requires `pretty`)
Armin Ronacher2b765132007-03-13 16:48:10 +0100372 """
Christoph Hack2751d942008-04-09 12:14:55 +0200373 return pformat(value, verbose=verbose)
Armin Ronacher2b765132007-03-13 16:48:10 +0100374
375
376def do_urlize(value, trim_url_limit=None, nofollow=False):
377 """
378 Converts URLs in plain text into clickable links.
379
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
382 "nofollow":
383
384 .. sourcecode:: jinja
385
386 {{ mytext|urlize(40, True) }}
387 links are shortened to 40 chars and defined with rel="nofollow"
388 """
Christoph Hack2751d942008-04-09 12:14:55 +0200389 return urlize(unicode(value), trim_url_limit, nofollow)
Armin Ronacher2b765132007-03-13 16:48:10 +0100390
391
392def do_indent(s, width=4, indentfirst=False):
393 """
394 {{ s|indent[ width[ indentfirst[ usetab]]] }}
395
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:
400
401 .. sourcecode:: jinja
402
403 {{ mytext|indent(2, True) }}
404 indent by two spaces and indent the first line too.
405 """
406 indention = ' ' * width
407 if indentfirst:
408 return u'\n'.join([indention + line for line in s.splitlines()])
409 return s.replace('\n', '\n' + indention)
Armin Ronacher2b765132007-03-13 16:48:10 +0100410
411
412def do_truncate(s, length=255, killwords=False, end='...'):
413 """
Armin Ronacher2b765132007-03-13 16:48:10 +0100414 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
420 third parameter.
421
422 .. sourcecode jinja::
423
424 {{ mytext|truncate(300, false, '&raquo;') }}
425 truncate mytext to 300 chars, don't split up words, use a
426 right pointing double arrow as ellipsis sign.
427 """
428 if len(s) <= length:
429 return s
430 elif killwords:
431 return s[:length] + end
432 words = s.split(' ')
433 result = []
434 m = 0
435 for word in words:
436 m += len(word) + 1
437 if m > length:
438 break
439 result.append(word)
440 result.append(end)
441 return u' '.join(result)
Armin Ronacher2b765132007-03-13 16:48:10 +0100442
443
444def do_wordwrap(s, pos=79, hard=False):
445 """
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
450 reading hard).
451 """
452 if len(s) < pos:
453 return s
454 if hard:
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)],
461 word), s.split(' '))
Armin Ronacher2b765132007-03-13 16:48:10 +0100462
463
464def do_wordcount(s):
465 """
466 Count the words in that string.
467 """
468 return len([x for x in s.split() if x])
Armin Ronacher2b765132007-03-13 16:48:10 +0100469
470
471def do_textile(s):
472 """
473 Prase the string using textile.
474
475 requires the `PyTextile`_ library.
476
477 .. _PyTextile: http://dealmeida.net/projects/textile/
478 """
479 from textile import textile
Armin Ronacher8712dad2007-06-08 01:07:48 +0200480 return textile(s.encode('utf-8')).decode('utf-8')
Armin Ronacher2b765132007-03-13 16:48:10 +0100481
482
483def do_markdown(s):
484 """
485 Parse the string using markdown.
486
487 requires the `Python-markdown`_ library.
488
489 .. _Python-markdown: http://www.freewisdom.org/projects/python-markdown/
490 """
491 from markdown import markdown
Armin Ronacher8712dad2007-06-08 01:07:48 +0200492 return markdown(s.encode('utf-8')).decode('utf-8')
Armin Ronacher2b765132007-03-13 16:48:10 +0100493
494
495def do_rst(s):
496 """
497 Parse the string using the reStructuredText parser from the
498 docutils package.
499
500 requires `docutils`_.
501
Georg Brandlfde3ff22007-07-18 09:27:01 +0200502 .. _docutils: http://docutils.sourceforge.net/
Armin Ronacher2b765132007-03-13 16:48:10 +0100503 """
Armin Ronacher8712dad2007-06-08 01:07:48 +0200504 from docutils.core import publish_parts
505 parts = publish_parts(source=s, writer_name='html4css1')
506 return parts['fragment']
Armin Ronacher2b765132007-03-13 16:48:10 +0100507
Armin Ronacherab45b842007-03-18 20:47:50 +0100508def do_int(default=0):
Armin Ronacher2b765132007-03-13 16:48:10 +0100509 """
Armin Ronacherab45b842007-03-18 20:47:50 +0100510 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.
Armin Ronacher2b765132007-03-13 16:48:10 +0100513 """
514 def wrapped(env, context, value):
Armin Ronacherab45b842007-03-18 20:47:50 +0100515 try:
516 return int(value)
517 except (TypeError, ValueError):
518 try:
519 return int(float(value))
520 except (TypeError, ValueError):
521 return default
Armin Ronacher2b765132007-03-13 16:48:10 +0100522 return wrapped
523
524
Armin Ronacherab45b842007-03-18 20:47:50 +0100525def do_float(default=0.0):
Armin Ronacher2b765132007-03-13 16:48:10 +0100526 """
Armin Ronacherab45b842007-03-18 20:47:50 +0100527 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.
Armin Ronacher2b765132007-03-13 16:48:10 +0100530 """
531 def wrapped(env, context, value):
Armin Ronacherab45b842007-03-18 20:47:50 +0100532 try:
533 return float(value)
534 except (TypeError, ValueError):
535 return default
Armin Ronacher2b765132007-03-13 16:48:10 +0100536 return wrapped
537
538
539def do_string():
540 """
541 Convert the value into an string.
542 """
543 return lambda e, c, v: e.to_unicode(v)
544
545
Armin Ronacherf0f4deb2007-03-18 23:10:15 +0100546def do_format(*args):
547 """
548 Apply python string formatting on an object:
549
550 .. sourcecode:: jinja
551
552 {{ "%s - %s"|format("Hello?", "Foo!") }}
553 -> Hello? - Foo!
554
555 Note that you cannot use the mapping syntax (``%(name)s``)
Armin Ronacher49659872007-05-12 23:29:33 +0200556 like in python. Use `|dformat` for that.
Armin Ronacherf0f4deb2007-03-18 23:10:15 +0100557 """
558 def wrapped(env, context, value):
559 return env.to_unicode(value) % args
560 return wrapped
561
562
Armin Ronacher49659872007-05-12 23:29:33 +0200563def do_dformat(d):
564 """
565 Apply python mapping string formatting on an object:
566
567 .. sourcecode:: jinja
568
569 {{ "Hello %(username)s!"|dformat({'username': 'John Doe'}) }}
570 -> Hello John Doe!
571
572 This is useful when adding variables to translateable
573 string expressions.
574
575 *New in Jinja 1.1*
576 """
577 if not isinstance(d, dict):
578 raise FilterArgumentError('dict required')
579 def wrapped(env, context, value):
580 return env.to_unicode(value) % d
581 return wrapped
582
583
Armin Ronacher566295e2007-03-19 13:19:34 +0100584def do_trim(value):
585 """
586 Strip leading and trailing whitespace.
587 """
588 return value.strip()
Armin Ronacher566295e2007-03-19 13:19:34 +0100589
590
591def do_capture(name='captured', clean=False):
Armin Ronacherf0f4deb2007-03-18 23:10:15 +0100592 """
593 Store the value in a variable called ``captured`` or a variable
594 with the name provided. Useful for filter blocks:
595
596 .. sourcecode:: jinja
597
598 {% filter capture('foo') %}
Armin Ronacher566295e2007-03-19 13:19:34 +0100599 ...
600 {% endfilter %}
601 {{ foo }}
602
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:
606
607 .. sourcecode:: jinja
608
609 {% filter capture('foo', True) %}
610 ...
Armin Ronacherf0f4deb2007-03-18 23:10:15 +0100611 {% endfilter %}
612 {{ foo }}
613 """
Armin Ronacher954153b2007-04-01 12:07:21 +0200614 if not isinstance(name, basestring):
Armin Ronacher566295e2007-03-19 13:19:34 +0100615 raise FilterArgumentError('You can only capture into variables')
Armin Ronacher0b666572007-03-18 23:15:23 +0100616 def wrapped(env, context, value):
617 context[name] = value
Armin Ronacher566295e2007-03-19 13:19:34 +0100618 if clean:
Armin Ronacherfb5bebc2007-04-27 18:24:19 +0200619 return TemplateData()
Armin Ronacher0b666572007-03-18 23:15:23 +0100620 return value
621 return wrapped
Armin Ronacherf0f4deb2007-03-18 23:10:15 +0100622
623
Armin Ronacher9bcd4112007-05-29 14:17:24 +0200624def do_striptags(value):
Georg Brandlaf31e4d2007-04-15 00:47:37 +0200625 """
626 Strip SGML/XML tags and replace adjacent whitespace by one space.
Armin Ronacher21580912007-04-17 17:13:10 +0200627
Georg Brandlaf31e4d2007-04-15 00:47:37 +0200628 *new in Jinja 1.1*
629 """
Armin Ronacher9bcd4112007-05-29 14:17:24 +0200630 return ' '.join(_striptags_re.sub('', value).split())
Georg Brandlaf31e4d2007-04-15 00:47:37 +0200631
632
Armin Ronacherd071f952007-04-13 22:32:11 +0200633def do_slice(slices, fill_with=None):
634 """
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:
638
Armin Ronacher89376072007-04-13 22:34:35 +0200639 .. sourcecode:: html+jinja
Armin Ronacherd071f952007-04-13 22:32:11 +0200640
641 <div class="columwrapper">
642 {%- for column in items|slice(3) %}
643 <ul class="column-{{ loop.index }}">
644 {%- for item in column %}
645 <li>{{ item }}</li>
646 {%- endfor %}
647 </ul>
648 {%- endfor %}
649 </div>
650
Armin Ronachereec31382007-04-14 14:50:45 +0200651 If you pass it a second argument it's used to fill missing
652 values on the last iteration.
653
654 *new in Jinja 1.1*
Armin Ronacherd071f952007-04-13 22:32:11 +0200655 """
656 def wrapped(env, context, value):
657 result = []
658 seq = list(value)
659 length = len(seq)
660 items_per_slice = length // slices
661 slices_with_extra = length % slices
662 offset = 0
663 for slice_number in xrange(slices):
664 start = offset + slice_number * items_per_slice
665 if slice_number < slices_with_extra:
666 offset += 1
667 end = offset + (slice_number + 1) * items_per_slice
668 tmp = seq[start:end]
669 if fill_with is not None and slice_number >= slices_with_extra:
670 tmp.append(fill_with)
671 result.append(tmp)
672 return result
673 return wrapped
674
675
676def do_batch(linecount, fill_with=None):
677 """
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:
682
Armin Ronacher89376072007-04-13 22:34:35 +0200683 .. sourcecode:: html+jinja
Armin Ronacherd071f952007-04-13 22:32:11 +0200684
685 <table>
686 {%- for row in items|batch(3, '&nbsp;') %}
687 <tr>
688 {%- for column in row %}
689 <tr>{{ column }}</td>
690 {%- endfor %}
691 </tr>
692 {%- endfor %}
693 </table>
694
Armin Ronachereec31382007-04-14 14:50:45 +0200695 *new in Jinja 1.1*
Armin Ronacherd071f952007-04-13 22:32:11 +0200696 """
697 def wrapped(env, context, value):
698 result = []
699 tmp = []
700 for item in value:
701 if len(tmp) == linecount:
702 result.append(tmp)
703 tmp = []
704 tmp.append(item)
705 if tmp:
706 if fill_with is not None and len(tmp) < linecount:
707 tmp += [fill_with] * (linecount - len(tmp))
708 result.append(tmp)
709 return result
710 return wrapped
711
712
Armin Ronachereec31382007-04-14 14:50:45 +0200713def do_sum():
714 """
715 Sum up the given sequence of numbers.
Armin Ronachera38b3122007-04-15 00:49:13 +0200716
717 *new in Jinja 1.1*
Armin Ronachereec31382007-04-14 14:50:45 +0200718 """
719 def wrapped(env, context, value):
720 return sum(value)
721 return wrapped
722
723
724def do_abs():
725 """
726 Return the absolute value of a number.
Armin Ronachera38b3122007-04-15 00:49:13 +0200727
728 *new in Jinja 1.1*
Armin Ronachereec31382007-04-14 14:50:45 +0200729 """
730 def wrapped(env, context, value):
731 return abs(value)
732 return wrapped
733
734
735def do_round(precision=0, method='common'):
736 """
737 Round the number to a given precision. The first
738 parameter specifies the precision (default is ``0``), the
739 second the rounding method:
740
741 - ``'common'`` rounds either up or down
742 - ``'ceil'`` always rounds up
743 - ``'floor'`` always rounds down
744
745 If you don't specify a method ``'common'`` is used.
746
747 .. sourcecode:: jinja
748
749 {{ 42.55|round }}
750 -> 43
751 {{ 42.55|round(1, 'floor') }}
752 -> 42.5
Armin Ronachera38b3122007-04-15 00:49:13 +0200753
754 *new in Jinja 1.1*
Armin Ronachereec31382007-04-14 14:50:45 +0200755 """
756 if not method in ('common', 'ceil', 'floor'):
757 raise FilterArgumentError('method must be common, ceil or floor')
758 if precision < 0:
759 raise FilterArgumentError('precision must be a postive integer '
760 'or zero.')
761 def wrapped(env, context, value):
762 if method == 'common':
763 return round(value, precision)
764 import math
765 func = getattr(math, method)
Armin Ronacher21580912007-04-17 17:13:10 +0200766 if precision:
767 return func(value * 10 * precision) / (10 * precision)
768 else:
769 return func(value)
Armin Ronachereec31382007-04-14 14:50:45 +0200770 return wrapped
771
772
Armin Ronacher9bcd4112007-05-29 14:17:24 +0200773def do_sort(reverse=False):
774 """
775 Sort a sequence. Per default it sorts ascending, if you pass it
776 `True` as first argument it will reverse the sorting.
777
778 *new in Jinja 1.1*
779 """
780 def wrapped(env, context, value):
781 return sorted(value, reverse=reverse)
782 return wrapped
783
784
Armin Ronachere39a5d22007-06-23 21:11:53 +0200785def do_groupby(attribute):
786 """
787 Group a sequence of objects by a common attribute.
788
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
792 snippet:
793
794 .. sourcecode:: html+jinja
795
796 <ul>
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>
802 {% endfor %}
803 </ul>
804
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
807 in common.
Armin Ronacher69ddc582007-06-24 12:37:13 +0200808
809 *New in Jinja 1.2*
Armin Ronachere39a5d22007-06-23 21:11:53 +0200810 """
811 def wrapped(env, context, value):
812 expr = lambda x: env.get_attribute(x, attribute)
Armin Ronacher30ffab12007-07-10 20:51:47 +0200813 return sorted([{
Armin Ronachere39a5d22007-06-23 21:11:53 +0200814 'grouper': a,
815 'list': list(b)
Armin Ronacher30ffab12007-07-10 20:51:47 +0200816 } for a, b in groupby(sorted(value, key=expr), expr)],
817 key=itemgetter('grouper'))
Armin Ronachere39a5d22007-06-23 21:11:53 +0200818 return wrapped
819
820
Armin Ronacher1cc232c2007-09-07 17:52:41 +0200821def do_getattribute(attribute):
822 """
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.
828
829 .. sourcecode:: jinja
830
831 {{ foo.bar }} -> {{ foo|getattribute('bar') }}
832
833 *New in Jinja 1.2*
834 """
835 def wrapped(env, context, value):
836 try:
837 return get_attribute(value, attribute)
838 except (SecurityException, AttributeError):
839 return env.undefined_singleton
840 return wrapped
841
842
843def do_getitem(key):
844 """
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.
848
849 .. sourcecode:: jinja
850
851 {{ foo.bar }} -> {{ foo|getitem('bar') }}
852
853 *New in Jinja 1.2*
854 """
855 def wrapped(env, context, value):
856 try:
857 return value[key]
858 except (TypeError, KeyError, IndexError, AttributeError):
859 return env.undefined_singleton
860 return wrapped
861
862
Armin Ronacher92f572f2007-02-26 22:17:32 +0100863FILTERS = {
864 'replace': do_replace,
865 'upper': do_upper,
866 'lower': do_lower,
867 'escape': do_escape,
868 'e': do_escape,
Armin Ronacher450756b2007-04-15 15:13:59 +0200869 'xmlattr': do_xmlattr,
Armin Ronacher92f572f2007-02-26 22:17:32 +0100870 'capitalize': do_capitalize,
871 'title': do_title,
872 'default': do_default,
873 'join': do_join,
874 'count': do_count,
Armin Ronacher2b765132007-03-13 16:48:10 +0100875 'dictsort': do_dictsort,
Armin Ronacher68c87252007-03-06 17:35:54 +0100876 'length': do_count,
Armin Ronacherdbc945d2007-03-05 18:03:32 +0100877 'reverse': do_reverse,
Armin Ronacherfed86c12007-02-27 10:31:14 +0100878 'center': do_center,
879 'title': do_title,
880 'capitalize': do_capitalize,
881 'first': do_first,
882 'last': do_last,
883 'random': do_random,
884 'urlencode': do_urlencode,
Armin Ronacher2b765132007-03-13 16:48:10 +0100885 'jsonencode': do_jsonencode,
886 'filesizeformat': do_filesizeformat,
887 'pprint': do_pprint,
888 'indent': do_indent,
889 'truncate': do_truncate,
890 'wordwrap': do_wordwrap,
891 'wordcount': do_wordcount,
892 'textile': do_textile,
893 'markdown': do_markdown,
894 'rst': do_rst,
895 'int': do_int,
896 'float': do_float,
Tassilo Schweyer934cb712007-03-14 18:04:07 +0100897 'string': do_string,
Armin Ronacherf0f4deb2007-03-18 23:10:15 +0100898 'urlize': do_urlize,
899 'format': do_format,
Armin Ronacher49659872007-05-12 23:29:33 +0200900 'dformat': do_dformat,
Armin Ronacher566295e2007-03-19 13:19:34 +0100901 'capture': do_capture,
Armin Ronacherd071f952007-04-13 22:32:11 +0200902 'trim': do_trim,
Georg Brandlaf31e4d2007-04-15 00:47:37 +0200903 'striptags': do_striptags,
Armin Ronacherd071f952007-04-13 22:32:11 +0200904 'slice': do_slice,
Armin Ronachereec31382007-04-14 14:50:45 +0200905 'batch': do_batch,
906 'sum': do_sum,
907 'abs': do_abs,
Armin Ronacher9bcd4112007-05-29 14:17:24 +0200908 'round': do_round,
Armin Ronachere39a5d22007-06-23 21:11:53 +0200909 'sort': do_sort,
Armin Ronacher1cc232c2007-09-07 17:52:41 +0200910 'groupby': do_groupby,
911 'getattribute': do_getattribute,
912 'getitem': do_getitem
Armin Ronacher92f572f2007-02-26 22:17:32 +0100913}