1# -*- coding: utf-8 -*- 2"""Built-in template filters used with the ``|`` operator.""" 3import math 4import random 5import re 6import warnings 7from collections import namedtuple 8from itertools import chain 9from itertools import groupby 10 11from markupsafe import escape 12from markupsafe import Markup 13from markupsafe import soft_unicode 14 15from ._compat import abc 16from ._compat import imap 17from ._compat import iteritems 18from ._compat import string_types 19from ._compat import text_type 20from .exceptions import FilterArgumentError 21from .runtime import Undefined 22from .utils import htmlsafe_json_dumps 23from .utils import pformat 24from .utils import unicode_urlencode 25from .utils import urlize 26 27_word_re = re.compile(r"\w+", re.UNICODE) 28_word_beginning_split_re = re.compile(r"([-\s\(\{\[\<]+)", re.UNICODE) 29 30 31def contextfilter(f): 32 """Decorator for marking context dependent filters. The current 33 :class:`Context` will be passed as first argument. 34 """ 35 f.contextfilter = True 36 return f 37 38 39def evalcontextfilter(f): 40 """Decorator for marking eval-context dependent filters. An eval 41 context object is passed as first argument. For more information 42 about the eval context, see :ref:`eval-context`. 43 44 .. versionadded:: 2.4 45 """ 46 f.evalcontextfilter = True 47 return f 48 49 50def environmentfilter(f): 51 """Decorator for marking environment dependent filters. The current 52 :class:`Environment` is passed to the filter as first argument. 53 """ 54 f.environmentfilter = True 55 return f 56 57 58def ignore_case(value): 59 """For use as a postprocessor for :func:`make_attrgetter`. Converts strings 60 to lowercase and returns other types as-is.""" 61 return value.lower() if isinstance(value, string_types) else value 62 63 64def make_attrgetter(environment, attribute, postprocess=None, default=None): 65 """Returns a callable that looks up the given attribute from a 66 passed object with the rules of the environment. Dots are allowed 67 to access attributes of attributes. Integer parts in paths are 68 looked up as integers. 69 """ 70 attribute = _prepare_attribute_parts(attribute) 71 72 def attrgetter(item): 73 for part in attribute: 74 item = environment.getitem(item, part) 75 76 if default and isinstance(item, Undefined): 77 item = default 78 79 if postprocess is not None: 80 item = postprocess(item) 81 82 return item 83 84 return attrgetter 85 86 87def make_multi_attrgetter(environment, attribute, postprocess=None): 88 """Returns a callable that looks up the given comma separated 89 attributes from a passed object with the rules of the environment. 90 Dots are allowed to access attributes of each attribute. Integer 91 parts in paths are looked up as integers. 92 93 The value returned by the returned callable is a list of extracted 94 attribute values. 95 96 Examples of attribute: "attr1,attr2", "attr1.inner1.0,attr2.inner2.0", etc. 97 """ 98 attribute_parts = ( 99 attribute.split(",") if isinstance(attribute, string_types) else [attribute] 100 ) 101 attribute = [ 102 _prepare_attribute_parts(attribute_part) for attribute_part in attribute_parts 103 ] 104 105 def attrgetter(item): 106 items = [None] * len(attribute) 107 for i, attribute_part in enumerate(attribute): 108 item_i = item 109 for part in attribute_part: 110 item_i = environment.getitem(item_i, part) 111 112 if postprocess is not None: 113 item_i = postprocess(item_i) 114 115 items[i] = item_i 116 return items 117 118 return attrgetter 119 120 121def _prepare_attribute_parts(attr): 122 if attr is None: 123 return [] 124 elif isinstance(attr, string_types): 125 return [int(x) if x.isdigit() else x for x in attr.split(".")] 126 else: 127 return [attr] 128 129 130def do_forceescape(value): 131 """Enforce HTML escaping. This will probably double escape variables.""" 132 if hasattr(value, "__html__"): 133 value = value.__html__() 134 return escape(text_type(value)) 135 136 137def do_urlencode(value): 138 """Quote data for use in a URL path or query using UTF-8. 139 140 Basic wrapper around :func:`urllib.parse.quote` when given a 141 string, or :func:`urllib.parse.urlencode` for a dict or iterable. 142 143 :param value: Data to quote. A string will be quoted directly. A 144 dict or iterable of ``(key, value)`` pairs will be joined as a 145 query string. 146 147 When given a string, "/" is not quoted. HTTP servers treat "/" and 148 "%2F" equivalently in paths. If you need quoted slashes, use the 149 ``|replace("/", "%2F")`` filter. 150 151 .. versionadded:: 2.7 152 """ 153 if isinstance(value, string_types) or not isinstance(value, abc.Iterable): 154 return unicode_urlencode(value) 155 156 if isinstance(value, dict): 157 items = iteritems(value) 158 else: 159 items = iter(value) 160 161 return u"&".join( 162 "%s=%s" % (unicode_urlencode(k, for_qs=True), unicode_urlencode(v, for_qs=True)) 163 for k, v in items 164 ) 165 166 167@evalcontextfilter 168def do_replace(eval_ctx, s, old, new, count=None): 169 """Return a copy of the value with all occurrences of a substring 170 replaced with a new one. The first argument is the substring 171 that should be replaced, the second is the replacement string. 172 If the optional third argument ``count`` is given, only the first 173 ``count`` occurrences are replaced: 174 175 .. sourcecode:: jinja 176 177 {{ "Hello World"|replace("Hello", "Goodbye") }} 178 -> Goodbye World 179 180 {{ "aaaaargh"|replace("a", "d'oh, ", 2) }} 181 -> d'oh, d'oh, aaargh 182 """ 183 if count is None: 184 count = -1 185 if not eval_ctx.autoescape: 186 return text_type(s).replace(text_type(old), text_type(new), count) 187 if ( 188 hasattr(old, "__html__") 189 or hasattr(new, "__html__") 190 and not hasattr(s, "__html__") 191 ): 192 s = escape(s) 193 else: 194 s = soft_unicode(s) 195 return s.replace(soft_unicode(old), soft_unicode(new), count) 196 197 198def do_upper(s): 199 """Convert a value to uppercase.""" 200 return soft_unicode(s).upper() 201 202 203def do_lower(s): 204 """Convert a value to lowercase.""" 205 return soft_unicode(s).lower() 206 207 208@evalcontextfilter 209def do_xmlattr(_eval_ctx, d, autospace=True): 210 """Create an SGML/XML attribute string based on the items in a dict. 211 All values that are neither `none` nor `undefined` are automatically 212 escaped: 213 214 .. sourcecode:: html+jinja 215 216 <ul{{ {'class': 'my_list', 'missing': none, 217 'id': 'list-%d'|format(variable)}|xmlattr }}> 218 ... 219 </ul> 220 221 Results in something like this: 222 223 .. sourcecode:: html 224 225 <ul class="my_list" id="list-42"> 226 ... 227 </ul> 228 229 As you can see it automatically prepends a space in front of the item 230 if the filter returned something unless the second parameter is false. 231 """ 232 rv = u" ".join( 233 u'%s="%s"' % (escape(key), escape(value)) 234 for key, value in iteritems(d) 235 if value is not None and not isinstance(value, Undefined) 236 ) 237 if autospace and rv: 238 rv = u" " + rv 239 if _eval_ctx.autoescape: 240 rv = Markup(rv) 241 return rv 242 243 244def do_capitalize(s): 245 """Capitalize a value. The first character will be uppercase, all others 246 lowercase. 247 """ 248 return soft_unicode(s).capitalize() 249 250 251def do_title(s): 252 """Return a titlecased version of the value. I.e. words will start with 253 uppercase letters, all remaining characters are lowercase. 254 """ 255 return "".join( 256 [ 257 item[0].upper() + item[1:].lower() 258 for item in _word_beginning_split_re.split(soft_unicode(s)) 259 if item 260 ] 261 ) 262 263 264def do_dictsort(value, case_sensitive=False, by="key", reverse=False): 265 """Sort a dict and yield (key, value) pairs. Because python dicts are 266 unsorted you may want to use this function to order them by either 267 key or value: 268 269 .. sourcecode:: jinja 270 271 {% for key, value in mydict|dictsort %} 272 sort the dict by key, case insensitive 273 274 {% for key, value in mydict|dictsort(reverse=true) %} 275 sort the dict by key, case insensitive, reverse order 276 277 {% for key, value in mydict|dictsort(true) %} 278 sort the dict by key, case sensitive 279 280 {% for key, value in mydict|dictsort(false, 'value') %} 281 sort the dict by value, case insensitive 282 """ 283 if by == "key": 284 pos = 0 285 elif by == "value": 286 pos = 1 287 else: 288 raise FilterArgumentError('You can only sort by either "key" or "value"') 289 290 def sort_func(item): 291 value = item[pos] 292 293 if not case_sensitive: 294 value = ignore_case(value) 295 296 return value 297 298 return sorted(value.items(), key=sort_func, reverse=reverse) 299 300 301@environmentfilter 302def do_sort(environment, value, reverse=False, case_sensitive=False, attribute=None): 303 """Sort an iterable using Python's :func:`sorted`. 304 305 .. sourcecode:: jinja 306 307 {% for city in cities|sort %} 308 ... 309 {% endfor %} 310 311 :param reverse: Sort descending instead of ascending. 312 :param case_sensitive: When sorting strings, sort upper and lower 313 case separately. 314 :param attribute: When sorting objects or dicts, an attribute or 315 key to sort by. Can use dot notation like ``"address.city"``. 316 Can be a list of attributes like ``"age,name"``. 317 318 The sort is stable, it does not change the relative order of 319 elements that compare equal. This makes it is possible to chain 320 sorts on different attributes and ordering. 321 322 .. sourcecode:: jinja 323 324 {% for user in users|sort(attribute="name") 325 |sort(reverse=true, attribute="age") %} 326 ... 327 {% endfor %} 328 329 As a shortcut to chaining when the direction is the same for all 330 attributes, pass a comma separate list of attributes. 331 332 .. sourcecode:: jinja 333 334 {% for user users|sort(attribute="age,name") %} 335 ... 336 {% endfor %} 337 338 .. versionchanged:: 2.11.0 339 The ``attribute`` parameter can be a comma separated list of 340 attributes, e.g. ``"age,name"``. 341 342 .. versionchanged:: 2.6 343 The ``attribute`` parameter was added. 344 """ 345 key_func = make_multi_attrgetter( 346 environment, attribute, postprocess=ignore_case if not case_sensitive else None 347 ) 348 return sorted(value, key=key_func, reverse=reverse) 349 350 351@environmentfilter 352def do_unique(environment, value, case_sensitive=False, attribute=None): 353 """Returns a list of unique items from the given iterable. 354 355 .. sourcecode:: jinja 356 357 {{ ['foo', 'bar', 'foobar', 'FooBar']|unique|list }} 358 -> ['foo', 'bar', 'foobar'] 359 360 The unique items are yielded in the same order as their first occurrence in 361 the iterable passed to the filter. 362 363 :param case_sensitive: Treat upper and lower case strings as distinct. 364 :param attribute: Filter objects with unique values for this attribute. 365 """ 366 getter = make_attrgetter( 367 environment, attribute, postprocess=ignore_case if not case_sensitive else None 368 ) 369 seen = set() 370 371 for item in value: 372 key = getter(item) 373 374 if key not in seen: 375 seen.add(key) 376 yield item 377 378 379def _min_or_max(environment, value, func, case_sensitive, attribute): 380 it = iter(value) 381 382 try: 383 first = next(it) 384 except StopIteration: 385 return environment.undefined("No aggregated item, sequence was empty.") 386 387 key_func = make_attrgetter( 388 environment, attribute, postprocess=ignore_case if not case_sensitive else None 389 ) 390 return func(chain([first], it), key=key_func) 391 392 393@environmentfilter 394def do_min(environment, value, case_sensitive=False, attribute=None): 395 """Return the smallest item from the sequence. 396 397 .. sourcecode:: jinja 398 399 {{ [1, 2, 3]|min }} 400 -> 1 401 402 :param case_sensitive: Treat upper and lower case strings as distinct. 403 :param attribute: Get the object with the min value of this attribute. 404 """ 405 return _min_or_max(environment, value, min, case_sensitive, attribute) 406 407 408@environmentfilter 409def do_max(environment, value, case_sensitive=False, attribute=None): 410 """Return the largest item from the sequence. 411 412 .. sourcecode:: jinja 413 414 {{ [1, 2, 3]|max }} 415 -> 3 416 417 :param case_sensitive: Treat upper and lower case strings as distinct. 418 :param attribute: Get the object with the max value of this attribute. 419 """ 420 return _min_or_max(environment, value, max, case_sensitive, attribute) 421 422 423def do_default(value, default_value=u"", boolean=False): 424 """If the value is undefined it will return the passed default value, 425 otherwise the value of the variable: 426 427 .. sourcecode:: jinja 428 429 {{ my_variable|default('my_variable is not defined') }} 430 431 This will output the value of ``my_variable`` if the variable was 432 defined, otherwise ``'my_variable is not defined'``. If you want 433 to use default with variables that evaluate to false you have to 434 set the second parameter to `true`: 435 436 .. sourcecode:: jinja 437 438 {{ ''|default('the string was empty', true) }} 439 440 .. versionchanged:: 2.11 441 It's now possible to configure the :class:`~jinja2.Environment` with 442 :class:`~jinja2.ChainableUndefined` to make the `default` filter work 443 on nested elements and attributes that may contain undefined values 444 in the chain without getting an :exc:`~jinja2.UndefinedError`. 445 """ 446 if isinstance(value, Undefined) or (boolean and not value): 447 return default_value 448 return value 449 450 451@evalcontextfilter 452def do_join(eval_ctx, value, d=u"", attribute=None): 453 """Return a string which is the concatenation of the strings in the 454 sequence. The separator between elements is an empty string per 455 default, you can define it with the optional parameter: 456 457 .. sourcecode:: jinja 458 459 {{ [1, 2, 3]|join('|') }} 460 -> 1|2|3 461 462 {{ [1, 2, 3]|join }} 463 -> 123 464 465 It is also possible to join certain attributes of an object: 466 467 .. sourcecode:: jinja 468 469 {{ users|join(', ', attribute='username') }} 470 471 .. versionadded:: 2.6 472 The `attribute` parameter was added. 473 """ 474 if attribute is not None: 475 value = imap(make_attrgetter(eval_ctx.environment, attribute), value) 476 477 # no automatic escaping? joining is a lot easier then 478 if not eval_ctx.autoescape: 479 return text_type(d).join(imap(text_type, value)) 480 481 # if the delimiter doesn't have an html representation we check 482 # if any of the items has. If yes we do a coercion to Markup 483 if not hasattr(d, "__html__"): 484 value = list(value) 485 do_escape = False 486 for idx, item in enumerate(value): 487 if hasattr(item, "__html__"): 488 do_escape = True 489 else: 490 value[idx] = text_type(item) 491 if do_escape: 492 d = escape(d) 493 else: 494 d = text_type(d) 495 return d.join(value) 496 497 # no html involved, to normal joining 498 return soft_unicode(d).join(imap(soft_unicode, value)) 499 500 501def do_center(value, width=80): 502 """Centers the value in a field of a given width.""" 503 return text_type(value).center(width) 504 505 506@environmentfilter 507def do_first(environment, seq): 508 """Return the first item of a sequence.""" 509 try: 510 return next(iter(seq)) 511 except StopIteration: 512 return environment.undefined("No first item, sequence was empty.") 513 514 515@environmentfilter 516def do_last(environment, seq): 517 """ 518 Return the last item of a sequence. 519 520 Note: Does not work with generators. You may want to explicitly 521 convert it to a list: 522 523 .. sourcecode:: jinja 524 525 {{ data | selectattr('name', '==', 'Jinja') | list | last }} 526 """ 527 try: 528 return next(iter(reversed(seq))) 529 except StopIteration: 530 return environment.undefined("No last item, sequence was empty.") 531 532 533@contextfilter 534def do_random(context, seq): 535 """Return a random item from the sequence.""" 536 try: 537 return random.choice(seq) 538 except IndexError: 539 return context.environment.undefined("No random item, sequence was empty.") 540 541 542def do_filesizeformat(value, binary=False): 543 """Format the value like a 'human-readable' file size (i.e. 13 kB, 544 4.1 MB, 102 Bytes, etc). Per default decimal prefixes are used (Mega, 545 Giga, etc.), if the second parameter is set to `True` the binary 546 prefixes are used (Mebi, Gibi). 547 """ 548 bytes = float(value) 549 base = binary and 1024 or 1000 550 prefixes = [ 551 (binary and "KiB" or "kB"), 552 (binary and "MiB" or "MB"), 553 (binary and "GiB" or "GB"), 554 (binary and "TiB" or "TB"), 555 (binary and "PiB" or "PB"), 556 (binary and "EiB" or "EB"), 557 (binary and "ZiB" or "ZB"), 558 (binary and "YiB" or "YB"), 559 ] 560 if bytes == 1: 561 return "1 Byte" 562 elif bytes < base: 563 return "%d Bytes" % bytes 564 else: 565 for i, prefix in enumerate(prefixes): 566 unit = base ** (i + 2) 567 if bytes < unit: 568 return "%.1f %s" % ((base * bytes / unit), prefix) 569 return "%.1f %s" % ((base * bytes / unit), prefix) 570 571 572def do_pprint(value, verbose=False): 573 """Pretty print a variable. Useful for debugging. 574 575 With Jinja 1.2 onwards you can pass it a parameter. If this parameter 576 is truthy the output will be more verbose (this requires `pretty`) 577 """ 578 return pformat(value, verbose=verbose) 579 580 581@evalcontextfilter 582def do_urlize( 583 eval_ctx, value, trim_url_limit=None, nofollow=False, target=None, rel=None 584): 585 """Converts URLs in plain text into clickable links. 586 587 If you pass the filter an additional integer it will shorten the urls 588 to that number. Also a third argument exists that makes the urls 589 "nofollow": 590 591 .. sourcecode:: jinja 592 593 {{ mytext|urlize(40, true) }} 594 links are shortened to 40 chars and defined with rel="nofollow" 595 596 If *target* is specified, the ``target`` attribute will be added to the 597 ``<a>`` tag: 598 599 .. sourcecode:: jinja 600 601 {{ mytext|urlize(40, target='_blank') }} 602 603 .. versionchanged:: 2.8+ 604 The *target* parameter was added. 605 """ 606 policies = eval_ctx.environment.policies 607 rel = set((rel or "").split() or []) 608 if nofollow: 609 rel.add("nofollow") 610 rel.update((policies["urlize.rel"] or "").split()) 611 if target is None: 612 target = policies["urlize.target"] 613 rel = " ".join(sorted(rel)) or None 614 rv = urlize(value, trim_url_limit, rel=rel, target=target) 615 if eval_ctx.autoescape: 616 rv = Markup(rv) 617 return rv 618 619 620def do_indent(s, width=4, first=False, blank=False, indentfirst=None): 621 """Return a copy of the string with each line indented by 4 spaces. The 622 first line and blank lines are not indented by default. 623 624 :param width: Number of spaces to indent by. 625 :param first: Don't skip indenting the first line. 626 :param blank: Don't skip indenting empty lines. 627 628 .. versionchanged:: 2.10 629 Blank lines are not indented by default. 630 631 Rename the ``indentfirst`` argument to ``first``. 632 """ 633 if indentfirst is not None: 634 warnings.warn( 635 "The 'indentfirst' argument is renamed to 'first' and will" 636 " be removed in version 3.0.", 637 DeprecationWarning, 638 stacklevel=2, 639 ) 640 first = indentfirst 641 642 indention = u" " * width 643 newline = u"\n" 644 645 if isinstance(s, Markup): 646 indention = Markup(indention) 647 newline = Markup(newline) 648 649 s += newline # this quirk is necessary for splitlines method 650 651 if blank: 652 rv = (newline + indention).join(s.splitlines()) 653 else: 654 lines = s.splitlines() 655 rv = lines.pop(0) 656 657 if lines: 658 rv += newline + newline.join( 659 indention + line if line else line for line in lines 660 ) 661 662 if first: 663 rv = indention + rv 664 665 return rv 666 667 668@environmentfilter 669def do_truncate(env, s, length=255, killwords=False, end="...", leeway=None): 670 """Return a truncated copy of the string. The length is specified 671 with the first parameter which defaults to ``255``. If the second 672 parameter is ``true`` the filter will cut the text at length. Otherwise 673 it will discard the last word. If the text was in fact 674 truncated it will append an ellipsis sign (``"..."``). If you want a 675 different ellipsis sign than ``"..."`` you can specify it using the 676 third parameter. Strings that only exceed the length by the tolerance 677 margin given in the fourth parameter will not be truncated. 678 679 .. sourcecode:: jinja 680 681 {{ "foo bar baz qux"|truncate(9) }} 682 -> "foo..." 683 {{ "foo bar baz qux"|truncate(9, True) }} 684 -> "foo ba..." 685 {{ "foo bar baz qux"|truncate(11) }} 686 -> "foo bar baz qux" 687 {{ "foo bar baz qux"|truncate(11, False, '...', 0) }} 688 -> "foo bar..." 689 690 The default leeway on newer Jinja versions is 5 and was 0 before but 691 can be reconfigured globally. 692 """ 693 if leeway is None: 694 leeway = env.policies["truncate.leeway"] 695 assert length >= len(end), "expected length >= %s, got %s" % (len(end), length) 696 assert leeway >= 0, "expected leeway >= 0, got %s" % leeway 697 if len(s) <= length + leeway: 698 return s 699 if killwords: 700 return s[: length - len(end)] + end 701 result = s[: length - len(end)].rsplit(" ", 1)[0] 702 return result + end 703 704 705@environmentfilter 706def do_wordwrap( 707 environment, 708 s, 709 width=79, 710 break_long_words=True, 711 wrapstring=None, 712 break_on_hyphens=True, 713): 714 """Wrap a string to the given width. Existing newlines are treated 715 as paragraphs to be wrapped separately. 716 717 :param s: Original text to wrap. 718 :param width: Maximum length of wrapped lines. 719 :param break_long_words: If a word is longer than ``width``, break 720 it across lines. 721 :param break_on_hyphens: If a word contains hyphens, it may be split 722 across lines. 723 :param wrapstring: String to join each wrapped line. Defaults to 724 :attr:`Environment.newline_sequence`. 725 726 .. versionchanged:: 2.11 727 Existing newlines are treated as paragraphs wrapped separately. 728 729 .. versionchanged:: 2.11 730 Added the ``break_on_hyphens`` parameter. 731 732 .. versionchanged:: 2.7 733 Added the ``wrapstring`` parameter. 734 """ 735 736 import textwrap 737 738 if not wrapstring: 739 wrapstring = environment.newline_sequence 740 741 # textwrap.wrap doesn't consider existing newlines when wrapping. 742 # If the string has a newline before width, wrap will still insert 743 # a newline at width, resulting in a short line. Instead, split and 744 # wrap each paragraph individually. 745 return wrapstring.join( 746 [ 747 wrapstring.join( 748 textwrap.wrap( 749 line, 750 width=width, 751 expand_tabs=False, 752 replace_whitespace=False, 753 break_long_words=break_long_words, 754 break_on_hyphens=break_on_hyphens, 755 ) 756 ) 757 for line in s.splitlines() 758 ] 759 ) 760 761 762def do_wordcount(s): 763 """Count the words in that string.""" 764 return len(_word_re.findall(soft_unicode(s))) 765 766 767def do_int(value, default=0, base=10): 768 """Convert the value into an integer. If the 769 conversion doesn't work it will return ``0``. You can 770 override this default using the first parameter. You 771 can also override the default base (10) in the second 772 parameter, which handles input with prefixes such as 773 0b, 0o and 0x for bases 2, 8 and 16 respectively. 774 The base is ignored for decimal numbers and non-string values. 775 """ 776 try: 777 if isinstance(value, string_types): 778 return int(value, base) 779 return int(value) 780 except (TypeError, ValueError): 781 # this quirk is necessary so that "42.23"|int gives 42. 782 try: 783 return int(float(value)) 784 except (TypeError, ValueError): 785 return default 786 787 788def do_float(value, default=0.0): 789 """Convert the value into a floating point number. If the 790 conversion doesn't work it will return ``0.0``. You can 791 override this default using the first parameter. 792 """ 793 try: 794 return float(value) 795 except (TypeError, ValueError): 796 return default 797 798 799def do_format(value, *args, **kwargs): 800 """Apply the given values to a `printf-style`_ format string, like 801 ``string % values``. 802 803 .. sourcecode:: jinja 804 805 {{ "%s, %s!"|format(greeting, name) }} 806 Hello, World! 807 808 In most cases it should be more convenient and efficient to use the 809 ``%`` operator or :meth:`str.format`. 810 811 .. code-block:: text 812 813 {{ "%s, %s!" % (greeting, name) }} 814 {{ "{}, {}!".format(greeting, name) }} 815 816 .. _printf-style: https://docs.python.org/library/stdtypes.html 817 #printf-style-string-formatting 818 """ 819 if args and kwargs: 820 raise FilterArgumentError( 821 "can't handle positional and keyword arguments at the same time" 822 ) 823 return soft_unicode(value) % (kwargs or args) 824 825 826def do_trim(value, chars=None): 827 """Strip leading and trailing characters, by default whitespace.""" 828 return soft_unicode(value).strip(chars) 829 830 831def do_striptags(value): 832 """Strip SGML/XML tags and replace adjacent whitespace by one space.""" 833 if hasattr(value, "__html__"): 834 value = value.__html__() 835 return Markup(text_type(value)).striptags() 836 837 838def do_slice(value, slices, fill_with=None): 839 """Slice an iterator and return a list of lists containing 840 those items. Useful if you want to create a div containing 841 three ul tags that represent columns: 842 843 .. sourcecode:: html+jinja 844 845 <div class="columnwrapper"> 846 {%- for column in items|slice(3) %} 847 <ul class="column-{{ loop.index }}"> 848 {%- for item in column %} 849 <li>{{ item }}</li> 850 {%- endfor %} 851 </ul> 852 {%- endfor %} 853 </div> 854 855 If you pass it a second argument it's used to fill missing 856 values on the last iteration. 857 """ 858 seq = list(value) 859 length = len(seq) 860 items_per_slice = length // slices 861 slices_with_extra = length % slices 862 offset = 0 863 for slice_number in range(slices): 864 start = offset + slice_number * items_per_slice 865 if slice_number < slices_with_extra: 866 offset += 1 867 end = offset + (slice_number + 1) * items_per_slice 868 tmp = seq[start:end] 869 if fill_with is not None and slice_number >= slices_with_extra: 870 tmp.append(fill_with) 871 yield tmp 872 873 874def do_batch(value, linecount, fill_with=None): 875 """ 876 A filter that batches items. It works pretty much like `slice` 877 just the other way round. It returns a list of lists with the 878 given number of items. If you provide a second parameter this 879 is used to fill up missing items. See this example: 880 881 .. sourcecode:: html+jinja 882 883 <table> 884 {%- for row in items|batch(3, ' ') %} 885 <tr> 886 {%- for column in row %} 887 <td>{{ column }}</td> 888 {%- endfor %} 889 </tr> 890 {%- endfor %} 891 </table> 892 """ 893 tmp = [] 894 for item in value: 895 if len(tmp) == linecount: 896 yield tmp 897 tmp = [] 898 tmp.append(item) 899 if tmp: 900 if fill_with is not None and len(tmp) < linecount: 901 tmp += [fill_with] * (linecount - len(tmp)) 902 yield tmp 903 904 905def do_round(value, precision=0, method="common"): 906 """Round the number to a given precision. The first 907 parameter specifies the precision (default is ``0``), the 908 second the rounding method: 909 910 - ``'common'`` rounds either up or down 911 - ``'ceil'`` always rounds up 912 - ``'floor'`` always rounds down 913 914 If you don't specify a method ``'common'`` is used. 915 916 .. sourcecode:: jinja 917 918 {{ 42.55|round }} 919 -> 43.0 920 {{ 42.55|round(1, 'floor') }} 921 -> 42.5 922 923 Note that even if rounded to 0 precision, a float is returned. If 924 you need a real integer, pipe it through `int`: 925 926 .. sourcecode:: jinja 927 928 {{ 42.55|round|int }} 929 -> 43 930 """ 931 if method not in {"common", "ceil", "floor"}: 932 raise FilterArgumentError("method must be common, ceil or floor") 933 if method == "common": 934 return round(value, precision) 935 func = getattr(math, method) 936 return func(value * (10 ** precision)) / (10 ** precision) 937 938 939# Use a regular tuple repr here. This is what we did in the past and we 940# really want to hide this custom type as much as possible. In particular 941# we do not want to accidentally expose an auto generated repr in case 942# people start to print this out in comments or something similar for 943# debugging. 944_GroupTuple = namedtuple("_GroupTuple", ["grouper", "list"]) 945_GroupTuple.__repr__ = tuple.__repr__ 946_GroupTuple.__str__ = tuple.__str__ 947 948 949@environmentfilter 950def do_groupby(environment, value, attribute): 951 """Group a sequence of objects by an attribute using Python's 952 :func:`itertools.groupby`. The attribute can use dot notation for 953 nested access, like ``"address.city"``. Unlike Python's ``groupby``, 954 the values are sorted first so only one group is returned for each 955 unique value. 956 957 For example, a list of ``User`` objects with a ``city`` attribute 958 can be rendered in groups. In this example, ``grouper`` refers to 959 the ``city`` value of the group. 960 961 .. sourcecode:: html+jinja 962 963 <ul>{% for city, items in users|groupby("city") %} 964 <li>{{ city }} 965 <ul>{% for user in items %} 966 <li>{{ user.name }} 967 {% endfor %}</ul> 968 </li> 969 {% endfor %}</ul> 970 971 ``groupby`` yields namedtuples of ``(grouper, list)``, which 972 can be used instead of the tuple unpacking above. ``grouper`` is the 973 value of the attribute, and ``list`` is the items with that value. 974 975 .. sourcecode:: html+jinja 976 977 <ul>{% for group in users|groupby("city") %} 978 <li>{{ group.grouper }}: {{ group.list|join(", ") }} 979 {% endfor %}</ul> 980 981 .. versionchanged:: 2.6 982 The attribute supports dot notation for nested access. 983 """ 984 expr = make_attrgetter(environment, attribute) 985 return [ 986 _GroupTuple(key, list(values)) 987 for key, values in groupby(sorted(value, key=expr), expr) 988 ] 989 990 991@environmentfilter 992def do_sum(environment, iterable, attribute=None, start=0): 993 """Returns the sum of a sequence of numbers plus the value of parameter 994 'start' (which defaults to 0). When the sequence is empty it returns 995 start. 996 997 It is also possible to sum up only certain attributes: 998 999 .. sourcecode:: jinja 1000 1001 Total: {{ items|sum(attribute='price') }} 1002 1003 .. versionchanged:: 2.6 1004 The `attribute` parameter was added to allow suming up over 1005 attributes. Also the `start` parameter was moved on to the right. 1006 """ 1007 if attribute is not None: 1008 iterable = imap(make_attrgetter(environment, attribute), iterable) 1009 return sum(iterable, start) 1010 1011 1012def do_list(value): 1013 """Convert the value into a list. If it was a string the returned list 1014 will be a list of characters. 1015 """ 1016 return list(value) 1017 1018 1019def do_mark_safe(value): 1020 """Mark the value as safe which means that in an environment with automatic 1021 escaping enabled this variable will not be escaped. 1022 """ 1023 return Markup(value) 1024 1025 1026def do_mark_unsafe(value): 1027 """Mark a value as unsafe. This is the reverse operation for :func:`safe`.""" 1028 return text_type(value) 1029 1030 1031def do_reverse(value): 1032 """Reverse the object or return an iterator that iterates over it the other 1033 way round. 1034 """ 1035 if isinstance(value, string_types): 1036 return value[::-1] 1037 try: 1038 return reversed(value) 1039 except TypeError: 1040 try: 1041 rv = list(value) 1042 rv.reverse() 1043 return rv 1044 except TypeError: 1045 raise FilterArgumentError("argument must be iterable") 1046 1047 1048@environmentfilter 1049def do_attr(environment, obj, name): 1050 """Get an attribute of an object. ``foo|attr("bar")`` works like 1051 ``foo.bar`` just that always an attribute is returned and items are not 1052 looked up. 1053 1054 See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details. 1055 """ 1056 try: 1057 name = str(name) 1058 except UnicodeError: 1059 pass 1060 else: 1061 try: 1062 value = getattr(obj, name) 1063 except AttributeError: 1064 pass 1065 else: 1066 if environment.sandboxed and not environment.is_safe_attribute( 1067 obj, name, value 1068 ): 1069 return environment.unsafe_undefined(obj, name) 1070 return value 1071 return environment.undefined(obj=obj, name=name) 1072 1073 1074@contextfilter 1075def do_map(*args, **kwargs): 1076 """Applies a filter on a sequence of objects or looks up an attribute. 1077 This is useful when dealing with lists of objects but you are really 1078 only interested in a certain value of it. 1079 1080 The basic usage is mapping on an attribute. Imagine you have a list 1081 of users but you are only interested in a list of usernames: 1082 1083 .. sourcecode:: jinja 1084 1085 Users on this page: {{ users|map(attribute='username')|join(', ') }} 1086 1087 You can specify a ``default`` value to use if an object in the list 1088 does not have the given attribute. 1089 1090 .. sourcecode:: jinja 1091 1092 {{ users|map(attribute="username", default="Anonymous")|join(", ") }} 1093 1094 Alternatively you can let it invoke a filter by passing the name of the 1095 filter and the arguments afterwards. A good example would be applying a 1096 text conversion filter on a sequence: 1097 1098 .. sourcecode:: jinja 1099 1100 Users on this page: {{ titles|map('lower')|join(', ') }} 1101 1102 Similar to a generator comprehension such as: 1103 1104 .. code-block:: python 1105 1106 (u.username for u in users) 1107 (u.username or "Anonymous" for u in users) 1108 (do_lower(x) for x in titles) 1109 1110 .. versionchanged:: 2.11.0 1111 Added the ``default`` parameter. 1112 1113 .. versionadded:: 2.7 1114 """ 1115 seq, func = prepare_map(args, kwargs) 1116 if seq: 1117 for item in seq: 1118 yield func(item) 1119 1120 1121@contextfilter 1122def do_select(*args, **kwargs): 1123 """Filters a sequence of objects by applying a test to each object, 1124 and only selecting the objects with the test succeeding. 1125 1126 If no test is specified, each object will be evaluated as a boolean. 1127 1128 Example usage: 1129 1130 .. sourcecode:: jinja 1131 1132 {{ numbers|select("odd") }} 1133 {{ numbers|select("odd") }} 1134 {{ numbers|select("divisibleby", 3) }} 1135 {{ numbers|select("lessthan", 42) }} 1136 {{ strings|select("equalto", "mystring") }} 1137 1138 Similar to a generator comprehension such as: 1139 1140 .. code-block:: python 1141 1142 (n for n in numbers if test_odd(n)) 1143 (n for n in numbers if test_divisibleby(n, 3)) 1144 1145 .. versionadded:: 2.7 1146 """ 1147 return select_or_reject(args, kwargs, lambda x: x, False) 1148 1149 1150@contextfilter 1151def do_reject(*args, **kwargs): 1152 """Filters a sequence of objects by applying a test to each object, 1153 and rejecting the objects with the test succeeding. 1154 1155 If no test is specified, each object will be evaluated as a boolean. 1156 1157 Example usage: 1158 1159 .. sourcecode:: jinja 1160 1161 {{ numbers|reject("odd") }} 1162 1163 Similar to a generator comprehension such as: 1164 1165 .. code-block:: python 1166 1167 (n for n in numbers if not test_odd(n)) 1168 1169 .. versionadded:: 2.7 1170 """ 1171 return select_or_reject(args, kwargs, lambda x: not x, False) 1172 1173 1174@contextfilter 1175def do_selectattr(*args, **kwargs): 1176 """Filters a sequence of objects by applying a test to the specified 1177 attribute of each object, and only selecting the objects with the 1178 test succeeding. 1179 1180 If no test is specified, the attribute's value will be evaluated as 1181 a boolean. 1182 1183 Example usage: 1184 1185 .. sourcecode:: jinja 1186 1187 {{ users|selectattr("is_active") }} 1188 {{ users|selectattr("email", "none") }} 1189 1190 Similar to a generator comprehension such as: 1191 1192 .. code-block:: python 1193 1194 (u for user in users if user.is_active) 1195 (u for user in users if test_none(user.email)) 1196 1197 .. versionadded:: 2.7 1198 """ 1199 return select_or_reject(args, kwargs, lambda x: x, True) 1200 1201 1202@contextfilter 1203def do_rejectattr(*args, **kwargs): 1204 """Filters a sequence of objects by applying a test to the specified 1205 attribute of each object, and rejecting the objects with the test 1206 succeeding. 1207 1208 If no test is specified, the attribute's value will be evaluated as 1209 a boolean. 1210 1211 .. sourcecode:: jinja 1212 1213 {{ users|rejectattr("is_active") }} 1214 {{ users|rejectattr("email", "none") }} 1215 1216 Similar to a generator comprehension such as: 1217 1218 .. code-block:: python 1219 1220 (u for user in users if not user.is_active) 1221 (u for user in users if not test_none(user.email)) 1222 1223 .. versionadded:: 2.7 1224 """ 1225 return select_or_reject(args, kwargs, lambda x: not x, True) 1226 1227 1228@evalcontextfilter 1229def do_tojson(eval_ctx, value, indent=None): 1230 """Dumps a structure to JSON so that it's safe to use in ``<script>`` 1231 tags. It accepts the same arguments and returns a JSON string. Note that 1232 this is available in templates through the ``|tojson`` filter which will 1233 also mark the result as safe. Due to how this function escapes certain 1234 characters this is safe even if used outside of ``<script>`` tags. 1235 1236 The following characters are escaped in strings: 1237 1238 - ``<`` 1239 - ``>`` 1240 - ``&`` 1241 - ``'`` 1242 1243 This makes it safe to embed such strings in any place in HTML with the 1244 notable exception of double quoted attributes. In that case single 1245 quote your attributes or HTML escape it in addition. 1246 1247 The indent parameter can be used to enable pretty printing. Set it to 1248 the number of spaces that the structures should be indented with. 1249 1250 Note that this filter is for use in HTML contexts only. 1251 1252 .. versionadded:: 2.9 1253 """ 1254 policies = eval_ctx.environment.policies 1255 dumper = policies["json.dumps_function"] 1256 options = policies["json.dumps_kwargs"] 1257 if indent is not None: 1258 options = dict(options) 1259 options["indent"] = indent 1260 return htmlsafe_json_dumps(value, dumper=dumper, **options) 1261 1262 1263def prepare_map(args, kwargs): 1264 context = args[0] 1265 seq = args[1] 1266 default = None 1267 1268 if len(args) == 2 and "attribute" in kwargs: 1269 attribute = kwargs.pop("attribute") 1270 default = kwargs.pop("default", None) 1271 if kwargs: 1272 raise FilterArgumentError( 1273 "Unexpected keyword argument %r" % next(iter(kwargs)) 1274 ) 1275 func = make_attrgetter(context.environment, attribute, default=default) 1276 else: 1277 try: 1278 name = args[2] 1279 args = args[3:] 1280 except LookupError: 1281 raise FilterArgumentError("map requires a filter argument") 1282 1283 def func(item): 1284 return context.environment.call_filter( 1285 name, item, args, kwargs, context=context 1286 ) 1287 1288 return seq, func 1289 1290 1291def prepare_select_or_reject(args, kwargs, modfunc, lookup_attr): 1292 context = args[0] 1293 seq = args[1] 1294 if lookup_attr: 1295 try: 1296 attr = args[2] 1297 except LookupError: 1298 raise FilterArgumentError("Missing parameter for attribute name") 1299 transfunc = make_attrgetter(context.environment, attr) 1300 off = 1 1301 else: 1302 off = 0 1303 1304 def transfunc(x): 1305 return x 1306 1307 try: 1308 name = args[2 + off] 1309 args = args[3 + off :] 1310 1311 def func(item): 1312 return context.environment.call_test(name, item, args, kwargs) 1313 1314 except LookupError: 1315 func = bool 1316 1317 return seq, lambda item: modfunc(func(transfunc(item))) 1318 1319 1320def select_or_reject(args, kwargs, modfunc, lookup_attr): 1321 seq, func = prepare_select_or_reject(args, kwargs, modfunc, lookup_attr) 1322 if seq: 1323 for item in seq: 1324 if func(item): 1325 yield item 1326 1327 1328FILTERS = { 1329 "abs": abs, 1330 "attr": do_attr, 1331 "batch": do_batch, 1332 "capitalize": do_capitalize, 1333 "center": do_center, 1334 "count": len, 1335 "d": do_default, 1336 "default": do_default, 1337 "dictsort": do_dictsort, 1338 "e": escape, 1339 "escape": escape, 1340 "filesizeformat": do_filesizeformat, 1341 "first": do_first, 1342 "float": do_float, 1343 "forceescape": do_forceescape, 1344 "format": do_format, 1345 "groupby": do_groupby, 1346 "indent": do_indent, 1347 "int": do_int, 1348 "join": do_join, 1349 "last": do_last, 1350 "length": len, 1351 "list": do_list, 1352 "lower": do_lower, 1353 "map": do_map, 1354 "min": do_min, 1355 "max": do_max, 1356 "pprint": do_pprint, 1357 "random": do_random, 1358 "reject": do_reject, 1359 "rejectattr": do_rejectattr, 1360 "replace": do_replace, 1361 "reverse": do_reverse, 1362 "round": do_round, 1363 "safe": do_mark_safe, 1364 "select": do_select, 1365 "selectattr": do_selectattr, 1366 "slice": do_slice, 1367 "sort": do_sort, 1368 "string": soft_unicode, 1369 "striptags": do_striptags, 1370 "sum": do_sum, 1371 "title": do_title, 1372 "trim": do_trim, 1373 "truncate": do_truncate, 1374 "unique": do_unique, 1375 "upper": do_upper, 1376 "urlencode": do_urlencode, 1377 "urlize": do_urlize, 1378 "wordcount": do_wordcount, 1379 "wordwrap": do_wordwrap, 1380 "xmlattr": do_xmlattr, 1381 "tojson": do_tojson, 1382} 1383