Index: mojo/public/third_party/jinja2/filters.py |
diff --git a/mojo/public/third_party/jinja2/filters.py b/mojo/public/third_party/jinja2/filters.py |
deleted file mode 100644 |
index fd0db04aa41026500910347cf401fe620c556188..0000000000000000000000000000000000000000 |
--- a/mojo/public/third_party/jinja2/filters.py |
+++ /dev/null |
@@ -1,987 +0,0 @@ |
-# -*- coding: utf-8 -*- |
-""" |
- jinja2.filters |
- ~~~~~~~~~~~~~~ |
- |
- Bundled jinja filters. |
- |
- :copyright: (c) 2010 by the Jinja Team. |
- :license: BSD, see LICENSE for more details. |
-""" |
-import re |
-import math |
- |
-from random import choice |
-from operator import itemgetter |
-from itertools import groupby |
-from jinja2.utils import Markup, escape, pformat, urlize, soft_unicode, \ |
- unicode_urlencode |
-from jinja2.runtime import Undefined |
-from jinja2.exceptions import FilterArgumentError |
-from jinja2._compat import next, imap, string_types, text_type, iteritems |
- |
- |
-_word_re = re.compile(r'\w+(?u)') |
- |
- |
-def contextfilter(f): |
- """Decorator for marking context dependent filters. The current |
- :class:`Context` will be passed as first argument. |
- """ |
- f.contextfilter = True |
- return f |
- |
- |
-def evalcontextfilter(f): |
- """Decorator for marking eval-context dependent filters. An eval |
- context object is passed as first argument. For more information |
- about the eval context, see :ref:`eval-context`. |
- |
- .. versionadded:: 2.4 |
- """ |
- f.evalcontextfilter = True |
- return f |
- |
- |
-def environmentfilter(f): |
- """Decorator for marking evironment dependent filters. The current |
- :class:`Environment` is passed to the filter as first argument. |
- """ |
- f.environmentfilter = True |
- return f |
- |
- |
-def make_attrgetter(environment, attribute): |
- """Returns a callable that looks up the given attribute from a |
- passed object with the rules of the environment. Dots are allowed |
- to access attributes of attributes. Integer parts in paths are |
- looked up as integers. |
- """ |
- if not isinstance(attribute, string_types) \ |
- or ('.' not in attribute and not attribute.isdigit()): |
- return lambda x: environment.getitem(x, attribute) |
- attribute = attribute.split('.') |
- def attrgetter(item): |
- for part in attribute: |
- if part.isdigit(): |
- part = int(part) |
- item = environment.getitem(item, part) |
- return item |
- return attrgetter |
- |
- |
-def do_forceescape(value): |
- """Enforce HTML escaping. This will probably double escape variables.""" |
- if hasattr(value, '__html__'): |
- value = value.__html__() |
- return escape(text_type(value)) |
- |
- |
-def do_urlencode(value): |
- """Escape strings for use in URLs (uses UTF-8 encoding). It accepts both |
- dictionaries and regular strings as well as pairwise iterables. |
- |
- .. versionadded:: 2.7 |
- """ |
- itemiter = None |
- if isinstance(value, dict): |
- itemiter = iteritems(value) |
- elif not isinstance(value, string_types): |
- try: |
- itemiter = iter(value) |
- except TypeError: |
- pass |
- if itemiter is None: |
- return unicode_urlencode(value) |
- return u'&'.join(unicode_urlencode(k) + '=' + |
- unicode_urlencode(v) for k, v in itemiter) |
- |
- |
-@evalcontextfilter |
-def do_replace(eval_ctx, s, old, new, count=None): |
- """Return a copy of the value with all occurrences of a substring |
- replaced with a new one. The first argument is the substring |
- that should be replaced, the second is the replacement string. |
- If the optional third argument ``count`` is given, only the first |
- ``count`` occurrences are replaced: |
- |
- .. sourcecode:: jinja |
- |
- {{ "Hello World"|replace("Hello", "Goodbye") }} |
- -> Goodbye World |
- |
- {{ "aaaaargh"|replace("a", "d'oh, ", 2) }} |
- -> d'oh, d'oh, aaargh |
- """ |
- if count is None: |
- count = -1 |
- if not eval_ctx.autoescape: |
- return text_type(s).replace(text_type(old), text_type(new), count) |
- if hasattr(old, '__html__') or hasattr(new, '__html__') and \ |
- not hasattr(s, '__html__'): |
- s = escape(s) |
- else: |
- s = soft_unicode(s) |
- return s.replace(soft_unicode(old), soft_unicode(new), count) |
- |
- |
-def do_upper(s): |
- """Convert a value to uppercase.""" |
- return soft_unicode(s).upper() |
- |
- |
-def do_lower(s): |
- """Convert a value to lowercase.""" |
- return soft_unicode(s).lower() |
- |
- |
-@evalcontextfilter |
-def do_xmlattr(_eval_ctx, d, autospace=True): |
- """Create an SGML/XML attribute string based on the items in a dict. |
- All values that are neither `none` nor `undefined` are automatically |
- escaped: |
- |
- .. sourcecode:: html+jinja |
- |
- <ul{{ {'class': 'my_list', 'missing': none, |
- 'id': 'list-%d'|format(variable)}|xmlattr }}> |
- ... |
- </ul> |
- |
- Results in something like this: |
- |
- .. sourcecode:: html |
- |
- <ul class="my_list" id="list-42"> |
- ... |
- </ul> |
- |
- As you can see it automatically prepends a space in front of the item |
- if the filter returned something unless the second parameter is false. |
- """ |
- rv = u' '.join( |
- u'%s="%s"' % (escape(key), escape(value)) |
- for key, value in iteritems(d) |
- if value is not None and not isinstance(value, Undefined) |
- ) |
- if autospace and rv: |
- rv = u' ' + rv |
- if _eval_ctx.autoescape: |
- rv = Markup(rv) |
- return rv |
- |
- |
-def do_capitalize(s): |
- """Capitalize a value. The first character will be uppercase, all others |
- lowercase. |
- """ |
- return soft_unicode(s).capitalize() |
- |
- |
-def do_title(s): |
- """Return a titlecased version of the value. I.e. words will start with |
- uppercase letters, all remaining characters are lowercase. |
- """ |
- rv = [] |
- for item in re.compile(r'([-\s]+)(?u)').split(s): |
- if not item: |
- continue |
- rv.append(item[0].upper() + item[1:].lower()) |
- return ''.join(rv) |
- |
- |
-def do_dictsort(value, case_sensitive=False, by='key'): |
- """Sort a dict and yield (key, value) pairs. Because python dicts are |
- unsorted you may want to use this function to order them by either |
- key or value: |
- |
- .. sourcecode:: jinja |
- |
- {% for item in mydict|dictsort %} |
- sort the dict by key, case insensitive |
- |
- {% for item in mydict|dictsort(true) %} |
- sort the dict by key, case sensitive |
- |
- {% for item in mydict|dictsort(false, 'value') %} |
- sort the dict by key, case insensitive, sorted |
- normally and ordered by value. |
- """ |
- if by == 'key': |
- pos = 0 |
- elif by == 'value': |
- pos = 1 |
- else: |
- raise FilterArgumentError('You can only sort by either ' |
- '"key" or "value"') |
- def sort_func(item): |
- value = item[pos] |
- if isinstance(value, string_types) and not case_sensitive: |
- value = value.lower() |
- return value |
- |
- return sorted(value.items(), key=sort_func) |
- |
- |
-@environmentfilter |
-def do_sort(environment, value, reverse=False, case_sensitive=False, |
- attribute=None): |
- """Sort an iterable. Per default it sorts ascending, if you pass it |
- true as first argument it will reverse the sorting. |
- |
- If the iterable is made of strings the third parameter can be used to |
- control the case sensitiveness of the comparison which is disabled by |
- default. |
- |
- .. sourcecode:: jinja |
- |
- {% for item in iterable|sort %} |
- ... |
- {% endfor %} |
- |
- It is also possible to sort by an attribute (for example to sort |
- by the date of an object) by specifying the `attribute` parameter: |
- |
- .. sourcecode:: jinja |
- |
- {% for item in iterable|sort(attribute='date') %} |
- ... |
- {% endfor %} |
- |
- .. versionchanged:: 2.6 |
- The `attribute` parameter was added. |
- """ |
- if not case_sensitive: |
- def sort_func(item): |
- if isinstance(item, string_types): |
- item = item.lower() |
- return item |
- else: |
- sort_func = None |
- if attribute is not None: |
- getter = make_attrgetter(environment, attribute) |
- def sort_func(item, processor=sort_func or (lambda x: x)): |
- return processor(getter(item)) |
- return sorted(value, key=sort_func, reverse=reverse) |
- |
- |
-def do_default(value, default_value=u'', boolean=False): |
- """If the value is undefined it will return the passed default value, |
- otherwise the value of the variable: |
- |
- .. sourcecode:: jinja |
- |
- {{ my_variable|default('my_variable is not defined') }} |
- |
- This will output the value of ``my_variable`` if the variable was |
- defined, otherwise ``'my_variable is not defined'``. If you want |
- to use default with variables that evaluate to false you have to |
- set the second parameter to `true`: |
- |
- .. sourcecode:: jinja |
- |
- {{ ''|default('the string was empty', true) }} |
- """ |
- if isinstance(value, Undefined) or (boolean and not value): |
- return default_value |
- return value |
- |
- |
-@evalcontextfilter |
-def do_join(eval_ctx, value, d=u'', attribute=None): |
- """Return a string which is the concatenation of the strings in the |
- sequence. The separator between elements is an empty string per |
- default, you can define it with the optional parameter: |
- |
- .. sourcecode:: jinja |
- |
- {{ [1, 2, 3]|join('|') }} |
- -> 1|2|3 |
- |
- {{ [1, 2, 3]|join }} |
- -> 123 |
- |
- It is also possible to join certain attributes of an object: |
- |
- .. sourcecode:: jinja |
- |
- {{ users|join(', ', attribute='username') }} |
- |
- .. versionadded:: 2.6 |
- The `attribute` parameter was added. |
- """ |
- if attribute is not None: |
- value = imap(make_attrgetter(eval_ctx.environment, attribute), value) |
- |
- # no automatic escaping? joining is a lot eaiser then |
- if not eval_ctx.autoescape: |
- return text_type(d).join(imap(text_type, value)) |
- |
- # if the delimiter doesn't have an html representation we check |
- # if any of the items has. If yes we do a coercion to Markup |
- if not hasattr(d, '__html__'): |
- value = list(value) |
- do_escape = False |
- for idx, item in enumerate(value): |
- if hasattr(item, '__html__'): |
- do_escape = True |
- else: |
- value[idx] = text_type(item) |
- if do_escape: |
- d = escape(d) |
- else: |
- d = text_type(d) |
- return d.join(value) |
- |
- # no html involved, to normal joining |
- return soft_unicode(d).join(imap(soft_unicode, value)) |
- |
- |
-def do_center(value, width=80): |
- """Centers the value in a field of a given width.""" |
- return text_type(value).center(width) |
- |
- |
-@environmentfilter |
-def do_first(environment, seq): |
- """Return the first item of a sequence.""" |
- try: |
- return next(iter(seq)) |
- except StopIteration: |
- return environment.undefined('No first item, sequence was empty.') |
- |
- |
-@environmentfilter |
-def do_last(environment, seq): |
- """Return the last item of a sequence.""" |
- try: |
- return next(iter(reversed(seq))) |
- except StopIteration: |
- return environment.undefined('No last item, sequence was empty.') |
- |
- |
-@environmentfilter |
-def do_random(environment, seq): |
- """Return a random item from the sequence.""" |
- try: |
- return choice(seq) |
- except IndexError: |
- return environment.undefined('No random item, sequence was empty.') |
- |
- |
-def do_filesizeformat(value, binary=False): |
- """Format the value like a 'human-readable' file size (i.e. 13 kB, |
- 4.1 MB, 102 Bytes, etc). Per default decimal prefixes are used (Mega, |
- Giga, etc.), if the second parameter is set to `True` the binary |
- prefixes are used (Mebi, Gibi). |
- """ |
- bytes = float(value) |
- base = binary and 1024 or 1000 |
- prefixes = [ |
- (binary and 'KiB' or 'kB'), |
- (binary and 'MiB' or 'MB'), |
- (binary and 'GiB' or 'GB'), |
- (binary and 'TiB' or 'TB'), |
- (binary and 'PiB' or 'PB'), |
- (binary and 'EiB' or 'EB'), |
- (binary and 'ZiB' or 'ZB'), |
- (binary and 'YiB' or 'YB') |
- ] |
- if bytes == 1: |
- return '1 Byte' |
- elif bytes < base: |
- return '%d Bytes' % bytes |
- else: |
- for i, prefix in enumerate(prefixes): |
- unit = base ** (i + 2) |
- if bytes < unit: |
- return '%.1f %s' % ((base * bytes / unit), prefix) |
- return '%.1f %s' % ((base * bytes / unit), prefix) |
- |
- |
-def do_pprint(value, verbose=False): |
- """Pretty print a variable. Useful for debugging. |
- |
- With Jinja 1.2 onwards you can pass it a parameter. If this parameter |
- is truthy the output will be more verbose (this requires `pretty`) |
- """ |
- return pformat(value, verbose=verbose) |
- |
- |
-@evalcontextfilter |
-def do_urlize(eval_ctx, value, trim_url_limit=None, nofollow=False): |
- """Converts URLs in plain text into clickable links. |
- |
- If you pass the filter an additional integer it will shorten the urls |
- to that number. Also a third argument exists that makes the urls |
- "nofollow": |
- |
- .. sourcecode:: jinja |
- |
- {{ mytext|urlize(40, true) }} |
- links are shortened to 40 chars and defined with rel="nofollow" |
- """ |
- rv = urlize(value, trim_url_limit, nofollow) |
- if eval_ctx.autoescape: |
- rv = Markup(rv) |
- return rv |
- |
- |
-def do_indent(s, width=4, indentfirst=False): |
- """Return a copy of the passed string, each line indented by |
- 4 spaces. The first line is not indented. If you want to |
- change the number of spaces or indent the first line too |
- you can pass additional parameters to the filter: |
- |
- .. sourcecode:: jinja |
- |
- {{ mytext|indent(2, true) }} |
- indent by two spaces and indent the first line too. |
- """ |
- indention = u' ' * width |
- rv = (u'\n' + indention).join(s.splitlines()) |
- if indentfirst: |
- rv = indention + rv |
- return rv |
- |
- |
-def do_truncate(s, length=255, killwords=False, end='...'): |
- """Return a truncated copy of the string. The length is specified |
- with the first parameter which defaults to ``255``. If the second |
- parameter is ``true`` the filter will cut the text at length. Otherwise |
- it will discard the last word. If the text was in fact |
- truncated it will append an ellipsis sign (``"..."``). If you want a |
- different ellipsis sign than ``"..."`` you can specify it using the |
- third parameter. |
- |
- .. sourcecode:: jinja |
- |
- {{ "foo bar"|truncate(5) }} |
- -> "foo ..." |
- {{ "foo bar"|truncate(5, True) }} |
- -> "foo b..." |
- """ |
- if len(s) <= length: |
- return s |
- elif killwords: |
- return s[:length] + end |
- words = s.split(' ') |
- result = [] |
- m = 0 |
- for word in words: |
- m += len(word) + 1 |
- if m > length: |
- break |
- result.append(word) |
- result.append(end) |
- return u' '.join(result) |
- |
-@environmentfilter |
-def do_wordwrap(environment, s, width=79, break_long_words=True, |
- wrapstring=None): |
- """ |
- Return a copy of the string passed to the filter wrapped after |
- ``79`` characters. You can override this default using the first |
- parameter. If you set the second parameter to `false` Jinja will not |
- split words apart if they are longer than `width`. By default, the newlines |
- will be the default newlines for the environment, but this can be changed |
- using the wrapstring keyword argument. |
- |
- .. versionadded:: 2.7 |
- Added support for the `wrapstring` parameter. |
- """ |
- if not wrapstring: |
- wrapstring = environment.newline_sequence |
- import textwrap |
- return wrapstring.join(textwrap.wrap(s, width=width, expand_tabs=False, |
- replace_whitespace=False, |
- break_long_words=break_long_words)) |
- |
- |
-def do_wordcount(s): |
- """Count the words in that string.""" |
- return len(_word_re.findall(s)) |
- |
- |
-def do_int(value, default=0): |
- """Convert the value into an integer. If the |
- conversion doesn't work it will return ``0``. You can |
- override this default using the first parameter. |
- """ |
- try: |
- return int(value) |
- except (TypeError, ValueError): |
- # this quirk is necessary so that "42.23"|int gives 42. |
- try: |
- return int(float(value)) |
- except (TypeError, ValueError): |
- return default |
- |
- |
-def do_float(value, default=0.0): |
- """Convert the value into a floating point number. If the |
- conversion doesn't work it will return ``0.0``. You can |
- override this default using the first parameter. |
- """ |
- try: |
- return float(value) |
- except (TypeError, ValueError): |
- return default |
- |
- |
-def do_format(value, *args, **kwargs): |
- """ |
- Apply python string formatting on an object: |
- |
- .. sourcecode:: jinja |
- |
- {{ "%s - %s"|format("Hello?", "Foo!") }} |
- -> Hello? - Foo! |
- """ |
- if args and kwargs: |
- raise FilterArgumentError('can\'t handle positional and keyword ' |
- 'arguments at the same time') |
- return soft_unicode(value) % (kwargs or args) |
- |
- |
-def do_trim(value): |
- """Strip leading and trailing whitespace.""" |
- return soft_unicode(value).strip() |
- |
- |
-def do_striptags(value): |
- """Strip SGML/XML tags and replace adjacent whitespace by one space. |
- """ |
- if hasattr(value, '__html__'): |
- value = value.__html__() |
- return Markup(text_type(value)).striptags() |
- |
- |
-def do_slice(value, slices, fill_with=None): |
- """Slice an iterator and return a list of lists containing |
- those items. Useful if you want to create a div containing |
- three ul tags that represent columns: |
- |
- .. sourcecode:: html+jinja |
- |
- <div class="columwrapper"> |
- {%- for column in items|slice(3) %} |
- <ul class="column-{{ loop.index }}"> |
- {%- for item in column %} |
- <li>{{ item }}</li> |
- {%- endfor %} |
- </ul> |
- {%- endfor %} |
- </div> |
- |
- If you pass it a second argument it's used to fill missing |
- values on the last iteration. |
- """ |
- seq = list(value) |
- length = len(seq) |
- items_per_slice = length // slices |
- slices_with_extra = length % slices |
- offset = 0 |
- for slice_number in range(slices): |
- start = offset + slice_number * items_per_slice |
- if slice_number < slices_with_extra: |
- offset += 1 |
- end = offset + (slice_number + 1) * items_per_slice |
- tmp = seq[start:end] |
- if fill_with is not None and slice_number >= slices_with_extra: |
- tmp.append(fill_with) |
- yield tmp |
- |
- |
-def do_batch(value, linecount, fill_with=None): |
- """ |
- A filter that batches items. It works pretty much like `slice` |
- just the other way round. It returns a list of lists with the |
- given number of items. If you provide a second parameter this |
- is used to fill up missing items. See this example: |
- |
- .. sourcecode:: html+jinja |
- |
- <table> |
- {%- for row in items|batch(3, ' ') %} |
- <tr> |
- {%- for column in row %} |
- <td>{{ column }}</td> |
- {%- endfor %} |
- </tr> |
- {%- endfor %} |
- </table> |
- """ |
- result = [] |
- tmp = [] |
- for item in value: |
- if len(tmp) == linecount: |
- yield tmp |
- tmp = [] |
- tmp.append(item) |
- if tmp: |
- if fill_with is not None and len(tmp) < linecount: |
- tmp += [fill_with] * (linecount - len(tmp)) |
- yield tmp |
- |
- |
-def do_round(value, precision=0, method='common'): |
- """Round the number to a given precision. The first |
- parameter specifies the precision (default is ``0``), the |
- second the rounding method: |
- |
- - ``'common'`` rounds either up or down |
- - ``'ceil'`` always rounds up |
- - ``'floor'`` always rounds down |
- |
- If you don't specify a method ``'common'`` is used. |
- |
- .. sourcecode:: jinja |
- |
- {{ 42.55|round }} |
- -> 43.0 |
- {{ 42.55|round(1, 'floor') }} |
- -> 42.5 |
- |
- Note that even if rounded to 0 precision, a float is returned. If |
- you need a real integer, pipe it through `int`: |
- |
- .. sourcecode:: jinja |
- |
- {{ 42.55|round|int }} |
- -> 43 |
- """ |
- if not method in ('common', 'ceil', 'floor'): |
- raise FilterArgumentError('method must be common, ceil or floor') |
- if method == 'common': |
- return round(value, precision) |
- func = getattr(math, method) |
- return func(value * (10 ** precision)) / (10 ** precision) |
- |
- |
-@environmentfilter |
-def do_groupby(environment, value, attribute): |
- """Group a sequence of objects by a common attribute. |
- |
- If you for example have a list of dicts or objects that represent persons |
- with `gender`, `first_name` and `last_name` attributes and you want to |
- group all users by genders you can do something like the following |
- snippet: |
- |
- .. sourcecode:: html+jinja |
- |
- <ul> |
- {% for group in persons|groupby('gender') %} |
- <li>{{ group.grouper }}<ul> |
- {% for person in group.list %} |
- <li>{{ person.first_name }} {{ person.last_name }}</li> |
- {% endfor %}</ul></li> |
- {% endfor %} |
- </ul> |
- |
- Additionally it's possible to use tuple unpacking for the grouper and |
- list: |
- |
- .. sourcecode:: html+jinja |
- |
- <ul> |
- {% for grouper, list in persons|groupby('gender') %} |
- ... |
- {% endfor %} |
- </ul> |
- |
- As you can see the item we're grouping by is stored in the `grouper` |
- attribute and the `list` contains all the objects that have this grouper |
- in common. |
- |
- .. versionchanged:: 2.6 |
- It's now possible to use dotted notation to group by the child |
- attribute of another attribute. |
- """ |
- expr = make_attrgetter(environment, attribute) |
- return sorted(map(_GroupTuple, groupby(sorted(value, key=expr), expr))) |
- |
- |
-class _GroupTuple(tuple): |
- __slots__ = () |
- grouper = property(itemgetter(0)) |
- list = property(itemgetter(1)) |
- |
- def __new__(cls, xxx_todo_changeme): |
- (key, value) = xxx_todo_changeme |
- return tuple.__new__(cls, (key, list(value))) |
- |
- |
-@environmentfilter |
-def do_sum(environment, iterable, attribute=None, start=0): |
- """Returns the sum of a sequence of numbers plus the value of parameter |
- 'start' (which defaults to 0). When the sequence is empty it returns |
- start. |
- |
- It is also possible to sum up only certain attributes: |
- |
- .. sourcecode:: jinja |
- |
- Total: {{ items|sum(attribute='price') }} |
- |
- .. versionchanged:: 2.6 |
- The `attribute` parameter was added to allow suming up over |
- attributes. Also the `start` parameter was moved on to the right. |
- """ |
- if attribute is not None: |
- iterable = imap(make_attrgetter(environment, attribute), iterable) |
- return sum(iterable, start) |
- |
- |
-def do_list(value): |
- """Convert the value into a list. If it was a string the returned list |
- will be a list of characters. |
- """ |
- return list(value) |
- |
- |
-def do_mark_safe(value): |
- """Mark the value as safe which means that in an environment with automatic |
- escaping enabled this variable will not be escaped. |
- """ |
- return Markup(value) |
- |
- |
-def do_mark_unsafe(value): |
- """Mark a value as unsafe. This is the reverse operation for :func:`safe`.""" |
- return text_type(value) |
- |
- |
-def do_reverse(value): |
- """Reverse the object or return an iterator the iterates over it the other |
- way round. |
- """ |
- if isinstance(value, string_types): |
- return value[::-1] |
- try: |
- return reversed(value) |
- except TypeError: |
- try: |
- rv = list(value) |
- rv.reverse() |
- return rv |
- except TypeError: |
- raise FilterArgumentError('argument must be iterable') |
- |
- |
-@environmentfilter |
-def do_attr(environment, obj, name): |
- """Get an attribute of an object. ``foo|attr("bar")`` works like |
- ``foo["bar"]`` just that always an attribute is returned and items are not |
- looked up. |
- |
- See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details. |
- """ |
- try: |
- name = str(name) |
- except UnicodeError: |
- pass |
- else: |
- try: |
- value = getattr(obj, name) |
- except AttributeError: |
- pass |
- else: |
- if environment.sandboxed and not \ |
- environment.is_safe_attribute(obj, name, value): |
- return environment.unsafe_undefined(obj, name) |
- return value |
- return environment.undefined(obj=obj, name=name) |
- |
- |
-@contextfilter |
-def do_map(*args, **kwargs): |
- """Applies a filter on a sequence of objects or looks up an attribute. |
- This is useful when dealing with lists of objects but you are really |
- only interested in a certain value of it. |
- |
- The basic usage is mapping on an attribute. Imagine you have a list |
- of users but you are only interested in a list of usernames: |
- |
- .. sourcecode:: jinja |
- |
- Users on this page: {{ users|map(attribute='username')|join(', ') }} |
- |
- Alternatively you can let it invoke a filter by passing the name of the |
- filter and the arguments afterwards. A good example would be applying a |
- text conversion filter on a sequence: |
- |
- .. sourcecode:: jinja |
- |
- Users on this page: {{ titles|map('lower')|join(', ') }} |
- |
- .. versionadded:: 2.7 |
- """ |
- context = args[0] |
- seq = args[1] |
- |
- if len(args) == 2 and 'attribute' in kwargs: |
- attribute = kwargs.pop('attribute') |
- if kwargs: |
- raise FilterArgumentError('Unexpected keyword argument %r' % |
- next(iter(kwargs))) |
- func = make_attrgetter(context.environment, attribute) |
- else: |
- try: |
- name = args[2] |
- args = args[3:] |
- except LookupError: |
- raise FilterArgumentError('map requires a filter argument') |
- func = lambda item: context.environment.call_filter( |
- name, item, args, kwargs, context=context) |
- |
- if seq: |
- for item in seq: |
- yield func(item) |
- |
- |
-@contextfilter |
-def do_select(*args, **kwargs): |
- """Filters a sequence of objects by appying a test to either the object |
- or the attribute and only selecting the ones with the test succeeding. |
- |
- Example usage: |
- |
- .. sourcecode:: jinja |
- |
- {{ numbers|select("odd") }} |
- |
- .. versionadded:: 2.7 |
- """ |
- return _select_or_reject(args, kwargs, lambda x: x, False) |
- |
- |
-@contextfilter |
-def do_reject(*args, **kwargs): |
- """Filters a sequence of objects by appying a test to either the object |
- or the attribute and rejecting the ones with the test succeeding. |
- |
- Example usage: |
- |
- .. sourcecode:: jinja |
- |
- {{ numbers|reject("odd") }} |
- |
- .. versionadded:: 2.7 |
- """ |
- return _select_or_reject(args, kwargs, lambda x: not x, False) |
- |
- |
-@contextfilter |
-def do_selectattr(*args, **kwargs): |
- """Filters a sequence of objects by appying a test to either the object |
- or the attribute and only selecting the ones with the test succeeding. |
- |
- Example usage: |
- |
- .. sourcecode:: jinja |
- |
- {{ users|selectattr("is_active") }} |
- {{ users|selectattr("email", "none") }} |
- |
- .. versionadded:: 2.7 |
- """ |
- return _select_or_reject(args, kwargs, lambda x: x, True) |
- |
- |
-@contextfilter |
-def do_rejectattr(*args, **kwargs): |
- """Filters a sequence of objects by appying a test to either the object |
- or the attribute and rejecting the ones with the test succeeding. |
- |
- .. sourcecode:: jinja |
- |
- {{ users|rejectattr("is_active") }} |
- {{ users|rejectattr("email", "none") }} |
- |
- .. versionadded:: 2.7 |
- """ |
- return _select_or_reject(args, kwargs, lambda x: not x, True) |
- |
- |
-def _select_or_reject(args, kwargs, modfunc, lookup_attr): |
- context = args[0] |
- seq = args[1] |
- if lookup_attr: |
- try: |
- attr = args[2] |
- except LookupError: |
- raise FilterArgumentError('Missing parameter for attribute name') |
- transfunc = make_attrgetter(context.environment, attr) |
- off = 1 |
- else: |
- off = 0 |
- transfunc = lambda x: x |
- |
- try: |
- name = args[2 + off] |
- args = args[3 + off:] |
- func = lambda item: context.environment.call_test( |
- name, item, args, kwargs) |
- except LookupError: |
- func = bool |
- |
- if seq: |
- for item in seq: |
- if modfunc(func(transfunc(item))): |
- yield item |
- |
- |
-FILTERS = { |
- 'attr': do_attr, |
- 'replace': do_replace, |
- 'upper': do_upper, |
- 'lower': do_lower, |
- 'escape': escape, |
- 'e': escape, |
- 'forceescape': do_forceescape, |
- 'capitalize': do_capitalize, |
- 'title': do_title, |
- 'default': do_default, |
- 'd': do_default, |
- 'join': do_join, |
- 'count': len, |
- 'dictsort': do_dictsort, |
- 'sort': do_sort, |
- 'length': len, |
- 'reverse': do_reverse, |
- 'center': do_center, |
- 'indent': do_indent, |
- 'title': do_title, |
- 'capitalize': do_capitalize, |
- 'first': do_first, |
- 'last': do_last, |
- 'map': do_map, |
- 'random': do_random, |
- 'reject': do_reject, |
- 'rejectattr': do_rejectattr, |
- 'filesizeformat': do_filesizeformat, |
- 'pprint': do_pprint, |
- 'truncate': do_truncate, |
- 'wordwrap': do_wordwrap, |
- 'wordcount': do_wordcount, |
- 'int': do_int, |
- 'float': do_float, |
- 'string': soft_unicode, |
- 'list': do_list, |
- 'urlize': do_urlize, |
- 'format': do_format, |
- 'trim': do_trim, |
- 'striptags': do_striptags, |
- 'select': do_select, |
- 'selectattr': do_selectattr, |
- 'slice': do_slice, |
- 'batch': do_batch, |
- 'sum': do_sum, |
- 'abs': abs, |
- 'round': do_round, |
- 'groupby': do_groupby, |
- 'safe': do_mark_safe, |
- 'xmlattr': do_xmlattr, |
- 'urlencode': do_urlencode |
-} |