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 |
+} |