| Index: third_party/jinja2/filters.py
|
| diff --git a/third_party/jinja2/filters.py b/third_party/jinja2/filters.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..1ef47f95161b7ef8f07dcd79bc86dc3582f6c985
|
| --- /dev/null
|
| +++ b/third_party/jinja2/filters.py
|
| @@ -0,0 +1,801 @@
|
| +# -*- 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 imap, groupby
|
| +from jinja2.utils import Markup, escape, pformat, urlize, soft_unicode
|
| +from jinja2.runtime import Undefined
|
| +from jinja2.exceptions import FilterArgumentError, SecurityError
|
| +
|
| +
|
| +_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.
|
| + """
|
| + if not isinstance(attribute, basestring) or '.' not in attribute:
|
| + return lambda x: environment.getitem(x, attribute)
|
| + attribute = attribute.split('.')
|
| + def attrgetter(item):
|
| + for part in attribute:
|
| + 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(unicode(value))
|
| +
|
| +
|
| +@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 unicode(s).replace(unicode(old), unicode(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 d.iteritems()
|
| + 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.
|
| + """
|
| + return soft_unicode(s).title()
|
| +
|
| +
|
| +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|dicsort(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, basestring) 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, basestring):
|
| + 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 (boolean and not value) or isinstance(value, Undefined):
|
| + 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 unicode(d).join(imap(unicode, 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] = unicode(item)
|
| + if do_escape:
|
| + d = escape(d)
|
| + else:
|
| + d = unicode(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 unicode(value).center(width)
|
| +
|
| +
|
| +@environmentfilter
|
| +def do_first(environment, seq):
|
| + """Return the first item of a sequence."""
|
| + try:
|
| + return iter(seq).next()
|
| + 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 iter(reversed(seq)).next()
|
| + 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 * base ** (i + 1)
|
| + if bytes < unit:
|
| + return "%.1f %s" % ((bytes / unit), prefix)
|
| + return "%.1f %s" % ((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 try to save 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::
|
| +
|
| + {{ mytext|truncate(300, false, '»') }}
|
| + truncate mytext to 300 chars, don't split up words, use a
|
| + right pointing double arrow as ellipsis sign.
|
| + """
|
| + 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):
|
| + """
|
| + 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`.
|
| + """
|
| + import textwrap
|
| + return environment.newline_sequence.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(unicode(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 xrange(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 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, (key, value)):
|
| + 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 unicode(value)
|
| +
|
| +
|
| +def do_reverse(value):
|
| + """Reverse the object or return an iterator the iterates over it the other
|
| + way round.
|
| + """
|
| + if isinstance(value, basestring):
|
| + 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)
|
| +
|
| +
|
| +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,
|
| + 'random': do_random,
|
| + '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,
|
| + 'slice': do_slice,
|
| + 'batch': do_batch,
|
| + 'sum': do_sum,
|
| + 'abs': abs,
|
| + 'round': do_round,
|
| + 'groupby': do_groupby,
|
| + 'safe': do_mark_safe,
|
| + 'xmlattr': do_xmlattr
|
| +}
|
|
|