Reworked implementation of the urlescape filter, made it Python3 compatible, document...
[jinja2.git] / jinja2 / filters.py
1 # -*- coding: utf-8 -*-
2 """
3     jinja2.filters
4     ~~~~~~~~~~~~~~
5
6     Bundled jinja filters.
7
8     :copyright: (c) 2010 by the Jinja Team.
9     :license: BSD, see LICENSE for more details.
10 """
11 import re
12 import math
13 from random import choice
14 from operator import itemgetter
15 from itertools import imap, groupby
16 from jinja2.utils import Markup, escape, pformat, urlize, soft_unicode, \
17      unicode_urlescape
18 from jinja2.runtime import Undefined
19 from jinja2.exceptions import FilterArgumentError
20
21
22 _word_re = re.compile(r'\w+(?u)')
23
24
25 def contextfilter(f):
26     """Decorator for marking context dependent filters. The current
27     :class:`Context` will be passed as first argument.
28     """
29     f.contextfilter = True
30     return f
31
32
33 def evalcontextfilter(f):
34     """Decorator for marking eval-context dependent filters.  An eval
35     context object is passed as first argument.  For more information
36     about the eval context, see :ref:`eval-context`.
37
38     .. versionadded:: 2.4
39     """
40     f.evalcontextfilter = True
41     return f
42
43
44 def environmentfilter(f):
45     """Decorator for marking evironment dependent filters.  The current
46     :class:`Environment` is passed to the filter as first argument.
47     """
48     f.environmentfilter = True
49     return f
50
51
52 def make_attrgetter(environment, attribute):
53     """Returns a callable that looks up the given attribute from a
54     passed object with the rules of the environment.  Dots are allowed
55     to access attributes of attributes.
56     """
57     if not isinstance(attribute, basestring) or '.' not in attribute:
58         return lambda x: environment.getitem(x, attribute)
59     attribute = attribute.split('.')
60     def attrgetter(item):
61         for part in attribute:
62             item = environment.getitem(item, part)
63         return item
64     return attrgetter
65
66
67 def do_forceescape(value):
68     """Enforce HTML escaping.  This will probably double escape variables."""
69     if hasattr(value, '__html__'):
70         value = value.__html__()
71     return escape(unicode(value))
72
73
74 def do_urlescape(value):
75     """Escape strings for use in URLs (uses UTF-8 encoding).  It accepts both
76     dictionaries and regular strings as well as pairwise iterables.
77
78     .. versionadded:: 2.7
79     """
80     itemiter = None
81     if isinstance(value, dict):
82         itemiter = value.iteritems()
83     elif not isinstance(value, basestring):
84         try:
85             itemiter = iter(value)
86         except TypeError:
87             pass
88     if itemiter is None:
89         return unicode_urlescape(value)
90     return u'&'.join(unicode_urlescape(k) + '=' +
91                      unicode_urlescape(v) for k, v in itemiter)
92
93
94 @evalcontextfilter
95 def do_replace(eval_ctx, s, old, new, count=None):
96     """Return a copy of the value with all occurrences of a substring
97     replaced with a new one. The first argument is the substring
98     that should be replaced, the second is the replacement string.
99     If the optional third argument ``count`` is given, only the first
100     ``count`` occurrences are replaced:
101
102     .. sourcecode:: jinja
103
104         {{ "Hello World"|replace("Hello", "Goodbye") }}
105             -> Goodbye World
106
107         {{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
108             -> d'oh, d'oh, aaargh
109     """
110     if count is None:
111         count = -1
112     if not eval_ctx.autoescape:
113         return unicode(s).replace(unicode(old), unicode(new), count)
114     if hasattr(old, '__html__') or hasattr(new, '__html__') and \
115        not hasattr(s, '__html__'):
116         s = escape(s)
117     else:
118         s = soft_unicode(s)
119     return s.replace(soft_unicode(old), soft_unicode(new), count)
120
121
122 def do_upper(s):
123     """Convert a value to uppercase."""
124     return soft_unicode(s).upper()
125
126
127 def do_lower(s):
128     """Convert a value to lowercase."""
129     return soft_unicode(s).lower()
130
131
132 @evalcontextfilter
133 def do_xmlattr(_eval_ctx, d, autospace=True):
134     """Create an SGML/XML attribute string based on the items in a dict.
135     All values that are neither `none` nor `undefined` are automatically
136     escaped:
137
138     .. sourcecode:: html+jinja
139
140         <ul{{ {'class': 'my_list', 'missing': none,
141                 'id': 'list-%d'|format(variable)}|xmlattr }}>
142         ...
143         </ul>
144
145     Results in something like this:
146
147     .. sourcecode:: html
148
149         <ul class="my_list" id="list-42">
150         ...
151         </ul>
152
153     As you can see it automatically prepends a space in front of the item
154     if the filter returned something unless the second parameter is false.
155     """
156     rv = u' '.join(
157         u'%s="%s"' % (escape(key), escape(value))
158         for key, value in d.iteritems()
159         if value is not None and not isinstance(value, Undefined)
160     )
161     if autospace and rv:
162         rv = u' ' + rv
163     if _eval_ctx.autoescape:
164         rv = Markup(rv)
165     return rv
166
167
168 def do_capitalize(s):
169     """Capitalize a value. The first character will be uppercase, all others
170     lowercase.
171     """
172     return soft_unicode(s).capitalize()
173
174
175 def do_title(s):
176     """Return a titlecased version of the value. I.e. words will start with
177     uppercase letters, all remaining characters are lowercase.
178     """
179     return soft_unicode(s).title()
180
181
182 def do_dictsort(value, case_sensitive=False, by='key'):
183     """Sort a dict and yield (key, value) pairs. Because python dicts are
184     unsorted you may want to use this function to order them by either
185     key or value:
186
187     .. sourcecode:: jinja
188
189         {% for item in mydict|dictsort %}
190             sort the dict by key, case insensitive
191
192         {% for item in mydict|dicsort(true) %}
193             sort the dict by key, case sensitive
194
195         {% for item in mydict|dictsort(false, 'value') %}
196             sort the dict by key, case insensitive, sorted
197             normally and ordered by value.
198     """
199     if by == 'key':
200         pos = 0
201     elif by == 'value':
202         pos = 1
203     else:
204         raise FilterArgumentError('You can only sort by either '
205                                   '"key" or "value"')
206     def sort_func(item):
207         value = item[pos]
208         if isinstance(value, basestring) and not case_sensitive:
209             value = value.lower()
210         return value
211
212     return sorted(value.items(), key=sort_func)
213
214
215 @environmentfilter
216 def do_sort(environment, value, reverse=False, case_sensitive=False,
217             attribute=None):
218     """Sort an iterable.  Per default it sorts ascending, if you pass it
219     true as first argument it will reverse the sorting.
220
221     If the iterable is made of strings the third parameter can be used to
222     control the case sensitiveness of the comparison which is disabled by
223     default.
224
225     .. sourcecode:: jinja
226
227         {% for item in iterable|sort %}
228             ...
229         {% endfor %}
230
231     It is also possible to sort by an attribute (for example to sort
232     by the date of an object) by specifying the `attribute` parameter:
233
234     .. sourcecode:: jinja
235
236         {% for item in iterable|sort(attribute='date') %}
237             ...
238         {% endfor %}
239
240     .. versionchanged:: 2.6
241        The `attribute` parameter was added.
242     """
243     if not case_sensitive:
244         def sort_func(item):
245             if isinstance(item, basestring):
246                 item = item.lower()
247             return item
248     else:
249         sort_func = None
250     if attribute is not None:
251         getter = make_attrgetter(environment, attribute)
252         def sort_func(item, processor=sort_func or (lambda x: x)):
253             return processor(getter(item))
254     return sorted(value, key=sort_func, reverse=reverse)
255
256
257 def do_default(value, default_value=u'', boolean=False):
258     """If the value is undefined it will return the passed default value,
259     otherwise the value of the variable:
260
261     .. sourcecode:: jinja
262
263         {{ my_variable|default('my_variable is not defined') }}
264
265     This will output the value of ``my_variable`` if the variable was
266     defined, otherwise ``'my_variable is not defined'``. If you want
267     to use default with variables that evaluate to false you have to
268     set the second parameter to `true`:
269
270     .. sourcecode:: jinja
271
272         {{ ''|default('the string was empty', true) }}
273     """
274     if (boolean and not value) or isinstance(value, Undefined):
275         return default_value
276     return value
277
278
279 @evalcontextfilter
280 def do_join(eval_ctx, value, d=u'', attribute=None):
281     """Return a string which is the concatenation of the strings in the
282     sequence. The separator between elements is an empty string per
283     default, you can define it with the optional parameter:
284
285     .. sourcecode:: jinja
286
287         {{ [1, 2, 3]|join('|') }}
288             -> 1|2|3
289
290         {{ [1, 2, 3]|join }}
291             -> 123
292
293     It is also possible to join certain attributes of an object:
294
295     .. sourcecode:: jinja
296
297         {{ users|join(', ', attribute='username') }}
298
299     .. versionadded:: 2.6
300        The `attribute` parameter was added.
301     """
302     if attribute is not None:
303         value = imap(make_attrgetter(eval_ctx.environment, attribute), value)
304
305     # no automatic escaping?  joining is a lot eaiser then
306     if not eval_ctx.autoescape:
307         return unicode(d).join(imap(unicode, value))
308
309     # if the delimiter doesn't have an html representation we check
310     # if any of the items has.  If yes we do a coercion to Markup
311     if not hasattr(d, '__html__'):
312         value = list(value)
313         do_escape = False
314         for idx, item in enumerate(value):
315             if hasattr(item, '__html__'):
316                 do_escape = True
317             else:
318                 value[idx] = unicode(item)
319         if do_escape:
320             d = escape(d)
321         else:
322             d = unicode(d)
323         return d.join(value)
324
325     # no html involved, to normal joining
326     return soft_unicode(d).join(imap(soft_unicode, value))
327
328
329 def do_center(value, width=80):
330     """Centers the value in a field of a given width."""
331     return unicode(value).center(width)
332
333
334 @environmentfilter
335 def do_first(environment, seq):
336     """Return the first item of a sequence."""
337     try:
338         return iter(seq).next()
339     except StopIteration:
340         return environment.undefined('No first item, sequence was empty.')
341
342
343 @environmentfilter
344 def do_last(environment, seq):
345     """Return the last item of a sequence."""
346     try:
347         return iter(reversed(seq)).next()
348     except StopIteration:
349         return environment.undefined('No last item, sequence was empty.')
350
351
352 @environmentfilter
353 def do_random(environment, seq):
354     """Return a random item from the sequence."""
355     try:
356         return choice(seq)
357     except IndexError:
358         return environment.undefined('No random item, sequence was empty.')
359
360
361 def do_filesizeformat(value, binary=False):
362     """Format the value like a 'human-readable' file size (i.e. 13 kB,
363     4.1 MB, 102 Bytes, etc).  Per default decimal prefixes are used (Mega,
364     Giga, etc.), if the second parameter is set to `True` the binary
365     prefixes are used (Mebi, Gibi).
366     """
367     bytes = float(value)
368     base = binary and 1024 or 1000
369     prefixes = [
370         (binary and 'KiB' or 'kB'),
371         (binary and 'MiB' or 'MB'),
372         (binary and 'GiB' or 'GB'),
373         (binary and 'TiB' or 'TB'),
374         (binary and 'PiB' or 'PB'),
375         (binary and 'EiB' or 'EB'),
376         (binary and 'ZiB' or 'ZB'),
377         (binary and 'YiB' or 'YB')
378     ]
379     if bytes == 1:
380         return '1 Byte'
381     elif bytes < base:
382         return '%d Bytes' % bytes
383     else:
384         for i, prefix in enumerate(prefixes):
385             unit = base ** (i + 2)
386             if bytes < unit:
387                 return '%.1f %s' % ((base * bytes / unit), prefix)
388         return '%.1f %s' % ((base * bytes / unit), prefix)
389
390
391 def do_pprint(value, verbose=False):
392     """Pretty print a variable. Useful for debugging.
393
394     With Jinja 1.2 onwards you can pass it a parameter.  If this parameter
395     is truthy the output will be more verbose (this requires `pretty`)
396     """
397     return pformat(value, verbose=verbose)
398
399
400 @evalcontextfilter
401 def do_urlize(eval_ctx, value, trim_url_limit=None, nofollow=False):
402     """Converts URLs in plain text into clickable links.
403
404     If you pass the filter an additional integer it will shorten the urls
405     to that number. Also a third argument exists that makes the urls
406     "nofollow":
407
408     .. sourcecode:: jinja
409
410         {{ mytext|urlize(40, true) }}
411             links are shortened to 40 chars and defined with rel="nofollow"
412     """
413     rv = urlize(value, trim_url_limit, nofollow)
414     if eval_ctx.autoescape:
415         rv = Markup(rv)
416     return rv
417
418
419 def do_indent(s, width=4, indentfirst=False):
420     """Return a copy of the passed string, each line indented by
421     4 spaces. The first line is not indented. If you want to
422     change the number of spaces or indent the first line too
423     you can pass additional parameters to the filter:
424
425     .. sourcecode:: jinja
426
427         {{ mytext|indent(2, true) }}
428             indent by two spaces and indent the first line too.
429     """
430     indention = u' ' * width
431     rv = (u'\n' + indention).join(s.splitlines())
432     if indentfirst:
433         rv = indention + rv
434     return rv
435
436
437 def do_truncate(s, length=255, killwords=False, end='...'):
438     """Return a truncated copy of the string. The length is specified
439     with the first parameter which defaults to ``255``. If the second
440     parameter is ``true`` the filter will cut the text at length. Otherwise
441     it will try to save the last word. If the text was in fact
442     truncated it will append an ellipsis sign (``"..."``). If you want a
443     different ellipsis sign than ``"..."`` you can specify it using the
444     third parameter.
445
446     .. sourcecode jinja::
447
448         {{ mytext|truncate(300, false, '&raquo;') }}
449             truncate mytext to 300 chars, don't split up words, use a
450             right pointing double arrow as ellipsis sign.
451     """
452     if len(s) <= length:
453         return s
454     elif killwords:
455         return s[:length] + end
456     words = s.split(' ')
457     result = []
458     m = 0
459     for word in words:
460         m += len(word) + 1
461         if m > length:
462             break
463         result.append(word)
464     result.append(end)
465     return u' '.join(result)
466
467 @environmentfilter
468 def do_wordwrap(environment, s, width=79, break_long_words=True):
469     """
470     Return a copy of the string passed to the filter wrapped after
471     ``79`` characters.  You can override this default using the first
472     parameter.  If you set the second parameter to `false` Jinja will not
473     split words apart if they are longer than `width`.
474     """
475     import textwrap
476     return environment.newline_sequence.join(textwrap.wrap(s, width=width, expand_tabs=False,
477                                    replace_whitespace=False,
478                                    break_long_words=break_long_words))
479
480
481 def do_wordcount(s):
482     """Count the words in that string."""
483     return len(_word_re.findall(s))
484
485
486 def do_int(value, default=0):
487     """Convert the value into an integer. If the
488     conversion doesn't work it will return ``0``. You can
489     override this default using the first parameter.
490     """
491     try:
492         return int(value)
493     except (TypeError, ValueError):
494         # this quirk is necessary so that "42.23"|int gives 42.
495         try:
496             return int(float(value))
497         except (TypeError, ValueError):
498             return default
499
500
501 def do_float(value, default=0.0):
502     """Convert the value into a floating point number. If the
503     conversion doesn't work it will return ``0.0``. You can
504     override this default using the first parameter.
505     """
506     try:
507         return float(value)
508     except (TypeError, ValueError):
509         return default
510
511
512 def do_format(value, *args, **kwargs):
513     """
514     Apply python string formatting on an object:
515
516     .. sourcecode:: jinja
517
518         {{ "%s - %s"|format("Hello?", "Foo!") }}
519             -> Hello? - Foo!
520     """
521     if args and kwargs:
522         raise FilterArgumentError('can\'t handle positional and keyword '
523                                   'arguments at the same time')
524     return soft_unicode(value) % (kwargs or args)
525
526
527 def do_trim(value):
528     """Strip leading and trailing whitespace."""
529     return soft_unicode(value).strip()
530
531
532 def do_striptags(value):
533     """Strip SGML/XML tags and replace adjacent whitespace by one space.
534     """
535     if hasattr(value, '__html__'):
536         value = value.__html__()
537     return Markup(unicode(value)).striptags()
538
539
540 def do_slice(value, slices, fill_with=None):
541     """Slice an iterator and return a list of lists containing
542     those items. Useful if you want to create a div containing
543     three ul tags that represent columns:
544
545     .. sourcecode:: html+jinja
546
547         <div class="columwrapper">
548           {%- for column in items|slice(3) %}
549             <ul class="column-{{ loop.index }}">
550             {%- for item in column %}
551               <li>{{ item }}</li>
552             {%- endfor %}
553             </ul>
554           {%- endfor %}
555         </div>
556
557     If you pass it a second argument it's used to fill missing
558     values on the last iteration.
559     """
560     seq = list(value)
561     length = len(seq)
562     items_per_slice = length // slices
563     slices_with_extra = length % slices
564     offset = 0
565     for slice_number in xrange(slices):
566         start = offset + slice_number * items_per_slice
567         if slice_number < slices_with_extra:
568             offset += 1
569         end = offset + (slice_number + 1) * items_per_slice
570         tmp = seq[start:end]
571         if fill_with is not None and slice_number >= slices_with_extra:
572             tmp.append(fill_with)
573         yield tmp
574
575
576 def do_batch(value, linecount, fill_with=None):
577     """
578     A filter that batches items. It works pretty much like `slice`
579     just the other way round. It returns a list of lists with the
580     given number of items. If you provide a second parameter this
581     is used to fill missing items. See this example:
582
583     .. sourcecode:: html+jinja
584
585         <table>
586         {%- for row in items|batch(3, '&nbsp;') %}
587           <tr>
588           {%- for column in row %}
589             <td>{{ column }}</td>
590           {%- endfor %}
591           </tr>
592         {%- endfor %}
593         </table>
594     """
595     result = []
596     tmp = []
597     for item in value:
598         if len(tmp) == linecount:
599             yield tmp
600             tmp = []
601         tmp.append(item)
602     if tmp:
603         if fill_with is not None and len(tmp) < linecount:
604             tmp += [fill_with] * (linecount - len(tmp))
605         yield tmp
606
607
608 def do_round(value, precision=0, method='common'):
609     """Round the number to a given precision. The first
610     parameter specifies the precision (default is ``0``), the
611     second the rounding method:
612
613     - ``'common'`` rounds either up or down
614     - ``'ceil'`` always rounds up
615     - ``'floor'`` always rounds down
616
617     If you don't specify a method ``'common'`` is used.
618
619     .. sourcecode:: jinja
620
621         {{ 42.55|round }}
622             -> 43.0
623         {{ 42.55|round(1, 'floor') }}
624             -> 42.5
625
626     Note that even if rounded to 0 precision, a float is returned.  If
627     you need a real integer, pipe it through `int`:
628
629     .. sourcecode:: jinja
630
631         {{ 42.55|round|int }}
632             -> 43
633     """
634     if not method in ('common', 'ceil', 'floor'):
635         raise FilterArgumentError('method must be common, ceil or floor')
636     if method == 'common':
637         return round(value, precision)
638     func = getattr(math, method)
639     return func(value * (10 ** precision)) / (10 ** precision)
640
641
642 @environmentfilter
643 def do_groupby(environment, value, attribute):
644     """Group a sequence of objects by a common attribute.
645
646     If you for example have a list of dicts or objects that represent persons
647     with `gender`, `first_name` and `last_name` attributes and you want to
648     group all users by genders you can do something like the following
649     snippet:
650
651     .. sourcecode:: html+jinja
652
653         <ul>
654         {% for group in persons|groupby('gender') %}
655             <li>{{ group.grouper }}<ul>
656             {% for person in group.list %}
657                 <li>{{ person.first_name }} {{ person.last_name }}</li>
658             {% endfor %}</ul></li>
659         {% endfor %}
660         </ul>
661
662     Additionally it's possible to use tuple unpacking for the grouper and
663     list:
664
665     .. sourcecode:: html+jinja
666
667         <ul>
668         {% for grouper, list in persons|groupby('gender') %}
669             ...
670         {% endfor %}
671         </ul>
672
673     As you can see the item we're grouping by is stored in the `grouper`
674     attribute and the `list` contains all the objects that have this grouper
675     in common.
676
677     .. versionchanged:: 2.6
678        It's now possible to use dotted notation to group by the child
679        attribute of another attribute.
680     """
681     expr = make_attrgetter(environment, attribute)
682     return sorted(map(_GroupTuple, groupby(sorted(value, key=expr), expr)))
683
684
685 class _GroupTuple(tuple):
686     __slots__ = ()
687     grouper = property(itemgetter(0))
688     list = property(itemgetter(1))
689
690     def __new__(cls, (key, value)):
691         return tuple.__new__(cls, (key, list(value)))
692
693
694 @environmentfilter
695 def do_sum(environment, iterable, attribute=None, start=0):
696     """Returns the sum of a sequence of numbers plus the value of parameter
697     'start' (which defaults to 0).  When the sequence is empty it returns
698     start.
699
700     It is also possible to sum up only certain attributes:
701
702     .. sourcecode:: jinja
703
704         Total: {{ items|sum(attribute='price') }}
705
706     .. versionchanged:: 2.6
707        The `attribute` parameter was added to allow suming up over
708        attributes.  Also the `start` parameter was moved on to the right.
709     """
710     if attribute is not None:
711         iterable = imap(make_attrgetter(environment, attribute), iterable)
712     return sum(iterable, start)
713
714
715 def do_list(value):
716     """Convert the value into a list.  If it was a string the returned list
717     will be a list of characters.
718     """
719     return list(value)
720
721
722 def do_mark_safe(value):
723     """Mark the value as safe which means that in an environment with automatic
724     escaping enabled this variable will not be escaped.
725     """
726     return Markup(value)
727
728
729 def do_mark_unsafe(value):
730     """Mark a value as unsafe.  This is the reverse operation for :func:`safe`."""
731     return unicode(value)
732
733
734 def do_reverse(value):
735     """Reverse the object or return an iterator the iterates over it the other
736     way round.
737     """
738     if isinstance(value, basestring):
739         return value[::-1]
740     try:
741         return reversed(value)
742     except TypeError:
743         try:
744             rv = list(value)
745             rv.reverse()
746             return rv
747         except TypeError:
748             raise FilterArgumentError('argument must be iterable')
749
750
751 @environmentfilter
752 def do_attr(environment, obj, name):
753     """Get an attribute of an object.  ``foo|attr("bar")`` works like
754     ``foo["bar"]`` just that always an attribute is returned and items are not
755     looked up.
756
757     See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details.
758     """
759     try:
760         name = str(name)
761     except UnicodeError:
762         pass
763     else:
764         try:
765             value = getattr(obj, name)
766         except AttributeError:
767             pass
768         else:
769             if environment.sandboxed and not \
770                environment.is_safe_attribute(obj, name, value):
771                 return environment.unsafe_undefined(obj, name)
772             return value
773     return environment.undefined(obj=obj, name=name)
774
775
776 FILTERS = {
777     'attr':                 do_attr,
778     'replace':              do_replace,
779     'upper':                do_upper,
780     'lower':                do_lower,
781     'escape':               escape,
782     'e':                    escape,
783     'forceescape':          do_forceescape,
784     'capitalize':           do_capitalize,
785     'title':                do_title,
786     'default':              do_default,
787     'd':                    do_default,
788     'join':                 do_join,
789     'count':                len,
790     'dictsort':             do_dictsort,
791     'sort':                 do_sort,
792     'length':               len,
793     'reverse':              do_reverse,
794     'center':               do_center,
795     'indent':               do_indent,
796     'title':                do_title,
797     'capitalize':           do_capitalize,
798     'first':                do_first,
799     'last':                 do_last,
800     'random':               do_random,
801     'filesizeformat':       do_filesizeformat,
802     'pprint':               do_pprint,
803     'truncate':             do_truncate,
804     'wordwrap':             do_wordwrap,
805     'wordcount':            do_wordcount,
806     'int':                  do_int,
807     'float':                do_float,
808     'string':               soft_unicode,
809     'list':                 do_list,
810     'urlize':               do_urlize,
811     'format':               do_format,
812     'trim':                 do_trim,
813     'striptags':            do_striptags,
814     'slice':                do_slice,
815     'batch':                do_batch,
816     'sum':                  do_sum,
817     'abs':                  abs,
818     'round':                do_round,
819     'groupby':              do_groupby,
820     'safe':                 do_mark_safe,
821     'xmlattr':              do_xmlattr,
822     'urlescape':            do_urlescape
823 }