Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(73)

Side by Side Diff: third_party/jinja2/filters.py

Issue 2316103002: binding: Updates Jinja2 from 2.7.1 to 2.8. (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/jinja2/ext.py ('k') | third_party/jinja2/get_jinja2.sh » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 """ 2 """
3 jinja2.filters 3 jinja2.filters
4 ~~~~~~~~~~~~~~ 4 ~~~~~~~~~~~~~~
5 5
6 Bundled jinja filters. 6 Bundled jinja filters.
7 7
8 :copyright: (c) 2010 by the Jinja Team. 8 :copyright: (c) 2010 by the Jinja Team.
9 :license: BSD, see LICENSE for more details. 9 :license: BSD, see LICENSE for more details.
10 """ 10 """
11 import re 11 import re
12 import math 12 import math
13 13
14 from random import choice 14 from random import choice
15 from operator import itemgetter 15 from operator import itemgetter
16 from itertools import groupby 16 from itertools import groupby
17 from jinja2.utils import Markup, escape, pformat, urlize, soft_unicode, \ 17 from jinja2.utils import Markup, escape, pformat, urlize, soft_unicode, \
18 unicode_urlencode 18 unicode_urlencode
19 from jinja2.runtime import Undefined 19 from jinja2.runtime import Undefined
20 from jinja2.exceptions import FilterArgumentError 20 from jinja2.exceptions import FilterArgumentError
21 from jinja2._compat import next, imap, string_types, text_type, iteritems 21 from jinja2._compat import imap, string_types, text_type, iteritems
22 22
23 23
24 _word_re = re.compile(r'\w+(?u)') 24 _word_re = re.compile(r'\w+(?u)')
25 25
26 26
27 def contextfilter(f): 27 def contextfilter(f):
28 """Decorator for marking context dependent filters. The current 28 """Decorator for marking context dependent filters. The current
29 :class:`Context` will be passed as first argument. 29 :class:`Context` will be passed as first argument.
30 """ 30 """
31 f.contextfilter = True 31 f.contextfilter = True
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
87 if isinstance(value, dict): 87 if isinstance(value, dict):
88 itemiter = iteritems(value) 88 itemiter = iteritems(value)
89 elif not isinstance(value, string_types): 89 elif not isinstance(value, string_types):
90 try: 90 try:
91 itemiter = iter(value) 91 itemiter = iter(value)
92 except TypeError: 92 except TypeError:
93 pass 93 pass
94 if itemiter is None: 94 if itemiter is None:
95 return unicode_urlencode(value) 95 return unicode_urlencode(value)
96 return u'&'.join(unicode_urlencode(k) + '=' + 96 return u'&'.join(unicode_urlencode(k) + '=' +
97 unicode_urlencode(v) for k, v in itemiter) 97 unicode_urlencode(v, for_qs=True)
98 for k, v in itemiter)
98 99
99 100
100 @evalcontextfilter 101 @evalcontextfilter
101 def do_replace(eval_ctx, s, old, new, count=None): 102 def do_replace(eval_ctx, s, old, new, count=None):
102 """Return a copy of the value with all occurrences of a substring 103 """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 replaced with a new one. The first argument is the substring
104 that should be replaced, the second is the replacement string. 105 that should be replaced, the second is the replacement string.
105 If the optional third argument ``count`` is given, only the first 106 If the optional third argument ``count`` is given, only the first
106 ``count`` occurrences are replaced: 107 ``count`` occurrences are replaced:
107 108
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
176 lowercase. 177 lowercase.
177 """ 178 """
178 return soft_unicode(s).capitalize() 179 return soft_unicode(s).capitalize()
179 180
180 181
181 def do_title(s): 182 def do_title(s):
182 """Return a titlecased version of the value. I.e. words will start with 183 """Return a titlecased version of the value. I.e. words will start with
183 uppercase letters, all remaining characters are lowercase. 184 uppercase letters, all remaining characters are lowercase.
184 """ 185 """
185 rv = [] 186 rv = []
186 for item in re.compile(r'([-\s]+)(?u)').split(s): 187 for item in re.compile(r'([-\s]+)(?u)').split(soft_unicode(s)):
187 if not item: 188 if not item:
188 continue 189 continue
189 rv.append(item[0].upper() + item[1:].lower()) 190 rv.append(item[0].upper() + item[1:].lower())
190 return ''.join(rv) 191 return ''.join(rv)
191 192
192 193
193 def do_dictsort(value, case_sensitive=False, by='key'): 194 def do_dictsort(value, case_sensitive=False, by='key'):
194 """Sort a dict and yield (key, value) pairs. Because python dicts are 195 """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 unsorted you may want to use this function to order them by either
196 key or value: 197 key or value:
197 198
198 .. sourcecode:: jinja 199 .. sourcecode:: jinja
199 200
200 {% for item in mydict|dictsort %} 201 {% for item in mydict|dictsort %}
201 sort the dict by key, case insensitive 202 sort the dict by key, case insensitive
202 203
203 {% for item in mydict|dictsort(true) %} 204 {% for item in mydict|dictsort(true) %}
204 sort the dict by key, case sensitive 205 sort the dict by key, case sensitive
205 206
206 {% for item in mydict|dictsort(false, 'value') %} 207 {% for item in mydict|dictsort(false, 'value') %}
207 sort the dict by key, case insensitive, sorted 208 sort the dict by value, case insensitive
208 normally and ordered by value.
209 """ 209 """
210 if by == 'key': 210 if by == 'key':
211 pos = 0 211 pos = 0
212 elif by == 'value': 212 elif by == 'value':
213 pos = 1 213 pos = 1
214 else: 214 else:
215 raise FilterArgumentError('You can only sort by either ' 215 raise FilterArgumentError('You can only sort by either '
216 '"key" or "value"') 216 '"key" or "value"')
217 def sort_func(item): 217 def sort_func(item):
218 value = item[pos] 218 value = item[pos]
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
402 def do_pprint(value, verbose=False): 402 def do_pprint(value, verbose=False):
403 """Pretty print a variable. Useful for debugging. 403 """Pretty print a variable. Useful for debugging.
404 404
405 With Jinja 1.2 onwards you can pass it a parameter. If this parameter 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`) 406 is truthy the output will be more verbose (this requires `pretty`)
407 """ 407 """
408 return pformat(value, verbose=verbose) 408 return pformat(value, verbose=verbose)
409 409
410 410
411 @evalcontextfilter 411 @evalcontextfilter
412 def do_urlize(eval_ctx, value, trim_url_limit=None, nofollow=False): 412 def do_urlize(eval_ctx, value, trim_url_limit=None, nofollow=False,
413 target=None):
413 """Converts URLs in plain text into clickable links. 414 """Converts URLs in plain text into clickable links.
414 415
415 If you pass the filter an additional integer it will shorten the urls 416 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 to that number. Also a third argument exists that makes the urls
417 "nofollow": 418 "nofollow":
418 419
419 .. sourcecode:: jinja 420 .. sourcecode:: jinja
420 421
421 {{ mytext|urlize(40, true) }} 422 {{ mytext|urlize(40, true) }}
422 links are shortened to 40 chars and defined with rel="nofollow" 423 links are shortened to 40 chars and defined with rel="nofollow"
424
425 If *target* is specified, the ``target`` attribute will be added to the
426 ``<a>`` tag:
427
428 .. sourcecode:: jinja
429
430 {{ mytext|urlize(40, target='_blank') }}
431
432 .. versionchanged:: 2.8+
433 The *target* parameter was added.
423 """ 434 """
424 rv = urlize(value, trim_url_limit, nofollow) 435 rv = urlize(value, trim_url_limit, nofollow, target)
425 if eval_ctx.autoescape: 436 if eval_ctx.autoescape:
426 rv = Markup(rv) 437 rv = Markup(rv)
427 return rv 438 return rv
428 439
429 440
430 def do_indent(s, width=4, indentfirst=False): 441 def do_indent(s, width=4, indentfirst=False):
431 """Return a copy of the passed string, each line indented by 442 """Return a copy of the passed string, each line indented by
432 4 spaces. The first line is not indented. If you want to 443 4 spaces. The first line is not indented. If you want to
433 change the number of spaces or indent the first line too 444 change the number of spaces or indent the first line too
434 you can pass additional parameters to the filter: 445 you can pass additional parameters to the filter:
(...skipping 14 matching lines...) Expand all
449 """Return a truncated copy of the string. The length is specified 460 """Return a truncated copy of the string. The length is specified
450 with the first parameter which defaults to ``255``. If the second 461 with the first parameter which defaults to ``255``. If the second
451 parameter is ``true`` the filter will cut the text at length. Otherwise 462 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 463 it will discard the last word. If the text was in fact
453 truncated it will append an ellipsis sign (``"..."``). If you want a 464 truncated it will append an ellipsis sign (``"..."``). If you want a
454 different ellipsis sign than ``"..."`` you can specify it using the 465 different ellipsis sign than ``"..."`` you can specify it using the
455 third parameter. 466 third parameter.
456 467
457 .. sourcecode:: jinja 468 .. sourcecode:: jinja
458 469
459 {{ "foo bar"|truncate(5) }} 470 {{ "foo bar baz"|truncate(9) }}
460 -> "foo ..." 471 -> "foo ..."
461 {{ "foo bar"|truncate(5, True) }} 472 {{ "foo bar baz"|truncate(9, True) }}
462 -> "foo b..." 473 -> "foo ba..."
474
463 """ 475 """
464 if len(s) <= length: 476 if len(s) <= length:
465 return s 477 return s
466 elif killwords: 478 elif killwords:
467 return s[:length] + end 479 return s[:length - len(end)] + end
468 words = s.split(' ') 480
469 result = [] 481 result = s[:length - len(end)].rsplit(' ', 1)[0]
470 m = 0 482 if len(result) < length:
471 for word in words: 483 result += ' '
472 m += len(word) + 1 484 return result + end
473 if m > length: 485
474 break
475 result.append(word)
476 result.append(end)
477 return u' '.join(result)
478 486
479 @environmentfilter 487 @environmentfilter
480 def do_wordwrap(environment, s, width=79, break_long_words=True, 488 def do_wordwrap(environment, s, width=79, break_long_words=True,
481 wrapstring=None): 489 wrapstring=None):
482 """ 490 """
483 Return a copy of the string passed to the filter wrapped after 491 Return a copy of the string passed to the filter wrapped after
484 ``79`` characters. You can override this default using the first 492 ``79`` characters. You can override this default using the first
485 parameter. If you set the second parameter to `false` Jinja will not 493 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 494 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 495 will be the default newlines for the environment, but this can be changed
488 using the wrapstring keyword argument. 496 using the wrapstring keyword argument.
489 497
490 .. versionadded:: 2.7 498 .. versionadded:: 2.7
491 Added support for the `wrapstring` parameter. 499 Added support for the `wrapstring` parameter.
492 """ 500 """
493 if not wrapstring: 501 if not wrapstring:
494 wrapstring = environment.newline_sequence 502 wrapstring = environment.newline_sequence
495 import textwrap 503 import textwrap
496 return wrapstring.join(textwrap.wrap(s, width=width, expand_tabs=False, 504 return wrapstring.join(textwrap.wrap(s, width=width, expand_tabs=False,
497 replace_whitespace=False, 505 replace_whitespace=False,
498 break_long_words=break_long_words)) 506 break_long_words=break_long_words))
499 507
500 508
501 def do_wordcount(s): 509 def do_wordcount(s):
502 """Count the words in that string.""" 510 """Count the words in that string."""
503 return len(_word_re.findall(s)) 511 return len(_word_re.findall(s))
504 512
505 513
506 def do_int(value, default=0): 514 def do_int(value, default=0, base=10):
507 """Convert the value into an integer. If the 515 """Convert the value into an integer. If the
508 conversion doesn't work it will return ``0``. You can 516 conversion doesn't work it will return ``0``. You can
509 override this default using the first parameter. 517 override this default using the first parameter. You
518 can also override the default base (10) in the second
519 parameter, which handles input with prefixes such as
520 0b, 0o and 0x for bases 2, 8 and 16 respectively.
510 """ 521 """
511 try: 522 try:
512 return int(value) 523 return int(value, base)
513 except (TypeError, ValueError): 524 except (TypeError, ValueError):
514 # this quirk is necessary so that "42.23"|int gives 42. 525 # this quirk is necessary so that "42.23"|int gives 42.
515 try: 526 try:
516 return int(float(value)) 527 return int(float(value))
517 except (TypeError, ValueError): 528 except (TypeError, ValueError):
518 return default 529 return default
519 530
520 531
521 def do_float(value, default=0.0): 532 def do_float(value, default=0.0):
522 """Convert the value into a floating point number. If the 533 """Convert the value into a floating point number. If the
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
605 <table> 616 <table>
606 {%- for row in items|batch(3, '&nbsp;') %} 617 {%- for row in items|batch(3, '&nbsp;') %}
607 <tr> 618 <tr>
608 {%- for column in row %} 619 {%- for column in row %}
609 <td>{{ column }}</td> 620 <td>{{ column }}</td>
610 {%- endfor %} 621 {%- endfor %}
611 </tr> 622 </tr>
612 {%- endfor %} 623 {%- endfor %}
613 </table> 624 </table>
614 """ 625 """
615 result = []
616 tmp = [] 626 tmp = []
617 for item in value: 627 for item in value:
618 if len(tmp) == linecount: 628 if len(tmp) == linecount:
619 yield tmp 629 yield tmp
620 tmp = [] 630 tmp = []
621 tmp.append(item) 631 tmp.append(item)
622 if tmp: 632 if tmp:
623 if fill_with is not None and len(tmp) < linecount: 633 if fill_with is not None and len(tmp) < linecount:
624 tmp += [fill_with] * (linecount - len(tmp)) 634 tmp += [fill_with] * (linecount - len(tmp))
625 yield tmp 635 yield tmp
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
746 """ 756 """
747 return Markup(value) 757 return Markup(value)
748 758
749 759
750 def do_mark_unsafe(value): 760 def do_mark_unsafe(value):
751 """Mark a value as unsafe. This is the reverse operation for :func:`safe`." "" 761 """Mark a value as unsafe. This is the reverse operation for :func:`safe`." ""
752 return text_type(value) 762 return text_type(value)
753 763
754 764
755 def do_reverse(value): 765 def do_reverse(value):
756 """Reverse the object or return an iterator the iterates over it the other 766 """Reverse the object or return an iterator that iterates over it the other
757 way round. 767 way round.
758 """ 768 """
759 if isinstance(value, string_types): 769 if isinstance(value, string_types):
760 return value[::-1] 770 return value[::-1]
761 try: 771 try:
762 return reversed(value) 772 return reversed(value)
763 except TypeError: 773 except TypeError:
764 try: 774 try:
765 rv = list(value) 775 rv = list(value)
766 rv.reverse() 776 rv.reverse()
767 return rv 777 return rv
768 except TypeError: 778 except TypeError:
769 raise FilterArgumentError('argument must be iterable') 779 raise FilterArgumentError('argument must be iterable')
770 780
771 781
772 @environmentfilter 782 @environmentfilter
773 def do_attr(environment, obj, name): 783 def do_attr(environment, obj, name):
774 """Get an attribute of an object. ``foo|attr("bar")`` works like 784 """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 785 ``foo.bar`` just that always an attribute is returned and items are not
776 looked up. 786 looked up.
777 787
778 See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details. 788 See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details.
779 """ 789 """
780 try: 790 try:
781 name = str(name) 791 name = str(name)
782 except UnicodeError: 792 except UnicodeError:
783 pass 793 pass
784 else: 794 else:
785 try: 795 try:
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
835 func = lambda item: context.environment.call_filter( 845 func = lambda item: context.environment.call_filter(
836 name, item, args, kwargs, context=context) 846 name, item, args, kwargs, context=context)
837 847
838 if seq: 848 if seq:
839 for item in seq: 849 for item in seq:
840 yield func(item) 850 yield func(item)
841 851
842 852
843 @contextfilter 853 @contextfilter
844 def do_select(*args, **kwargs): 854 def do_select(*args, **kwargs):
845 """Filters a sequence of objects by appying a test to either the object 855 """Filters a sequence of objects by applying a test to the object and only
846 or the attribute and only selecting the ones with the test succeeding. 856 selecting the ones with the test succeeding.
847 857
848 Example usage: 858 Example usage:
849 859
850 .. sourcecode:: jinja 860 .. sourcecode:: jinja
851 861
852 {{ numbers|select("odd") }} 862 {{ numbers|select("odd") }}
863 {{ numbers|select("odd") }}
853 864
854 .. versionadded:: 2.7 865 .. versionadded:: 2.7
855 """ 866 """
856 return _select_or_reject(args, kwargs, lambda x: x, False) 867 return _select_or_reject(args, kwargs, lambda x: x, False)
857 868
858 869
859 @contextfilter 870 @contextfilter
860 def do_reject(*args, **kwargs): 871 def do_reject(*args, **kwargs):
861 """Filters a sequence of objects by appying a test to either the object 872 """Filters a sequence of objects by applying a test to the object and
862 or the attribute and rejecting the ones with the test succeeding. 873 rejecting the ones with the test succeeding.
863 874
864 Example usage: 875 Example usage:
865 876
866 .. sourcecode:: jinja 877 .. sourcecode:: jinja
867 878
868 {{ numbers|reject("odd") }} 879 {{ numbers|reject("odd") }}
869 880
870 .. versionadded:: 2.7 881 .. versionadded:: 2.7
871 """ 882 """
872 return _select_or_reject(args, kwargs, lambda x: not x, False) 883 return _select_or_reject(args, kwargs, lambda x: not x, False)
873 884
874 885
875 @contextfilter 886 @contextfilter
876 def do_selectattr(*args, **kwargs): 887 def do_selectattr(*args, **kwargs):
877 """Filters a sequence of objects by appying a test to either the object 888 """Filters a sequence of objects by applying a test to an attribute of an
878 or the attribute and only selecting the ones with the test succeeding. 889 object and only selecting the ones with the test succeeding.
879 890
880 Example usage: 891 Example usage:
881 892
882 .. sourcecode:: jinja 893 .. sourcecode:: jinja
883 894
884 {{ users|selectattr("is_active") }} 895 {{ users|selectattr("is_active") }}
885 {{ users|selectattr("email", "none") }} 896 {{ users|selectattr("email", "none") }}
886 897
887 .. versionadded:: 2.7 898 .. versionadded:: 2.7
888 """ 899 """
889 return _select_or_reject(args, kwargs, lambda x: x, True) 900 return _select_or_reject(args, kwargs, lambda x: x, True)
890 901
891 902
892 @contextfilter 903 @contextfilter
893 def do_rejectattr(*args, **kwargs): 904 def do_rejectattr(*args, **kwargs):
894 """Filters a sequence of objects by appying a test to either the object 905 """Filters a sequence of objects by applying a test to an attribute of an
895 or the attribute and rejecting the ones with the test succeeding. 906 object or the attribute and rejecting the ones with the test succeeding.
896 907
897 .. sourcecode:: jinja 908 .. sourcecode:: jinja
898 909
899 {{ users|rejectattr("is_active") }} 910 {{ users|rejectattr("is_active") }}
900 {{ users|rejectattr("email", "none") }} 911 {{ users|rejectattr("email", "none") }}
901 912
902 .. versionadded:: 2.7 913 .. versionadded:: 2.7
903 """ 914 """
904 return _select_or_reject(args, kwargs, lambda x: not x, True) 915 return _select_or_reject(args, kwargs, lambda x: not x, True)
905 916
(...skipping 20 matching lines...) Expand all
926 except LookupError: 937 except LookupError:
927 func = bool 938 func = bool
928 939
929 if seq: 940 if seq:
930 for item in seq: 941 for item in seq:
931 if modfunc(func(transfunc(item))): 942 if modfunc(func(transfunc(item))):
932 yield item 943 yield item
933 944
934 945
935 FILTERS = { 946 FILTERS = {
947 'abs': abs,
936 'attr': do_attr, 948 'attr': do_attr,
937 'replace': do_replace, 949 'batch': do_batch,
938 'upper': do_upper, 950 'capitalize': do_capitalize,
951 'center': do_center,
952 'count': len,
953 'd': do_default,
954 'default': do_default,
955 'dictsort': do_dictsort,
956 'e': escape,
957 'escape': escape,
958 'filesizeformat': do_filesizeformat,
959 'first': do_first,
960 'float': do_float,
961 'forceescape': do_forceescape,
962 'format': do_format,
963 'groupby': do_groupby,
964 'indent': do_indent,
965 'int': do_int,
966 'join': do_join,
967 'last': do_last,
968 'length': len,
969 'list': do_list,
939 'lower': do_lower, 970 '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, 971 'map': do_map,
972 'pprint': do_pprint,
960 'random': do_random, 973 'random': do_random,
961 'reject': do_reject, 974 'reject': do_reject,
962 'rejectattr': do_rejectattr, 975 'rejectattr': do_rejectattr,
963 'filesizeformat': do_filesizeformat, 976 'replace': do_replace,
964 'pprint': do_pprint, 977 'reverse': do_reverse,
965 'truncate': do_truncate, 978 'round': do_round,
966 'wordwrap': do_wordwrap, 979 'safe': do_mark_safe,
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, 980 'select': do_select,
977 'selectattr': do_selectattr, 981 'selectattr': do_selectattr,
978 'slice': do_slice, 982 'slice': do_slice,
979 'batch': do_batch, 983 'sort': do_sort,
984 'string': soft_unicode,
985 'striptags': do_striptags,
980 'sum': do_sum, 986 'sum': do_sum,
981 'abs': abs, 987 'title': do_title,
982 'round': do_round, 988 'trim': do_trim,
983 'groupby': do_groupby, 989 'truncate': do_truncate,
984 'safe': do_mark_safe, 990 'upper': do_upper,
991 'urlencode': do_urlencode,
992 'urlize': do_urlize,
993 'wordcount': do_wordcount,
994 'wordwrap': do_wordwrap,
985 'xmlattr': do_xmlattr, 995 'xmlattr': do_xmlattr,
986 'urlencode': do_urlencode
987 } 996 }
OLDNEW
« no previous file with comments | « third_party/jinja2/ext.py ('k') | third_party/jinja2/get_jinja2.sh » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698