1 # -*- coding: utf-8 -*-
8 :copyright: 2007 by Armin Ronacher.
9 :license: BSD, see LICENSE for more details.
11 from random import choice
12 from urllib import urlencode, quote
13 from jinja.utils import escape, urlize
14 from jinja.datastructure import Undefined
15 from jinja.exceptions import FilterArgumentError
21 # python2.3 compatibility hack for the do_reverse function
27 return list(seq)[::-1]
29 raise TypeError('argument to _reversed must '
35 Decorator for filters that just work on unicode objects.
38 def wrapped(env, context, value):
40 for idx, var in enumerate(nargs):
41 if isinstance(var, str):
42 nargs[idx] = env.to_unicode(var)
43 return f(env.to_unicode(value), *nargs)
46 decorator.__doc__ = f.__doc__
47 decorator.__name__ = f.__name__
53 def do_replace(s, old, new, count=None):
55 Return a copy of the value with all occurrences of a substring
56 replaced with a new one. The first argument is the substring
57 that should be replaced, the second is the replacement string.
58 If the optional third argument ``count`` is given, only the first
59 ``count`` occurrences are replaced:
63 {{ "Hello World"|replace("Hello", "Goodbye") }}
66 {{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
69 if not isinstance(old, basestring) or \
70 not isinstance(new, basestring):
71 raise FilterArgumentException('the replace filter requires '
72 'string replacement arguments')
73 elif not isinstance(count, (int, long)):
74 raise FilterArgumentException('the count parameter of the '
75 'replace filter requires '
78 return s.replace(old, new)
79 return s.replace(old, new, count)
80 do_replace = stringfilter(do_replace)
85 Convert a value to uppercase.
88 do_upper = stringfilter(do_upper)
93 Convert a value to lowercase.
96 do_lower = stringfilter(do_lower)
99 def do_escape(s, attribute=False):
101 XML escape ``&``, ``<``, and ``>`` in a string of data. If the
102 optional parameter is `true` this filter will also convert
103 ``"`` to ``"``. This filter is just used if the environment
104 was configured with disabled `auto_escape`.
106 This method will have no effect it the value is already escaped.
108 return escape(s, attribute)
109 do_escape = stringfilter(do_escape)
112 def do_capitalize(s):
114 Capitalize a value. The first character will be uppercase, all others
117 return s.capitalize()
118 do_capitalize = stringfilter(do_capitalize)
123 Return a titlecased version of the value. I.e. words will start with
124 uppercase letters, all remaining characters are lowercase.
127 do_title = stringfilter(do_title)
130 def do_dictsort(case_sensitive=False, by='key'):
132 Sort a dict and yield (key, value) pairs. Because python dicts are
133 unsorted you may want to use this function to order them by either
136 .. sourcecode:: jinja
138 {% for item in mydict|dictsort %}
139 sort the dict by key, case insensitive
141 {% for item in mydict|dicsort(true) %}
142 sort the dict by key, case sensitive
144 {% for item in mydict|dictsort(false, 'value') %}
145 sort the dict by key, case insensitive, sorted
146 normally and ordered by value.
153 raise FilterArgumentError('You can only sort by either '
155 def sort_func(value, env):
156 if isinstance(value, basestring):
157 value = env.to_unicode(value)
158 if not case_sensitive:
159 value = value.lower()
162 def wrapped(env, context, value):
163 items = value.items()
164 items.sort(lambda a, b: cmp(sort_func(a[pos], env),
165 sort_func(b[pos], env)))
170 def do_default(default_value=u'', boolean=False):
172 If the value is undefined it will return the passed default value,
173 otherwise the value of the variable:
175 .. sourcecode:: jinja
177 {{ my_variable|default('my_variable is not defined') }}
179 This will output the value of ``my_variable`` if the variable was
180 defined, otherwise ``'my_variable is not defined'``. If you want
181 to use default with variables that evaluate to false you have to
182 set the second parameter to `true`:
184 .. sourcecode:: jinja
186 {{ ''|default('the string was empty', true) }}
188 def wrapped(env, context, value):
189 if (boolean and not value) or value in (Undefined, None):
197 Return a string which is the concatenation of the strings in the
198 sequence. The separator between elements is an empty string per
199 default, you can define ith with the optional parameter:
201 .. sourcecode:: jinja
203 {{ [1, 2, 3]|join('|') }}
209 def wrapped(env, context, value):
210 return env.to_unicode(d).join([env.to_unicode(x) for x in value])
216 Return the length of the value. In case if getting an integer or float
217 it will convert it into a string an return the length of the new
218 string. If the object has no length it will of corse return 0.
220 def wrapped(env, context, value):
222 if type(value) in (int, float, long):
223 return len(str(value))
232 Return a reversed list of the sequence filtered. You can use this
233 for example for reverse iteration:
235 .. sourcecode:: jinja
237 {% for item in seq|reverse %}
241 def wrapped(env, context, value):
251 def do_center(value, width=80):
253 Centers the value in a field of a given width.
255 return value.center(width)
256 do_center = stringfilter(do_center)
261 Return the frist item of a sequence.
263 def wrapped(env, context, seq):
265 return iter(seq).next()
266 except StopIteration:
273 Return the last item of a sequence.
275 def wrapped(env, context, seq):
277 return iter(_reversed(seq)).next()
278 except (TypeError, StopIteration):
285 Return a random item from the sequence.
287 def wrapped(env, context, seq):
297 urlencode a string or directory.
299 .. sourcecode:: jinja
301 {{ {'foo': 'bar', 'blub': 'blah'}|urlencode }}
307 def wrapped(env, context, value):
308 if isinstance(value, dict):
310 for key, value in value.iteritems():
311 tmp[env.to_unicode(key)] = env.to_unicode(value)
312 return urlencode(tmp)
314 return quote(env.to_unicode(value))
320 JSON dump a variable. just works if simplejson is installed.
322 .. sourcecode:: jinja
324 {{ 'Hello World'|jsonencode }}
332 return lambda e, c, v: simplejson.dumps(v)
335 def do_filesizeformat():
337 Format the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, 102
340 def wrapped(env, context, value):
348 return "%d Byte%s" % (bytes, bytes != 1 and 's' or '')
349 elif bytes < 1024 * 1024:
350 return "%.1f KB" % (bytes / 1024)
351 elif bytes < 1024 * 1024 * 1024:
352 return "%.1f MB" % (bytes / (1024 * 1024))
353 return "%.1f GB" % (bytes / (1024 * 1024 * 1024))
359 Pretty print a variable. Useful for debugging.
361 def wrapped(env, context, value):
362 from pprint import pformat
363 return pformat(value)
367 def do_urlize(value, trim_url_limit=None, nofollow=False):
369 Converts URLs in plain text into clickable links.
371 If you pass the filter an additional integer it will shorten the urls
372 to that number. Also a third argument exists that makes the urls
375 .. sourcecode:: jinja
377 {{ mytext|urlize(40, True) }}
378 links are shortened to 40 chars and defined with rel="nofollow"
380 return urlize(value, trim_url_limit, nofollow)
381 do_urlize = stringfilter(do_urlize)
384 def do_indent(s, width=4, indentfirst=False):
386 {{ s|indent[ width[ indentfirst[ usetab]]] }}
388 Return a copy of the passed string, each line indented by
389 4 spaces. The first line is not indented. If you want to
390 change the number of spaces or indent the first line too
391 you can pass additional parameters to the filter:
393 .. sourcecode:: jinja
395 {{ mytext|indent(2, True) }}
396 indent by two spaces and indent the first line too.
398 indention = ' ' * width
400 return u'\n'.join([indention + line for line in s.splitlines()])
401 return s.replace('\n', '\n' + indention)
402 do_indent = stringfilter(do_indent)
405 def do_truncate(s, length=255, killwords=False, end='...'):
407 Return a truncated copy of the string. The length is specified
408 with the first parameter which defaults to ``255``. If the second
409 parameter is ``true`` the filter will cut the text at length. Otherwise
410 it will try to save the last word. If the text was in fact
411 truncated it will append an ellipsis sign (``"..."``). If you want a
412 different ellipsis sign than ``"..."`` you can specify it using the
415 .. sourcecode jinja::
417 {{ mytext|truncate(300, false, '»') }}
418 truncate mytext to 300 chars, don't split up words, use a
419 right pointing double arrow as ellipsis sign.
424 return s[:length] + end
434 return u' '.join(result)
435 do_truncate = stringfilter(do_truncate)
438 def do_wordwrap(s, pos=79, hard=False):
440 Return a copy of the string passed to the filter wrapped after
441 ``79`` characters. You can override this default using the first
442 parameter. If you set the second parameter to `true` Jinja will
443 also split words apart (usually a bad idea because it makes
449 return u'\n'.join([s[idx:idx + pos] for idx in
450 xrange(0, len(s), pos)])
451 # code from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/148061
452 return reduce(lambda line, word, pos=pos: u'%s%s%s' %
453 (line, u' \n'[(len(line)-line.rfind('\n') - 1 +
454 len(word.split('\n', 1)[0]) >= pos)],
456 do_wordwrap = stringfilter(do_wordwrap)
461 Count the words in that string.
463 return len([x for x in s.split() if x])
464 do_wordcount = stringfilter(do_wordcount)
469 Prase the string using textile.
471 requires the `PyTextile`_ library.
473 .. _PyTextile: http://dealmeida.net/projects/textile/
475 from textile import textile
477 do_textile = stringfilter(do_textile)
482 Parse the string using markdown.
484 requires the `Python-markdown`_ library.
486 .. _Python-markdown: http://www.freewisdom.org/projects/python-markdown/
488 from markdown import markdown
490 do_markdown = stringfilter(do_markdown)
495 Parse the string using the reStructuredText parser from the
498 requires `docutils`_.
500 .. _docutils: from http://docutils.sourceforge.net/
503 from docutils.core import publish_parts
504 parts = publish_parts(source=s, writer_name='html4css1')
505 return parts['fragment']
508 do_rst = stringfilter(do_rst)
511 def do_int(default=0):
513 Convert the value into an integer. If the
514 conversion doesn't work it will return ``0``. You can
515 override this default using the first parameter.
517 def wrapped(env, context, value):
520 except (TypeError, ValueError):
522 return int(float(value))
523 except (TypeError, ValueError):
528 def do_float(default=0.0):
530 Convert the value into a floating point number. If the
531 conversion doesn't work it will return ``0.0``. You can
532 override this default using the first parameter.
534 def wrapped(env, context, value):
537 except (TypeError, ValueError):
544 Convert the value into an string.
546 return lambda e, c, v: e.to_unicode(v)
549 def do_format(*args):
551 Apply python string formatting on an object:
553 .. sourcecode:: jinja
555 {{ "%s - %s"|format("Hello?", "Foo!") }}
558 Note that you cannot use the mapping syntax (``%(name)s``)
561 def wrapped(env, context, value):
562 return env.to_unicode(value) % args
568 Strip leading and trailing whitespace.
571 do_trim = stringfilter(do_trim)
574 def do_capture(name='captured', clean=False):
576 Store the value in a variable called ``captured`` or a variable
577 with the name provided. Useful for filter blocks:
579 .. sourcecode:: jinja
581 {% filter capture('foo') %}
586 This will output "..." two times. One time from the filter block
587 and one time from the variable. If you don't want the filter to
588 output something you can use it in `clean` mode:
590 .. sourcecode:: jinja
592 {% filter capture('foo', True) %}
597 if not isinstance(name, unicode):
598 raise FilterArgumentError('You can only capture into variables')
599 def wrapped(env, context, value):
600 context[name] = value
608 'replace': do_replace,
613 'capitalize': do_capitalize,
615 'default': do_default,
618 'dictsort': do_dictsort,
620 'reverse': do_reverse,
623 'capitalize': do_capitalize,
627 'urlencode': do_urlencode,
628 'jsonencode': do_jsonencode,
629 'filesizeformat': do_filesizeformat,
632 'truncate': do_truncate,
633 'wordwrap': do_wordwrap,
634 'wordcount': do_wordcount,
635 'textile': do_textile,
636 'markdown': do_markdown,
643 'capture': do_capture,