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