jinja2.filters
Built-in template filters used with the |
operator.
1"""Built-in template filters used with the ``|`` operator.""" 2 3import math 4import random 5import re 6import typing 7import typing as t 8from collections import abc 9from itertools import chain 10from itertools import groupby 11 12from markupsafe import escape 13from markupsafe import Markup 14from markupsafe import soft_str 15 16from .async_utils import async_variant 17from .async_utils import auto_aiter 18from .async_utils import auto_await 19from .async_utils import auto_to_list 20from .exceptions import FilterArgumentError 21from .runtime import Undefined 22from .utils import htmlsafe_json_dumps 23from .utils import pass_context 24from .utils import pass_environment 25from .utils import pass_eval_context 26from .utils import pformat 27from .utils import url_quote 28from .utils import urlize 29 30if t.TYPE_CHECKING: 31 import typing_extensions as te 32 33 from .environment import Environment 34 from .nodes import EvalContext 35 from .runtime import Context 36 from .sandbox import SandboxedEnvironment # noqa: F401 37 38 class HasHTML(te.Protocol): 39 def __html__(self) -> str: 40 pass 41 42 43F = t.TypeVar("F", bound=t.Callable[..., t.Any]) 44K = t.TypeVar("K") 45V = t.TypeVar("V") 46 47 48def ignore_case(value: V) -> V: 49 """For use as a postprocessor for :func:`make_attrgetter`. Converts strings 50 to lowercase and returns other types as-is.""" 51 if isinstance(value, str): 52 return t.cast(V, value.lower()) 53 54 return value 55 56 57def make_attrgetter( 58 environment: "Environment", 59 attribute: t.Optional[t.Union[str, int]], 60 postprocess: t.Optional[t.Callable[[t.Any], t.Any]] = None, 61 default: t.Optional[t.Any] = None, 62) -> t.Callable[[t.Any], t.Any]: 63 """Returns a callable that looks up the given attribute from a 64 passed object with the rules of the environment. Dots are allowed 65 to access attributes of attributes. Integer parts in paths are 66 looked up as integers. 67 """ 68 parts = _prepare_attribute_parts(attribute) 69 70 def attrgetter(item: t.Any) -> t.Any: 71 for part in parts: 72 item = environment.getitem(item, part) 73 74 if default is not None and isinstance(item, Undefined): 75 item = default 76 77 if postprocess is not None: 78 item = postprocess(item) 79 80 return item 81 82 return attrgetter 83 84 85def make_multi_attrgetter( 86 environment: "Environment", 87 attribute: t.Optional[t.Union[str, int]], 88 postprocess: t.Optional[t.Callable[[t.Any], t.Any]] = None, 89) -> t.Callable[[t.Any], t.List[t.Any]]: 90 """Returns a callable that looks up the given comma separated 91 attributes from a passed object with the rules of the environment. 92 Dots are allowed to access attributes of each attribute. Integer 93 parts in paths are looked up as integers. 94 95 The value returned by the returned callable is a list of extracted 96 attribute values. 97 98 Examples of attribute: "attr1,attr2", "attr1.inner1.0,attr2.inner2.0", etc. 99 """ 100 if isinstance(attribute, str): 101 split: t.Sequence[t.Union[str, int, None]] = attribute.split(",") 102 else: 103 split = [attribute] 104 105 parts = [_prepare_attribute_parts(item) for item in split] 106 107 def attrgetter(item: t.Any) -> t.List[t.Any]: 108 items = [None] * len(parts) 109 110 for i, attribute_part in enumerate(parts): 111 item_i = item 112 113 for part in attribute_part: 114 item_i = environment.getitem(item_i, part) 115 116 if postprocess is not None: 117 item_i = postprocess(item_i) 118 119 items[i] = item_i 120 121 return items 122 123 return attrgetter 124 125 126def _prepare_attribute_parts( 127 attr: t.Optional[t.Union[str, int]], 128) -> t.List[t.Union[str, int]]: 129 if attr is None: 130 return [] 131 132 if isinstance(attr, str): 133 return [int(x) if x.isdigit() else x for x in attr.split(".")] 134 135 return [attr] 136 137 138def do_forceescape(value: "t.Union[str, HasHTML]") -> Markup: 139 """Enforce HTML escaping. This will probably double escape variables.""" 140 if hasattr(value, "__html__"): 141 value = t.cast("HasHTML", value).__html__() 142 143 return escape(str(value)) 144 145 146def do_urlencode( 147 value: t.Union[str, t.Mapping[str, t.Any], t.Iterable[t.Tuple[str, t.Any]]], 148) -> str: 149 """Quote data for use in a URL path or query using UTF-8. 150 151 Basic wrapper around :func:`urllib.parse.quote` when given a 152 string, or :func:`urllib.parse.urlencode` for a dict or iterable. 153 154 :param value: Data to quote. A string will be quoted directly. A 155 dict or iterable of ``(key, value)`` pairs will be joined as a 156 query string. 157 158 When given a string, "/" is not quoted. HTTP servers treat "/" and 159 "%2F" equivalently in paths. If you need quoted slashes, use the 160 ``|replace("/", "%2F")`` filter. 161 162 .. versionadded:: 2.7 163 """ 164 if isinstance(value, str) or not isinstance(value, abc.Iterable): 165 return url_quote(value) 166 167 if isinstance(value, dict): 168 items: t.Iterable[t.Tuple[str, t.Any]] = value.items() 169 else: 170 items = value # type: ignore 171 172 return "&".join( 173 f"{url_quote(k, for_qs=True)}={url_quote(v, for_qs=True)}" for k, v in items 174 ) 175 176 177@pass_eval_context 178def do_replace( 179 eval_ctx: "EvalContext", s: str, old: str, new: str, count: t.Optional[int] = None 180) -> str: 181 """Return a copy of the value with all occurrences of a substring 182 replaced with a new one. The first argument is the substring 183 that should be replaced, the second is the replacement string. 184 If the optional third argument ``count`` is given, only the first 185 ``count`` occurrences are replaced: 186 187 .. sourcecode:: jinja 188 189 {{ "Hello World"|replace("Hello", "Goodbye") }} 190 -> Goodbye World 191 192 {{ "aaaaargh"|replace("a", "d'oh, ", 2) }} 193 -> d'oh, d'oh, aaargh 194 """ 195 if count is None: 196 count = -1 197 198 if not eval_ctx.autoescape: 199 return str(s).replace(str(old), str(new), count) 200 201 if ( 202 hasattr(old, "__html__") 203 or hasattr(new, "__html__") 204 and not hasattr(s, "__html__") 205 ): 206 s = escape(s) 207 else: 208 s = soft_str(s) 209 210 return s.replace(soft_str(old), soft_str(new), count) 211 212 213def do_upper(s: str) -> str: 214 """Convert a value to uppercase.""" 215 return soft_str(s).upper() 216 217 218def do_lower(s: str) -> str: 219 """Convert a value to lowercase.""" 220 return soft_str(s).lower() 221 222 223def do_items(value: t.Union[t.Mapping[K, V], Undefined]) -> t.Iterator[t.Tuple[K, V]]: 224 """Return an iterator over the ``(key, value)`` items of a mapping. 225 226 ``x|items`` is the same as ``x.items()``, except if ``x`` is 227 undefined an empty iterator is returned. 228 229 This filter is useful if you expect the template to be rendered with 230 an implementation of Jinja in another programming language that does 231 not have a ``.items()`` method on its mapping type. 232 233 .. code-block:: html+jinja 234 235 <dl> 236 {% for key, value in my_dict|items %} 237 <dt>{{ key }} 238 <dd>{{ value }} 239 {% endfor %} 240 </dl> 241 242 .. versionadded:: 3.1 243 """ 244 if isinstance(value, Undefined): 245 return 246 247 if not isinstance(value, abc.Mapping): 248 raise TypeError("Can only get item pairs from a mapping.") 249 250 yield from value.items() 251 252 253# Check for characters that would move the parser state from key to value. 254# https://html.spec.whatwg.org/#attribute-name-state 255_attr_key_re = re.compile(r"[\s/>=]", flags=re.ASCII) 256 257 258@pass_eval_context 259def do_xmlattr( 260 eval_ctx: "EvalContext", d: t.Mapping[str, t.Any], autospace: bool = True 261) -> str: 262 """Create an SGML/XML attribute string based on the items in a dict. 263 264 **Values** that are neither ``none`` nor ``undefined`` are automatically 265 escaped, safely allowing untrusted user input. 266 267 User input should not be used as **keys** to this filter. If any key 268 contains a space, ``/`` solidus, ``>`` greater-than sign, or ``=`` equals 269 sign, this fails with a ``ValueError``. Regardless of this, user input 270 should never be used as keys to this filter, or must be separately validated 271 first. 272 273 .. sourcecode:: html+jinja 274 275 <ul{{ {'class': 'my_list', 'missing': none, 276 'id': 'list-%d'|format(variable)}|xmlattr }}> 277 ... 278 </ul> 279 280 Results in something like this: 281 282 .. sourcecode:: html 283 284 <ul class="my_list" id="list-42"> 285 ... 286 </ul> 287 288 As you can see it automatically prepends a space in front of the item 289 if the filter returned something unless the second parameter is false. 290 291 .. versionchanged:: 3.1.4 292 Keys with ``/`` solidus, ``>`` greater-than sign, or ``=`` equals sign 293 are not allowed. 294 295 .. versionchanged:: 3.1.3 296 Keys with spaces are not allowed. 297 """ 298 items = [] 299 300 for key, value in d.items(): 301 if value is None or isinstance(value, Undefined): 302 continue 303 304 if _attr_key_re.search(key) is not None: 305 raise ValueError(f"Invalid character in attribute name: {key!r}") 306 307 items.append(f'{escape(key)}="{escape(value)}"') 308 309 rv = " ".join(items) 310 311 if autospace and rv: 312 rv = " " + rv 313 314 if eval_ctx.autoescape: 315 rv = Markup(rv) 316 317 return rv 318 319 320def do_capitalize(s: str) -> str: 321 """Capitalize a value. The first character will be uppercase, all others 322 lowercase. 323 """ 324 return soft_str(s).capitalize() 325 326 327_word_beginning_split_re = re.compile(r"([-\s({\[<]+)") 328 329 330def do_title(s: str) -> str: 331 """Return a titlecased version of the value. I.e. words will start with 332 uppercase letters, all remaining characters are lowercase. 333 """ 334 return "".join( 335 [ 336 item[0].upper() + item[1:].lower() 337 for item in _word_beginning_split_re.split(soft_str(s)) 338 if item 339 ] 340 ) 341 342 343def do_dictsort( 344 value: t.Mapping[K, V], 345 case_sensitive: bool = False, 346 by: 'te.Literal["key", "value"]' = "key", 347 reverse: bool = False, 348) -> t.List[t.Tuple[K, V]]: 349 """Sort a dict and yield (key, value) pairs. Python dicts may not 350 be in the order you want to display them in, so sort them first. 351 352 .. sourcecode:: jinja 353 354 {% for key, value in mydict|dictsort %} 355 sort the dict by key, case insensitive 356 357 {% for key, value in mydict|dictsort(reverse=true) %} 358 sort the dict by key, case insensitive, reverse order 359 360 {% for key, value in mydict|dictsort(true) %} 361 sort the dict by key, case sensitive 362 363 {% for key, value in mydict|dictsort(false, 'value') %} 364 sort the dict by value, case insensitive 365 """ 366 if by == "key": 367 pos = 0 368 elif by == "value": 369 pos = 1 370 else: 371 raise FilterArgumentError('You can only sort by either "key" or "value"') 372 373 def sort_func(item: t.Tuple[t.Any, t.Any]) -> t.Any: 374 value = item[pos] 375 376 if not case_sensitive: 377 value = ignore_case(value) 378 379 return value 380 381 return sorted(value.items(), key=sort_func, reverse=reverse) 382 383 384@pass_environment 385def do_sort( 386 environment: "Environment", 387 value: "t.Iterable[V]", 388 reverse: bool = False, 389 case_sensitive: bool = False, 390 attribute: t.Optional[t.Union[str, int]] = None, 391) -> "t.List[V]": 392 """Sort an iterable using Python's :func:`sorted`. 393 394 .. sourcecode:: jinja 395 396 {% for city in cities|sort %} 397 ... 398 {% endfor %} 399 400 :param reverse: Sort descending instead of ascending. 401 :param case_sensitive: When sorting strings, sort upper and lower 402 case separately. 403 :param attribute: When sorting objects or dicts, an attribute or 404 key to sort by. Can use dot notation like ``"address.city"``. 405 Can be a list of attributes like ``"age,name"``. 406 407 The sort is stable, it does not change the relative order of 408 elements that compare equal. This makes it is possible to chain 409 sorts on different attributes and ordering. 410 411 .. sourcecode:: jinja 412 413 {% for user in users|sort(attribute="name") 414 |sort(reverse=true, attribute="age") %} 415 ... 416 {% endfor %} 417 418 As a shortcut to chaining when the direction is the same for all 419 attributes, pass a comma separate list of attributes. 420 421 .. sourcecode:: jinja 422 423 {% for user in users|sort(attribute="age,name") %} 424 ... 425 {% endfor %} 426 427 .. versionchanged:: 2.11.0 428 The ``attribute`` parameter can be a comma separated list of 429 attributes, e.g. ``"age,name"``. 430 431 .. versionchanged:: 2.6 432 The ``attribute`` parameter was added. 433 """ 434 key_func = make_multi_attrgetter( 435 environment, attribute, postprocess=ignore_case if not case_sensitive else None 436 ) 437 return sorted(value, key=key_func, reverse=reverse) 438 439 440@pass_environment 441def do_unique( 442 environment: "Environment", 443 value: "t.Iterable[V]", 444 case_sensitive: bool = False, 445 attribute: t.Optional[t.Union[str, int]] = None, 446) -> "t.Iterator[V]": 447 """Returns a list of unique items from the given iterable. 448 449 .. sourcecode:: jinja 450 451 {{ ['foo', 'bar', 'foobar', 'FooBar']|unique|list }} 452 -> ['foo', 'bar', 'foobar'] 453 454 The unique items are yielded in the same order as their first occurrence in 455 the iterable passed to the filter. 456 457 :param case_sensitive: Treat upper and lower case strings as distinct. 458 :param attribute: Filter objects with unique values for this attribute. 459 """ 460 getter = make_attrgetter( 461 environment, attribute, postprocess=ignore_case if not case_sensitive else None 462 ) 463 seen = set() 464 465 for item in value: 466 key = getter(item) 467 468 if key not in seen: 469 seen.add(key) 470 yield item 471 472 473def _min_or_max( 474 environment: "Environment", 475 value: "t.Iterable[V]", 476 func: "t.Callable[..., V]", 477 case_sensitive: bool, 478 attribute: t.Optional[t.Union[str, int]], 479) -> "t.Union[V, Undefined]": 480 it = iter(value) 481 482 try: 483 first = next(it) 484 except StopIteration: 485 return environment.undefined("No aggregated item, sequence was empty.") 486 487 key_func = make_attrgetter( 488 environment, attribute, postprocess=ignore_case if not case_sensitive else None 489 ) 490 return func(chain([first], it), key=key_func) 491 492 493@pass_environment 494def do_min( 495 environment: "Environment", 496 value: "t.Iterable[V]", 497 case_sensitive: bool = False, 498 attribute: t.Optional[t.Union[str, int]] = None, 499) -> "t.Union[V, Undefined]": 500 """Return the smallest item from the sequence. 501 502 .. sourcecode:: jinja 503 504 {{ [1, 2, 3]|min }} 505 -> 1 506 507 :param case_sensitive: Treat upper and lower case strings as distinct. 508 :param attribute: Get the object with the min value of this attribute. 509 """ 510 return _min_or_max(environment, value, min, case_sensitive, attribute) 511 512 513@pass_environment 514def do_max( 515 environment: "Environment", 516 value: "t.Iterable[V]", 517 case_sensitive: bool = False, 518 attribute: t.Optional[t.Union[str, int]] = None, 519) -> "t.Union[V, Undefined]": 520 """Return the largest item from the sequence. 521 522 .. sourcecode:: jinja 523 524 {{ [1, 2, 3]|max }} 525 -> 3 526 527 :param case_sensitive: Treat upper and lower case strings as distinct. 528 :param attribute: Get the object with the max value of this attribute. 529 """ 530 return _min_or_max(environment, value, max, case_sensitive, attribute) 531 532 533def do_default( 534 value: V, 535 default_value: V = "", # type: ignore 536 boolean: bool = False, 537) -> V: 538 """If the value is undefined it will return the passed default value, 539 otherwise the value of the variable: 540 541 .. sourcecode:: jinja 542 543 {{ my_variable|default('my_variable is not defined') }} 544 545 This will output the value of ``my_variable`` if the variable was 546 defined, otherwise ``'my_variable is not defined'``. If you want 547 to use default with variables that evaluate to false you have to 548 set the second parameter to `true`: 549 550 .. sourcecode:: jinja 551 552 {{ ''|default('the string was empty', true) }} 553 554 .. versionchanged:: 2.11 555 It's now possible to configure the :class:`~jinja2.Environment` with 556 :class:`~jinja2.ChainableUndefined` to make the `default` filter work 557 on nested elements and attributes that may contain undefined values 558 in the chain without getting an :exc:`~jinja2.UndefinedError`. 559 """ 560 if isinstance(value, Undefined) or (boolean and not value): 561 return default_value 562 563 return value 564 565 566@pass_eval_context 567def sync_do_join( 568 eval_ctx: "EvalContext", 569 value: t.Iterable[t.Any], 570 d: str = "", 571 attribute: t.Optional[t.Union[str, int]] = None, 572) -> str: 573 """Return a string which is the concatenation of the strings in the 574 sequence. The separator between elements is an empty string per 575 default, you can define it with the optional parameter: 576 577 .. sourcecode:: jinja 578 579 {{ [1, 2, 3]|join('|') }} 580 -> 1|2|3 581 582 {{ [1, 2, 3]|join }} 583 -> 123 584 585 It is also possible to join certain attributes of an object: 586 587 .. sourcecode:: jinja 588 589 {{ users|join(', ', attribute='username') }} 590 591 .. versionadded:: 2.6 592 The `attribute` parameter was added. 593 """ 594 if attribute is not None: 595 value = map(make_attrgetter(eval_ctx.environment, attribute), value) 596 597 # no automatic escaping? joining is a lot easier then 598 if not eval_ctx.autoescape: 599 return str(d).join(map(str, value)) 600 601 # if the delimiter doesn't have an html representation we check 602 # if any of the items has. If yes we do a coercion to Markup 603 if not hasattr(d, "__html__"): 604 value = list(value) 605 do_escape = False 606 607 for idx, item in enumerate(value): 608 if hasattr(item, "__html__"): 609 do_escape = True 610 else: 611 value[idx] = str(item) 612 613 if do_escape: 614 d = escape(d) 615 else: 616 d = str(d) 617 618 return d.join(value) 619 620 # no html involved, to normal joining 621 return soft_str(d).join(map(soft_str, value)) 622 623 624@async_variant(sync_do_join) # type: ignore 625async def do_join( 626 eval_ctx: "EvalContext", 627 value: t.Union[t.AsyncIterable[t.Any], t.Iterable[t.Any]], 628 d: str = "", 629 attribute: t.Optional[t.Union[str, int]] = None, 630) -> str: 631 return sync_do_join(eval_ctx, await auto_to_list(value), d, attribute) 632 633 634def do_center(value: str, width: int = 80) -> str: 635 """Centers the value in a field of a given width.""" 636 return soft_str(value).center(width) 637 638 639@pass_environment 640def sync_do_first( 641 environment: "Environment", seq: "t.Iterable[V]" 642) -> "t.Union[V, Undefined]": 643 """Return the first item of a sequence.""" 644 try: 645 return next(iter(seq)) 646 except StopIteration: 647 return environment.undefined("No first item, sequence was empty.") 648 649 650@async_variant(sync_do_first) # type: ignore 651async def do_first( 652 environment: "Environment", seq: "t.Union[t.AsyncIterable[V], t.Iterable[V]]" 653) -> "t.Union[V, Undefined]": 654 try: 655 return await auto_aiter(seq).__anext__() 656 except StopAsyncIteration: 657 return environment.undefined("No first item, sequence was empty.") 658 659 660@pass_environment 661def do_last( 662 environment: "Environment", seq: "t.Reversible[V]" 663) -> "t.Union[V, Undefined]": 664 """Return the last item of a sequence. 665 666 Note: Does not work with generators. You may want to explicitly 667 convert it to a list: 668 669 .. sourcecode:: jinja 670 671 {{ data | selectattr('name', '==', 'Jinja') | list | last }} 672 """ 673 try: 674 return next(iter(reversed(seq))) 675 except StopIteration: 676 return environment.undefined("No last item, sequence was empty.") 677 678 679# No async do_last, it may not be safe in async mode. 680 681 682@pass_context 683def do_random(context: "Context", seq: "t.Sequence[V]") -> "t.Union[V, Undefined]": 684 """Return a random item from the sequence.""" 685 try: 686 return random.choice(seq) 687 except IndexError: 688 return context.environment.undefined("No random item, sequence was empty.") 689 690 691def do_filesizeformat(value: t.Union[str, float, int], binary: bool = False) -> str: 692 """Format the value like a 'human-readable' file size (i.e. 13 kB, 693 4.1 MB, 102 Bytes, etc). Per default decimal prefixes are used (Mega, 694 Giga, etc.), if the second parameter is set to `True` the binary 695 prefixes are used (Mebi, Gibi). 696 """ 697 bytes = float(value) 698 base = 1024 if binary else 1000 699 prefixes = [ 700 ("KiB" if binary else "kB"), 701 ("MiB" if binary else "MB"), 702 ("GiB" if binary else "GB"), 703 ("TiB" if binary else "TB"), 704 ("PiB" if binary else "PB"), 705 ("EiB" if binary else "EB"), 706 ("ZiB" if binary else "ZB"), 707 ("YiB" if binary else "YB"), 708 ] 709 710 if bytes == 1: 711 return "1 Byte" 712 elif bytes < base: 713 return f"{int(bytes)} Bytes" 714 else: 715 for i, prefix in enumerate(prefixes): 716 unit = base ** (i + 2) 717 718 if bytes < unit: 719 return f"{base * bytes / unit:.1f} {prefix}" 720 721 return f"{base * bytes / unit:.1f} {prefix}" 722 723 724def do_pprint(value: t.Any) -> str: 725 """Pretty print a variable. Useful for debugging.""" 726 return pformat(value) 727 728 729_uri_scheme_re = re.compile(r"^([\w.+-]{2,}:(/){0,2})$") 730 731 732@pass_eval_context 733def do_urlize( 734 eval_ctx: "EvalContext", 735 value: str, 736 trim_url_limit: t.Optional[int] = None, 737 nofollow: bool = False, 738 target: t.Optional[str] = None, 739 rel: t.Optional[str] = None, 740 extra_schemes: t.Optional[t.Iterable[str]] = None, 741) -> str: 742 """Convert URLs in text into clickable links. 743 744 This may not recognize links in some situations. Usually, a more 745 comprehensive formatter, such as a Markdown library, is a better 746 choice. 747 748 Works on ``http://``, ``https://``, ``www.``, ``mailto:``, and email 749 addresses. Links with trailing punctuation (periods, commas, closing 750 parentheses) and leading punctuation (opening parentheses) are 751 recognized excluding the punctuation. Email addresses that include 752 header fields are not recognized (for example, 753 ``mailto:address@example.com?cc=copy@example.com``). 754 755 :param value: Original text containing URLs to link. 756 :param trim_url_limit: Shorten displayed URL values to this length. 757 :param nofollow: Add the ``rel=nofollow`` attribute to links. 758 :param target: Add the ``target`` attribute to links. 759 :param rel: Add the ``rel`` attribute to links. 760 :param extra_schemes: Recognize URLs that start with these schemes 761 in addition to the default behavior. Defaults to 762 ``env.policies["urlize.extra_schemes"]``, which defaults to no 763 extra schemes. 764 765 .. versionchanged:: 3.0 766 The ``extra_schemes`` parameter was added. 767 768 .. versionchanged:: 3.0 769 Generate ``https://`` links for URLs without a scheme. 770 771 .. versionchanged:: 3.0 772 The parsing rules were updated. Recognize email addresses with 773 or without the ``mailto:`` scheme. Validate IP addresses. Ignore 774 parentheses and brackets in more cases. 775 776 .. versionchanged:: 2.8 777 The ``target`` parameter was added. 778 """ 779 policies = eval_ctx.environment.policies 780 rel_parts = set((rel or "").split()) 781 782 if nofollow: 783 rel_parts.add("nofollow") 784 785 rel_parts.update((policies["urlize.rel"] or "").split()) 786 rel = " ".join(sorted(rel_parts)) or None 787 788 if target is None: 789 target = policies["urlize.target"] 790 791 if extra_schemes is None: 792 extra_schemes = policies["urlize.extra_schemes"] or () 793 794 for scheme in extra_schemes: 795 if _uri_scheme_re.fullmatch(scheme) is None: 796 raise FilterArgumentError(f"{scheme!r} is not a valid URI scheme prefix.") 797 798 rv = urlize( 799 value, 800 trim_url_limit=trim_url_limit, 801 rel=rel, 802 target=target, 803 extra_schemes=extra_schemes, 804 ) 805 806 if eval_ctx.autoescape: 807 rv = Markup(rv) 808 809 return rv 810 811 812def do_indent( 813 s: str, width: t.Union[int, str] = 4, first: bool = False, blank: bool = False 814) -> str: 815 """Return a copy of the string with each line indented by 4 spaces. The 816 first line and blank lines are not indented by default. 817 818 :param width: Number of spaces, or a string, to indent by. 819 :param first: Don't skip indenting the first line. 820 :param blank: Don't skip indenting empty lines. 821 822 .. versionchanged:: 3.0 823 ``width`` can be a string. 824 825 .. versionchanged:: 2.10 826 Blank lines are not indented by default. 827 828 Rename the ``indentfirst`` argument to ``first``. 829 """ 830 if isinstance(width, str): 831 indention = width 832 else: 833 indention = " " * width 834 835 newline = "\n" 836 837 if isinstance(s, Markup): 838 indention = Markup(indention) 839 newline = Markup(newline) 840 841 s += newline # this quirk is necessary for splitlines method 842 843 if blank: 844 rv = (newline + indention).join(s.splitlines()) 845 else: 846 lines = s.splitlines() 847 rv = lines.pop(0) 848 849 if lines: 850 rv += newline + newline.join( 851 indention + line if line else line for line in lines 852 ) 853 854 if first: 855 rv = indention + rv 856 857 return rv 858 859 860@pass_environment 861def do_truncate( 862 env: "Environment", 863 s: str, 864 length: int = 255, 865 killwords: bool = False, 866 end: str = "...", 867 leeway: t.Optional[int] = None, 868) -> str: 869 """Return a truncated copy of the string. The length is specified 870 with the first parameter which defaults to ``255``. If the second 871 parameter is ``true`` the filter will cut the text at length. Otherwise 872 it will discard the last word. If the text was in fact 873 truncated it will append an ellipsis sign (``"..."``). If you want a 874 different ellipsis sign than ``"..."`` you can specify it using the 875 third parameter. Strings that only exceed the length by the tolerance 876 margin given in the fourth parameter will not be truncated. 877 878 .. sourcecode:: jinja 879 880 {{ "foo bar baz qux"|truncate(9) }} 881 -> "foo..." 882 {{ "foo bar baz qux"|truncate(9, True) }} 883 -> "foo ba..." 884 {{ "foo bar baz qux"|truncate(11) }} 885 -> "foo bar baz qux" 886 {{ "foo bar baz qux"|truncate(11, False, '...', 0) }} 887 -> "foo bar..." 888 889 The default leeway on newer Jinja versions is 5 and was 0 before but 890 can be reconfigured globally. 891 """ 892 if leeway is None: 893 leeway = env.policies["truncate.leeway"] 894 895 assert length >= len(end), f"expected length >= {len(end)}, got {length}" 896 assert leeway >= 0, f"expected leeway >= 0, got {leeway}" 897 898 if len(s) <= length + leeway: 899 return s 900 901 if killwords: 902 return s[: length - len(end)] + end 903 904 result = s[: length - len(end)].rsplit(" ", 1)[0] 905 return result + end 906 907 908@pass_environment 909def do_wordwrap( 910 environment: "Environment", 911 s: str, 912 width: int = 79, 913 break_long_words: bool = True, 914 wrapstring: t.Optional[str] = None, 915 break_on_hyphens: bool = True, 916) -> str: 917 """Wrap a string to the given width. Existing newlines are treated 918 as paragraphs to be wrapped separately. 919 920 :param s: Original text to wrap. 921 :param width: Maximum length of wrapped lines. 922 :param break_long_words: If a word is longer than ``width``, break 923 it across lines. 924 :param break_on_hyphens: If a word contains hyphens, it may be split 925 across lines. 926 :param wrapstring: String to join each wrapped line. Defaults to 927 :attr:`Environment.newline_sequence`. 928 929 .. versionchanged:: 2.11 930 Existing newlines are treated as paragraphs wrapped separately. 931 932 .. versionchanged:: 2.11 933 Added the ``break_on_hyphens`` parameter. 934 935 .. versionchanged:: 2.7 936 Added the ``wrapstring`` parameter. 937 """ 938 import textwrap 939 940 if wrapstring is None: 941 wrapstring = environment.newline_sequence 942 943 # textwrap.wrap doesn't consider existing newlines when wrapping. 944 # If the string has a newline before width, wrap will still insert 945 # a newline at width, resulting in a short line. Instead, split and 946 # wrap each paragraph individually. 947 return wrapstring.join( 948 [ 949 wrapstring.join( 950 textwrap.wrap( 951 line, 952 width=width, 953 expand_tabs=False, 954 replace_whitespace=False, 955 break_long_words=break_long_words, 956 break_on_hyphens=break_on_hyphens, 957 ) 958 ) 959 for line in s.splitlines() 960 ] 961 ) 962 963 964_word_re = re.compile(r"\w+") 965 966 967def do_wordcount(s: str) -> int: 968 """Count the words in that string.""" 969 return len(_word_re.findall(soft_str(s))) 970 971 972def do_int(value: t.Any, default: int = 0, base: int = 10) -> int: 973 """Convert the value into an integer. If the 974 conversion doesn't work it will return ``0``. You can 975 override this default using the first parameter. You 976 can also override the default base (10) in the second 977 parameter, which handles input with prefixes such as 978 0b, 0o and 0x for bases 2, 8 and 16 respectively. 979 The base is ignored for decimal numbers and non-string values. 980 """ 981 try: 982 if isinstance(value, str): 983 return int(value, base) 984 985 return int(value) 986 except (TypeError, ValueError): 987 # this quirk is necessary so that "42.23"|int gives 42. 988 try: 989 return int(float(value)) 990 except (TypeError, ValueError): 991 return default 992 993 994def do_float(value: t.Any, default: float = 0.0) -> float: 995 """Convert the value into a floating point number. If the 996 conversion doesn't work it will return ``0.0``. You can 997 override this default using the first parameter. 998 """ 999 try: 1000 return float(value) 1001 except (TypeError, ValueError): 1002 return default 1003 1004 1005def do_format(value: str, *args: t.Any, **kwargs: t.Any) -> str: 1006 """Apply the given values to a `printf-style`_ format string, like 1007 ``string % values``. 1008 1009 .. sourcecode:: jinja 1010 1011 {{ "%s, %s!"|format(greeting, name) }} 1012 Hello, World! 1013 1014 In most cases it should be more convenient and efficient to use the 1015 ``%`` operator or :meth:`str.format`. 1016 1017 .. code-block:: text 1018 1019 {{ "%s, %s!" % (greeting, name) }} 1020 {{ "{}, {}!".format(greeting, name) }} 1021 1022 .. _printf-style: https://docs.python.org/library/stdtypes.html 1023 #printf-style-string-formatting 1024 """ 1025 if args and kwargs: 1026 raise FilterArgumentError( 1027 "can't handle positional and keyword arguments at the same time" 1028 ) 1029 1030 return soft_str(value) % (kwargs or args) 1031 1032 1033def do_trim(value: str, chars: t.Optional[str] = None) -> str: 1034 """Strip leading and trailing characters, by default whitespace.""" 1035 return soft_str(value).strip(chars) 1036 1037 1038def do_striptags(value: "t.Union[str, HasHTML]") -> str: 1039 """Strip SGML/XML tags and replace adjacent whitespace by one space.""" 1040 if hasattr(value, "__html__"): 1041 value = t.cast("HasHTML", value).__html__() 1042 1043 return Markup(str(value)).striptags() 1044 1045 1046def sync_do_slice( 1047 value: "t.Collection[V]", slices: int, fill_with: "t.Optional[V]" = None 1048) -> "t.Iterator[t.List[V]]": 1049 """Slice an iterator and return a list of lists containing 1050 those items. Useful if you want to create a div containing 1051 three ul tags that represent columns: 1052 1053 .. sourcecode:: html+jinja 1054 1055 <div class="columnwrapper"> 1056 {%- for column in items|slice(3) %} 1057 <ul class="column-{{ loop.index }}"> 1058 {%- for item in column %} 1059 <li>{{ item }}</li> 1060 {%- endfor %} 1061 </ul> 1062 {%- endfor %} 1063 </div> 1064 1065 If you pass it a second argument it's used to fill missing 1066 values on the last iteration. 1067 """ 1068 seq = list(value) 1069 length = len(seq) 1070 items_per_slice = length // slices 1071 slices_with_extra = length % slices 1072 offset = 0 1073 1074 for slice_number in range(slices): 1075 start = offset + slice_number * items_per_slice 1076 1077 if slice_number < slices_with_extra: 1078 offset += 1 1079 1080 end = offset + (slice_number + 1) * items_per_slice 1081 tmp = seq[start:end] 1082 1083 if fill_with is not None and slice_number >= slices_with_extra: 1084 tmp.append(fill_with) 1085 1086 yield tmp 1087 1088 1089@async_variant(sync_do_slice) # type: ignore 1090async def do_slice( 1091 value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", 1092 slices: int, 1093 fill_with: t.Optional[t.Any] = None, 1094) -> "t.Iterator[t.List[V]]": 1095 return sync_do_slice(await auto_to_list(value), slices, fill_with) 1096 1097 1098def do_batch( 1099 value: "t.Iterable[V]", linecount: int, fill_with: "t.Optional[V]" = None 1100) -> "t.Iterator[t.List[V]]": 1101 """ 1102 A filter that batches items. It works pretty much like `slice` 1103 just the other way round. It returns a list of lists with the 1104 given number of items. If you provide a second parameter this 1105 is used to fill up missing items. See this example: 1106 1107 .. sourcecode:: html+jinja 1108 1109 <table> 1110 {%- for row in items|batch(3, ' ') %} 1111 <tr> 1112 {%- for column in row %} 1113 <td>{{ column }}</td> 1114 {%- endfor %} 1115 </tr> 1116 {%- endfor %} 1117 </table> 1118 """ 1119 tmp: "t.List[V]" = [] 1120 1121 for item in value: 1122 if len(tmp) == linecount: 1123 yield tmp 1124 tmp = [] 1125 1126 tmp.append(item) 1127 1128 if tmp: 1129 if fill_with is not None and len(tmp) < linecount: 1130 tmp += [fill_with] * (linecount - len(tmp)) 1131 1132 yield tmp 1133 1134 1135def do_round( 1136 value: float, 1137 precision: int = 0, 1138 method: 'te.Literal["common", "ceil", "floor"]' = "common", 1139) -> float: 1140 """Round the number to a given precision. The first 1141 parameter specifies the precision (default is ``0``), the 1142 second the rounding method: 1143 1144 - ``'common'`` rounds either up or down 1145 - ``'ceil'`` always rounds up 1146 - ``'floor'`` always rounds down 1147 1148 If you don't specify a method ``'common'`` is used. 1149 1150 .. sourcecode:: jinja 1151 1152 {{ 42.55|round }} 1153 -> 43.0 1154 {{ 42.55|round(1, 'floor') }} 1155 -> 42.5 1156 1157 Note that even if rounded to 0 precision, a float is returned. If 1158 you need a real integer, pipe it through `int`: 1159 1160 .. sourcecode:: jinja 1161 1162 {{ 42.55|round|int }} 1163 -> 43 1164 """ 1165 if method not in {"common", "ceil", "floor"}: 1166 raise FilterArgumentError("method must be common, ceil or floor") 1167 1168 if method == "common": 1169 return round(value, precision) 1170 1171 func = getattr(math, method) 1172 return t.cast(float, func(value * (10**precision)) / (10**precision)) 1173 1174 1175class _GroupTuple(t.NamedTuple): 1176 grouper: t.Any 1177 list: t.List[t.Any] 1178 1179 # Use the regular tuple repr to hide this subclass if users print 1180 # out the value during debugging. 1181 def __repr__(self) -> str: 1182 return tuple.__repr__(self) 1183 1184 def __str__(self) -> str: 1185 return tuple.__str__(self) 1186 1187 1188@pass_environment 1189def sync_do_groupby( 1190 environment: "Environment", 1191 value: "t.Iterable[V]", 1192 attribute: t.Union[str, int], 1193 default: t.Optional[t.Any] = None, 1194 case_sensitive: bool = False, 1195) -> "t.List[_GroupTuple]": 1196 """Group a sequence of objects by an attribute using Python's 1197 :func:`itertools.groupby`. The attribute can use dot notation for 1198 nested access, like ``"address.city"``. Unlike Python's ``groupby``, 1199 the values are sorted first so only one group is returned for each 1200 unique value. 1201 1202 For example, a list of ``User`` objects with a ``city`` attribute 1203 can be rendered in groups. In this example, ``grouper`` refers to 1204 the ``city`` value of the group. 1205 1206 .. sourcecode:: html+jinja 1207 1208 <ul>{% for city, items in users|groupby("city") %} 1209 <li>{{ city }} 1210 <ul>{% for user in items %} 1211 <li>{{ user.name }} 1212 {% endfor %}</ul> 1213 </li> 1214 {% endfor %}</ul> 1215 1216 ``groupby`` yields namedtuples of ``(grouper, list)``, which 1217 can be used instead of the tuple unpacking above. ``grouper`` is the 1218 value of the attribute, and ``list`` is the items with that value. 1219 1220 .. sourcecode:: html+jinja 1221 1222 <ul>{% for group in users|groupby("city") %} 1223 <li>{{ group.grouper }}: {{ group.list|join(", ") }} 1224 {% endfor %}</ul> 1225 1226 You can specify a ``default`` value to use if an object in the list 1227 does not have the given attribute. 1228 1229 .. sourcecode:: jinja 1230 1231 <ul>{% for city, items in users|groupby("city", default="NY") %} 1232 <li>{{ city }}: {{ items|map(attribute="name")|join(", ") }}</li> 1233 {% endfor %}</ul> 1234 1235 Like the :func:`~jinja-filters.sort` filter, sorting and grouping is 1236 case-insensitive by default. The ``key`` for each group will have 1237 the case of the first item in that group of values. For example, if 1238 a list of users has cities ``["CA", "NY", "ca"]``, the "CA" group 1239 will have two values. This can be disabled by passing 1240 ``case_sensitive=True``. 1241 1242 .. versionchanged:: 3.1 1243 Added the ``case_sensitive`` parameter. Sorting and grouping is 1244 case-insensitive by default, matching other filters that do 1245 comparisons. 1246 1247 .. versionchanged:: 3.0 1248 Added the ``default`` parameter. 1249 1250 .. versionchanged:: 2.6 1251 The attribute supports dot notation for nested access. 1252 """ 1253 expr = make_attrgetter( 1254 environment, 1255 attribute, 1256 postprocess=ignore_case if not case_sensitive else None, 1257 default=default, 1258 ) 1259 out = [ 1260 _GroupTuple(key, list(values)) 1261 for key, values in groupby(sorted(value, key=expr), expr) 1262 ] 1263 1264 if not case_sensitive: 1265 # Return the real key from the first value instead of the lowercase key. 1266 output_expr = make_attrgetter(environment, attribute, default=default) 1267 out = [_GroupTuple(output_expr(values[0]), values) for _, values in out] 1268 1269 return out 1270 1271 1272@async_variant(sync_do_groupby) # type: ignore 1273async def do_groupby( 1274 environment: "Environment", 1275 value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", 1276 attribute: t.Union[str, int], 1277 default: t.Optional[t.Any] = None, 1278 case_sensitive: bool = False, 1279) -> "t.List[_GroupTuple]": 1280 expr = make_attrgetter( 1281 environment, 1282 attribute, 1283 postprocess=ignore_case if not case_sensitive else None, 1284 default=default, 1285 ) 1286 out = [ 1287 _GroupTuple(key, await auto_to_list(values)) 1288 for key, values in groupby(sorted(await auto_to_list(value), key=expr), expr) 1289 ] 1290 1291 if not case_sensitive: 1292 # Return the real key from the first value instead of the lowercase key. 1293 output_expr = make_attrgetter(environment, attribute, default=default) 1294 out = [_GroupTuple(output_expr(values[0]), values) for _, values in out] 1295 1296 return out 1297 1298 1299@pass_environment 1300def sync_do_sum( 1301 environment: "Environment", 1302 iterable: "t.Iterable[V]", 1303 attribute: t.Optional[t.Union[str, int]] = None, 1304 start: V = 0, # type: ignore 1305) -> V: 1306 """Returns the sum of a sequence of numbers plus the value of parameter 1307 'start' (which defaults to 0). When the sequence is empty it returns 1308 start. 1309 1310 It is also possible to sum up only certain attributes: 1311 1312 .. sourcecode:: jinja 1313 1314 Total: {{ items|sum(attribute='price') }} 1315 1316 .. versionchanged:: 2.6 1317 The ``attribute`` parameter was added to allow summing up over 1318 attributes. Also the ``start`` parameter was moved on to the right. 1319 """ 1320 if attribute is not None: 1321 iterable = map(make_attrgetter(environment, attribute), iterable) 1322 1323 return sum(iterable, start) # type: ignore[no-any-return, call-overload] 1324 1325 1326@async_variant(sync_do_sum) # type: ignore 1327async def do_sum( 1328 environment: "Environment", 1329 iterable: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", 1330 attribute: t.Optional[t.Union[str, int]] = None, 1331 start: V = 0, # type: ignore 1332) -> V: 1333 rv = start 1334 1335 if attribute is not None: 1336 func = make_attrgetter(environment, attribute) 1337 else: 1338 1339 def func(x: V) -> V: 1340 return x 1341 1342 async for item in auto_aiter(iterable): 1343 rv += func(item) 1344 1345 return rv 1346 1347 1348def sync_do_list(value: "t.Iterable[V]") -> "t.List[V]": 1349 """Convert the value into a list. If it was a string the returned list 1350 will be a list of characters. 1351 """ 1352 return list(value) 1353 1354 1355@async_variant(sync_do_list) # type: ignore 1356async def do_list(value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]") -> "t.List[V]": 1357 return await auto_to_list(value) 1358 1359 1360def do_mark_safe(value: str) -> Markup: 1361 """Mark the value as safe which means that in an environment with automatic 1362 escaping enabled this variable will not be escaped. 1363 """ 1364 return Markup(value) 1365 1366 1367def do_mark_unsafe(value: str) -> str: 1368 """Mark a value as unsafe. This is the reverse operation for :func:`safe`.""" 1369 return str(value) 1370 1371 1372@typing.overload 1373def do_reverse(value: str) -> str: ... 1374 1375 1376@typing.overload 1377def do_reverse(value: "t.Iterable[V]") -> "t.Iterable[V]": ... 1378 1379 1380def do_reverse(value: t.Union[str, t.Iterable[V]]) -> t.Union[str, t.Iterable[V]]: 1381 """Reverse the object or return an iterator that iterates over it the other 1382 way round. 1383 """ 1384 if isinstance(value, str): 1385 return value[::-1] 1386 1387 try: 1388 return reversed(value) # type: ignore 1389 except TypeError: 1390 try: 1391 rv = list(value) 1392 rv.reverse() 1393 return rv 1394 except TypeError as e: 1395 raise FilterArgumentError("argument must be iterable") from e 1396 1397 1398@pass_environment 1399def do_attr( 1400 environment: "Environment", obj: t.Any, name: str 1401) -> t.Union[Undefined, t.Any]: 1402 """Get an attribute of an object. ``foo|attr("bar")`` works like 1403 ``foo.bar`` just that always an attribute is returned and items are not 1404 looked up. 1405 1406 See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details. 1407 """ 1408 try: 1409 name = str(name) 1410 except UnicodeError: 1411 pass 1412 else: 1413 try: 1414 value = getattr(obj, name) 1415 except AttributeError: 1416 pass 1417 else: 1418 if environment.sandboxed: 1419 environment = t.cast("SandboxedEnvironment", environment) 1420 1421 if not environment.is_safe_attribute(obj, name, value): 1422 return environment.unsafe_undefined(obj, name) 1423 1424 return value 1425 1426 return environment.undefined(obj=obj, name=name) 1427 1428 1429@typing.overload 1430def sync_do_map( 1431 context: "Context", 1432 value: t.Iterable[t.Any], 1433 name: str, 1434 *args: t.Any, 1435 **kwargs: t.Any, 1436) -> t.Iterable[t.Any]: ... 1437 1438 1439@typing.overload 1440def sync_do_map( 1441 context: "Context", 1442 value: t.Iterable[t.Any], 1443 *, 1444 attribute: str = ..., 1445 default: t.Optional[t.Any] = None, 1446) -> t.Iterable[t.Any]: ... 1447 1448 1449@pass_context 1450def sync_do_map( 1451 context: "Context", value: t.Iterable[t.Any], *args: t.Any, **kwargs: t.Any 1452) -> t.Iterable[t.Any]: 1453 """Applies a filter on a sequence of objects or looks up an attribute. 1454 This is useful when dealing with lists of objects but you are really 1455 only interested in a certain value of it. 1456 1457 The basic usage is mapping on an attribute. Imagine you have a list 1458 of users but you are only interested in a list of usernames: 1459 1460 .. sourcecode:: jinja 1461 1462 Users on this page: {{ users|map(attribute='username')|join(', ') }} 1463 1464 You can specify a ``default`` value to use if an object in the list 1465 does not have the given attribute. 1466 1467 .. sourcecode:: jinja 1468 1469 {{ users|map(attribute="username", default="Anonymous")|join(", ") }} 1470 1471 Alternatively you can let it invoke a filter by passing the name of the 1472 filter and the arguments afterwards. A good example would be applying a 1473 text conversion filter on a sequence: 1474 1475 .. sourcecode:: jinja 1476 1477 Users on this page: {{ titles|map('lower')|join(', ') }} 1478 1479 Similar to a generator comprehension such as: 1480 1481 .. code-block:: python 1482 1483 (u.username for u in users) 1484 (getattr(u, "username", "Anonymous") for u in users) 1485 (do_lower(x) for x in titles) 1486 1487 .. versionchanged:: 2.11.0 1488 Added the ``default`` parameter. 1489 1490 .. versionadded:: 2.7 1491 """ 1492 if value: 1493 func = prepare_map(context, args, kwargs) 1494 1495 for item in value: 1496 yield func(item) 1497 1498 1499@typing.overload 1500def do_map( 1501 context: "Context", 1502 value: t.Union[t.AsyncIterable[t.Any], t.Iterable[t.Any]], 1503 name: str, 1504 *args: t.Any, 1505 **kwargs: t.Any, 1506) -> t.Iterable[t.Any]: ... 1507 1508 1509@typing.overload 1510def do_map( 1511 context: "Context", 1512 value: t.Union[t.AsyncIterable[t.Any], t.Iterable[t.Any]], 1513 *, 1514 attribute: str = ..., 1515 default: t.Optional[t.Any] = None, 1516) -> t.Iterable[t.Any]: ... 1517 1518 1519@async_variant(sync_do_map) # type: ignore 1520async def do_map( 1521 context: "Context", 1522 value: t.Union[t.AsyncIterable[t.Any], t.Iterable[t.Any]], 1523 *args: t.Any, 1524 **kwargs: t.Any, 1525) -> t.AsyncIterable[t.Any]: 1526 if value: 1527 func = prepare_map(context, args, kwargs) 1528 1529 async for item in auto_aiter(value): 1530 yield await auto_await(func(item)) 1531 1532 1533@pass_context 1534def sync_do_select( 1535 context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any 1536) -> "t.Iterator[V]": 1537 """Filters a sequence of objects by applying a test to each object, 1538 and only selecting the objects with the test succeeding. 1539 1540 If no test is specified, each object will be evaluated as a boolean. 1541 1542 Example usage: 1543 1544 .. sourcecode:: jinja 1545 1546 {{ numbers|select("odd") }} 1547 {{ numbers|select("odd") }} 1548 {{ numbers|select("divisibleby", 3) }} 1549 {{ numbers|select("lessthan", 42) }} 1550 {{ strings|select("equalto", "mystring") }} 1551 1552 Similar to a generator comprehension such as: 1553 1554 .. code-block:: python 1555 1556 (n for n in numbers if test_odd(n)) 1557 (n for n in numbers if test_divisibleby(n, 3)) 1558 1559 .. versionadded:: 2.7 1560 """ 1561 return select_or_reject(context, value, args, kwargs, lambda x: x, False) 1562 1563 1564@async_variant(sync_do_select) # type: ignore 1565async def do_select( 1566 context: "Context", 1567 value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", 1568 *args: t.Any, 1569 **kwargs: t.Any, 1570) -> "t.AsyncIterator[V]": 1571 return async_select_or_reject(context, value, args, kwargs, lambda x: x, False) 1572 1573 1574@pass_context 1575def sync_do_reject( 1576 context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any 1577) -> "t.Iterator[V]": 1578 """Filters a sequence of objects by applying a test to each object, 1579 and rejecting the objects with the test succeeding. 1580 1581 If no test is specified, each object will be evaluated as a boolean. 1582 1583 Example usage: 1584 1585 .. sourcecode:: jinja 1586 1587 {{ numbers|reject("odd") }} 1588 1589 Similar to a generator comprehension such as: 1590 1591 .. code-block:: python 1592 1593 (n for n in numbers if not test_odd(n)) 1594 1595 .. versionadded:: 2.7 1596 """ 1597 return select_or_reject(context, value, args, kwargs, lambda x: not x, False) 1598 1599 1600@async_variant(sync_do_reject) # type: ignore 1601async def do_reject( 1602 context: "Context", 1603 value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", 1604 *args: t.Any, 1605 **kwargs: t.Any, 1606) -> "t.AsyncIterator[V]": 1607 return async_select_or_reject(context, value, args, kwargs, lambda x: not x, False) 1608 1609 1610@pass_context 1611def sync_do_selectattr( 1612 context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any 1613) -> "t.Iterator[V]": 1614 """Filters a sequence of objects by applying a test to the specified 1615 attribute of each object, and only selecting the objects with the 1616 test succeeding. 1617 1618 If no test is specified, the attribute's value will be evaluated as 1619 a boolean. 1620 1621 Example usage: 1622 1623 .. sourcecode:: jinja 1624 1625 {{ users|selectattr("is_active") }} 1626 {{ users|selectattr("email", "none") }} 1627 1628 Similar to a generator comprehension such as: 1629 1630 .. code-block:: python 1631 1632 (u for user in users if user.is_active) 1633 (u for user in users if test_none(user.email)) 1634 1635 .. versionadded:: 2.7 1636 """ 1637 return select_or_reject(context, value, args, kwargs, lambda x: x, True) 1638 1639 1640@async_variant(sync_do_selectattr) # type: ignore 1641async def do_selectattr( 1642 context: "Context", 1643 value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", 1644 *args: t.Any, 1645 **kwargs: t.Any, 1646) -> "t.AsyncIterator[V]": 1647 return async_select_or_reject(context, value, args, kwargs, lambda x: x, True) 1648 1649 1650@pass_context 1651def sync_do_rejectattr( 1652 context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any 1653) -> "t.Iterator[V]": 1654 """Filters a sequence of objects by applying a test to the specified 1655 attribute of each object, and rejecting the objects with the test 1656 succeeding. 1657 1658 If no test is specified, the attribute's value will be evaluated as 1659 a boolean. 1660 1661 .. sourcecode:: jinja 1662 1663 {{ users|rejectattr("is_active") }} 1664 {{ users|rejectattr("email", "none") }} 1665 1666 Similar to a generator comprehension such as: 1667 1668 .. code-block:: python 1669 1670 (u for user in users if not user.is_active) 1671 (u for user in users if not test_none(user.email)) 1672 1673 .. versionadded:: 2.7 1674 """ 1675 return select_or_reject(context, value, args, kwargs, lambda x: not x, True) 1676 1677 1678@async_variant(sync_do_rejectattr) # type: ignore 1679async def do_rejectattr( 1680 context: "Context", 1681 value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", 1682 *args: t.Any, 1683 **kwargs: t.Any, 1684) -> "t.AsyncIterator[V]": 1685 return async_select_or_reject(context, value, args, kwargs, lambda x: not x, True) 1686 1687 1688@pass_eval_context 1689def do_tojson( 1690 eval_ctx: "EvalContext", value: t.Any, indent: t.Optional[int] = None 1691) -> Markup: 1692 """Serialize an object to a string of JSON, and mark it safe to 1693 render in HTML. This filter is only for use in HTML documents. 1694 1695 The returned string is safe to render in HTML documents and 1696 ``<script>`` tags. The exception is in HTML attributes that are 1697 double quoted; either use single quotes or the ``|forceescape`` 1698 filter. 1699 1700 :param value: The object to serialize to JSON. 1701 :param indent: The ``indent`` parameter passed to ``dumps``, for 1702 pretty-printing the value. 1703 1704 .. versionadded:: 2.9 1705 """ 1706 policies = eval_ctx.environment.policies 1707 dumps = policies["json.dumps_function"] 1708 kwargs = policies["json.dumps_kwargs"] 1709 1710 if indent is not None: 1711 kwargs = kwargs.copy() 1712 kwargs["indent"] = indent 1713 1714 return htmlsafe_json_dumps(value, dumps=dumps, **kwargs) 1715 1716 1717def prepare_map( 1718 context: "Context", args: t.Tuple[t.Any, ...], kwargs: t.Dict[str, t.Any] 1719) -> t.Callable[[t.Any], t.Any]: 1720 if not args and "attribute" in kwargs: 1721 attribute = kwargs.pop("attribute") 1722 default = kwargs.pop("default", None) 1723 1724 if kwargs: 1725 raise FilterArgumentError( 1726 f"Unexpected keyword argument {next(iter(kwargs))!r}" 1727 ) 1728 1729 func = make_attrgetter(context.environment, attribute, default=default) 1730 else: 1731 try: 1732 name = args[0] 1733 args = args[1:] 1734 except LookupError: 1735 raise FilterArgumentError("map requires a filter argument") from None 1736 1737 def func(item: t.Any) -> t.Any: 1738 return context.environment.call_filter( 1739 name, item, args, kwargs, context=context 1740 ) 1741 1742 return func 1743 1744 1745def prepare_select_or_reject( 1746 context: "Context", 1747 args: t.Tuple[t.Any, ...], 1748 kwargs: t.Dict[str, t.Any], 1749 modfunc: t.Callable[[t.Any], t.Any], 1750 lookup_attr: bool, 1751) -> t.Callable[[t.Any], t.Any]: 1752 if lookup_attr: 1753 try: 1754 attr = args[0] 1755 except LookupError: 1756 raise FilterArgumentError("Missing parameter for attribute name") from None 1757 1758 transfunc = make_attrgetter(context.environment, attr) 1759 off = 1 1760 else: 1761 off = 0 1762 1763 def transfunc(x: V) -> V: 1764 return x 1765 1766 try: 1767 name = args[off] 1768 args = args[1 + off :] 1769 1770 def func(item: t.Any) -> t.Any: 1771 return context.environment.call_test(name, item, args, kwargs) 1772 1773 except LookupError: 1774 func = bool # type: ignore 1775 1776 return lambda item: modfunc(func(transfunc(item))) 1777 1778 1779def select_or_reject( 1780 context: "Context", 1781 value: "t.Iterable[V]", 1782 args: t.Tuple[t.Any, ...], 1783 kwargs: t.Dict[str, t.Any], 1784 modfunc: t.Callable[[t.Any], t.Any], 1785 lookup_attr: bool, 1786) -> "t.Iterator[V]": 1787 if value: 1788 func = prepare_select_or_reject(context, args, kwargs, modfunc, lookup_attr) 1789 1790 for item in value: 1791 if func(item): 1792 yield item 1793 1794 1795async def async_select_or_reject( 1796 context: "Context", 1797 value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", 1798 args: t.Tuple[t.Any, ...], 1799 kwargs: t.Dict[str, t.Any], 1800 modfunc: t.Callable[[t.Any], t.Any], 1801 lookup_attr: bool, 1802) -> "t.AsyncIterator[V]": 1803 if value: 1804 func = prepare_select_or_reject(context, args, kwargs, modfunc, lookup_attr) 1805 1806 async for item in auto_aiter(value): 1807 if func(item): 1808 yield item 1809 1810 1811FILTERS = { 1812 "abs": abs, 1813 "attr": do_attr, 1814 "batch": do_batch, 1815 "capitalize": do_capitalize, 1816 "center": do_center, 1817 "count": len, 1818 "d": do_default, 1819 "default": do_default, 1820 "dictsort": do_dictsort, 1821 "e": escape, 1822 "escape": escape, 1823 "filesizeformat": do_filesizeformat, 1824 "first": do_first, 1825 "float": do_float, 1826 "forceescape": do_forceescape, 1827 "format": do_format, 1828 "groupby": do_groupby, 1829 "indent": do_indent, 1830 "int": do_int, 1831 "join": do_join, 1832 "last": do_last, 1833 "length": len, 1834 "list": do_list, 1835 "lower": do_lower, 1836 "items": do_items, 1837 "map": do_map, 1838 "min": do_min, 1839 "max": do_max, 1840 "pprint": do_pprint, 1841 "random": do_random, 1842 "reject": do_reject, 1843 "rejectattr": do_rejectattr, 1844 "replace": do_replace, 1845 "reverse": do_reverse, 1846 "round": do_round, 1847 "safe": do_mark_safe, 1848 "select": do_select, 1849 "selectattr": do_selectattr, 1850 "slice": do_slice, 1851 "sort": do_sort, 1852 "string": soft_str, 1853 "striptags": do_striptags, 1854 "sum": do_sum, 1855 "title": do_title, 1856 "trim": do_trim, 1857 "truncate": do_truncate, 1858 "unique": do_unique, 1859 "upper": do_upper, 1860 "urlencode": do_urlencode, 1861 "urlize": do_urlize, 1862 "wordcount": do_wordcount, 1863 "wordwrap": do_wordwrap, 1864 "xmlattr": do_xmlattr, 1865 "tojson": do_tojson, 1866}
49def ignore_case(value: V) -> V: 50 """For use as a postprocessor for :func:`make_attrgetter`. Converts strings 51 to lowercase and returns other types as-is.""" 52 if isinstance(value, str): 53 return t.cast(V, value.lower()) 54 55 return value
For use as a postprocessor for make_attrgetter()
. Converts strings
to lowercase and returns other types as-is.
58def make_attrgetter( 59 environment: "Environment", 60 attribute: t.Optional[t.Union[str, int]], 61 postprocess: t.Optional[t.Callable[[t.Any], t.Any]] = None, 62 default: t.Optional[t.Any] = None, 63) -> t.Callable[[t.Any], t.Any]: 64 """Returns a callable that looks up the given attribute from a 65 passed object with the rules of the environment. Dots are allowed 66 to access attributes of attributes. Integer parts in paths are 67 looked up as integers. 68 """ 69 parts = _prepare_attribute_parts(attribute) 70 71 def attrgetter(item: t.Any) -> t.Any: 72 for part in parts: 73 item = environment.getitem(item, part) 74 75 if default is not None and isinstance(item, Undefined): 76 item = default 77 78 if postprocess is not None: 79 item = postprocess(item) 80 81 return item 82 83 return attrgetter
Returns a callable that looks up the given attribute from a passed object with the rules of the environment. Dots are allowed to access attributes of attributes. Integer parts in paths are looked up as integers.
86def make_multi_attrgetter( 87 environment: "Environment", 88 attribute: t.Optional[t.Union[str, int]], 89 postprocess: t.Optional[t.Callable[[t.Any], t.Any]] = None, 90) -> t.Callable[[t.Any], t.List[t.Any]]: 91 """Returns a callable that looks up the given comma separated 92 attributes from a passed object with the rules of the environment. 93 Dots are allowed to access attributes of each attribute. Integer 94 parts in paths are looked up as integers. 95 96 The value returned by the returned callable is a list of extracted 97 attribute values. 98 99 Examples of attribute: "attr1,attr2", "attr1.inner1.0,attr2.inner2.0", etc. 100 """ 101 if isinstance(attribute, str): 102 split: t.Sequence[t.Union[str, int, None]] = attribute.split(",") 103 else: 104 split = [attribute] 105 106 parts = [_prepare_attribute_parts(item) for item in split] 107 108 def attrgetter(item: t.Any) -> t.List[t.Any]: 109 items = [None] * len(parts) 110 111 for i, attribute_part in enumerate(parts): 112 item_i = item 113 114 for part in attribute_part: 115 item_i = environment.getitem(item_i, part) 116 117 if postprocess is not None: 118 item_i = postprocess(item_i) 119 120 items[i] = item_i 121 122 return items 123 124 return attrgetter
Returns a callable that looks up the given comma separated attributes from a passed object with the rules of the environment. Dots are allowed to access attributes of each attribute. Integer parts in paths are looked up as integers.
The value returned by the returned callable is a list of extracted attribute values.
Examples of attribute: "attr1,attr2", "attr1.inner1.0,attr2.inner2.0", etc.
139def do_forceescape(value: "t.Union[str, HasHTML]") -> Markup: 140 """Enforce HTML escaping. This will probably double escape variables.""" 141 if hasattr(value, "__html__"): 142 value = t.cast("HasHTML", value).__html__() 143 144 return escape(str(value))
Enforce HTML escaping. This will probably double escape variables.
147def do_urlencode( 148 value: t.Union[str, t.Mapping[str, t.Any], t.Iterable[t.Tuple[str, t.Any]]], 149) -> str: 150 """Quote data for use in a URL path or query using UTF-8. 151 152 Basic wrapper around :func:`urllib.parse.quote` when given a 153 string, or :func:`urllib.parse.urlencode` for a dict or iterable. 154 155 :param value: Data to quote. A string will be quoted directly. A 156 dict or iterable of ``(key, value)`` pairs will be joined as a 157 query string. 158 159 When given a string, "/" is not quoted. HTTP servers treat "/" and 160 "%2F" equivalently in paths. If you need quoted slashes, use the 161 ``|replace("/", "%2F")`` filter. 162 163 .. versionadded:: 2.7 164 """ 165 if isinstance(value, str) or not isinstance(value, abc.Iterable): 166 return url_quote(value) 167 168 if isinstance(value, dict): 169 items: t.Iterable[t.Tuple[str, t.Any]] = value.items() 170 else: 171 items = value # type: ignore 172 173 return "&".join( 174 f"{url_quote(k, for_qs=True)}={url_quote(v, for_qs=True)}" for k, v in items 175 )
Quote data for use in a URL path or query using UTF-8.
Basic wrapper around urllib.parse.quote()
when given a
string, or urllib.parse.urlencode()
for a dict or iterable.
Parameters
- value: Data to quote. A string will be quoted directly. A
dict or iterable of
(key, value)
pairs will be joined as a query string.
When given a string, "/" is not quoted. HTTP servers treat "/" and
"%2F" equivalently in paths. If you need quoted slashes, use the
|replace("/", "%2F")
filter.
New in version 2.7.
178@pass_eval_context 179def do_replace( 180 eval_ctx: "EvalContext", s: str, old: str, new: str, count: t.Optional[int] = None 181) -> str: 182 """Return a copy of the value with all occurrences of a substring 183 replaced with a new one. The first argument is the substring 184 that should be replaced, the second is the replacement string. 185 If the optional third argument ``count`` is given, only the first 186 ``count`` occurrences are replaced: 187 188 .. sourcecode:: jinja 189 190 {{ "Hello World"|replace("Hello", "Goodbye") }} 191 -> Goodbye World 192 193 {{ "aaaaargh"|replace("a", "d'oh, ", 2) }} 194 -> d'oh, d'oh, aaargh 195 """ 196 if count is None: 197 count = -1 198 199 if not eval_ctx.autoescape: 200 return str(s).replace(str(old), str(new), count) 201 202 if ( 203 hasattr(old, "__html__") 204 or hasattr(new, "__html__") 205 and not hasattr(s, "__html__") 206 ): 207 s = escape(s) 208 else: 209 s = soft_str(s) 210 211 return s.replace(soft_str(old), soft_str(new), count)
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
214def do_upper(s: str) -> str: 215 """Convert a value to uppercase.""" 216 return soft_str(s).upper()
Convert a value to uppercase.
219def do_lower(s: str) -> str: 220 """Convert a value to lowercase.""" 221 return soft_str(s).lower()
Convert a value to lowercase.
224def do_items(value: t.Union[t.Mapping[K, V], Undefined]) -> t.Iterator[t.Tuple[K, V]]: 225 """Return an iterator over the ``(key, value)`` items of a mapping. 226 227 ``x|items`` is the same as ``x.items()``, except if ``x`` is 228 undefined an empty iterator is returned. 229 230 This filter is useful if you expect the template to be rendered with 231 an implementation of Jinja in another programming language that does 232 not have a ``.items()`` method on its mapping type. 233 234 .. code-block:: html+jinja 235 236 <dl> 237 {% for key, value in my_dict|items %} 238 <dt>{{ key }} 239 <dd>{{ value }} 240 {% endfor %} 241 </dl> 242 243 .. versionadded:: 3.1 244 """ 245 if isinstance(value, Undefined): 246 return 247 248 if not isinstance(value, abc.Mapping): 249 raise TypeError("Can only get item pairs from a mapping.") 250 251 yield from value.items()
Return an iterator over the (key, value)
items of a mapping.
x|items
is the same as x.items()
, except if x
is
undefined an empty iterator is returned.
This filter is useful if you expect the template to be rendered with
an implementation of Jinja in another programming language that does
not have a .items()
method on its mapping type.
<dl>
{% for key, value in my_dict|items %}
<dt>{{ key }}
<dd>{{ value }}
{% endfor %}
</dl>
New in version 3.1.
259@pass_eval_context 260def do_xmlattr( 261 eval_ctx: "EvalContext", d: t.Mapping[str, t.Any], autospace: bool = True 262) -> str: 263 """Create an SGML/XML attribute string based on the items in a dict. 264 265 **Values** that are neither ``none`` nor ``undefined`` are automatically 266 escaped, safely allowing untrusted user input. 267 268 User input should not be used as **keys** to this filter. If any key 269 contains a space, ``/`` solidus, ``>`` greater-than sign, or ``=`` equals 270 sign, this fails with a ``ValueError``. Regardless of this, user input 271 should never be used as keys to this filter, or must be separately validated 272 first. 273 274 .. sourcecode:: html+jinja 275 276 <ul{{ {'class': 'my_list', 'missing': none, 277 'id': 'list-%d'|format(variable)}|xmlattr }}> 278 ... 279 </ul> 280 281 Results in something like this: 282 283 .. sourcecode:: html 284 285 <ul class="my_list" id="list-42"> 286 ... 287 </ul> 288 289 As you can see it automatically prepends a space in front of the item 290 if the filter returned something unless the second parameter is false. 291 292 .. versionchanged:: 3.1.4 293 Keys with ``/`` solidus, ``>`` greater-than sign, or ``=`` equals sign 294 are not allowed. 295 296 .. versionchanged:: 3.1.3 297 Keys with spaces are not allowed. 298 """ 299 items = [] 300 301 for key, value in d.items(): 302 if value is None or isinstance(value, Undefined): 303 continue 304 305 if _attr_key_re.search(key) is not None: 306 raise ValueError(f"Invalid character in attribute name: {key!r}") 307 308 items.append(f'{escape(key)}="{escape(value)}"') 309 310 rv = " ".join(items) 311 312 if autospace and rv: 313 rv = " " + rv 314 315 if eval_ctx.autoescape: 316 rv = Markup(rv) 317 318 return rv
Create an SGML/XML attribute string based on the items in a dict.
Values that are neither none
nor undefined
are automatically
escaped, safely allowing untrusted user input.
User input should not be used as keys to this filter. If any key
contains a space, /
solidus, >
greater-than sign, or =
equals
sign, this fails with a ValueError
. Regardless of this, user input
should never be used as keys to this filter, or must be separately validated
first.
.. 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.
Changed in version 3.1.4:
Keys with /
solidus, >
greater-than sign, or =
equals sign
are not allowed.
Changed in version 3.1.3: Keys with spaces are not allowed.
321def do_capitalize(s: str) -> str: 322 """Capitalize a value. The first character will be uppercase, all others 323 lowercase. 324 """ 325 return soft_str(s).capitalize()
Capitalize a value. The first character will be uppercase, all others lowercase.
331def do_title(s: str) -> str: 332 """Return a titlecased version of the value. I.e. words will start with 333 uppercase letters, all remaining characters are lowercase. 334 """ 335 return "".join( 336 [ 337 item[0].upper() + item[1:].lower() 338 for item in _word_beginning_split_re.split(soft_str(s)) 339 if item 340 ] 341 )
Return a titlecased version of the value. I.e. words will start with uppercase letters, all remaining characters are lowercase.
344def do_dictsort( 345 value: t.Mapping[K, V], 346 case_sensitive: bool = False, 347 by: 'te.Literal["key", "value"]' = "key", 348 reverse: bool = False, 349) -> t.List[t.Tuple[K, V]]: 350 """Sort a dict and yield (key, value) pairs. Python dicts may not 351 be in the order you want to display them in, so sort them first. 352 353 .. sourcecode:: jinja 354 355 {% for key, value in mydict|dictsort %} 356 sort the dict by key, case insensitive 357 358 {% for key, value in mydict|dictsort(reverse=true) %} 359 sort the dict by key, case insensitive, reverse order 360 361 {% for key, value in mydict|dictsort(true) %} 362 sort the dict by key, case sensitive 363 364 {% for key, value in mydict|dictsort(false, 'value') %} 365 sort the dict by value, case insensitive 366 """ 367 if by == "key": 368 pos = 0 369 elif by == "value": 370 pos = 1 371 else: 372 raise FilterArgumentError('You can only sort by either "key" or "value"') 373 374 def sort_func(item: t.Tuple[t.Any, t.Any]) -> t.Any: 375 value = item[pos] 376 377 if not case_sensitive: 378 value = ignore_case(value) 379 380 return value 381 382 return sorted(value.items(), key=sort_func, reverse=reverse)
Sort a dict and yield (key, value) pairs. Python dicts may not be in the order you want to display them in, so sort them first.
.. sourcecode:: jinja
{% for key, value in mydict|dictsort %}
sort the dict by key, case insensitive
{% for key, value in mydict|dictsort(reverse=true) %}
sort the dict by key, case insensitive, reverse order
{% for key, value in mydict|dictsort(true) %}
sort the dict by key, case sensitive
{% for key, value in mydict|dictsort(false, 'value') %}
sort the dict by value, case insensitive
385@pass_environment 386def do_sort( 387 environment: "Environment", 388 value: "t.Iterable[V]", 389 reverse: bool = False, 390 case_sensitive: bool = False, 391 attribute: t.Optional[t.Union[str, int]] = None, 392) -> "t.List[V]": 393 """Sort an iterable using Python's :func:`sorted`. 394 395 .. sourcecode:: jinja 396 397 {% for city in cities|sort %} 398 ... 399 {% endfor %} 400 401 :param reverse: Sort descending instead of ascending. 402 :param case_sensitive: When sorting strings, sort upper and lower 403 case separately. 404 :param attribute: When sorting objects or dicts, an attribute or 405 key to sort by. Can use dot notation like ``"address.city"``. 406 Can be a list of attributes like ``"age,name"``. 407 408 The sort is stable, it does not change the relative order of 409 elements that compare equal. This makes it is possible to chain 410 sorts on different attributes and ordering. 411 412 .. sourcecode:: jinja 413 414 {% for user in users|sort(attribute="name") 415 |sort(reverse=true, attribute="age") %} 416 ... 417 {% endfor %} 418 419 As a shortcut to chaining when the direction is the same for all 420 attributes, pass a comma separate list of attributes. 421 422 .. sourcecode:: jinja 423 424 {% for user in users|sort(attribute="age,name") %} 425 ... 426 {% endfor %} 427 428 .. versionchanged:: 2.11.0 429 The ``attribute`` parameter can be a comma separated list of 430 attributes, e.g. ``"age,name"``. 431 432 .. versionchanged:: 2.6 433 The ``attribute`` parameter was added. 434 """ 435 key_func = make_multi_attrgetter( 436 environment, attribute, postprocess=ignore_case if not case_sensitive else None 437 ) 438 return sorted(value, key=key_func, reverse=reverse)
Sort an iterable using Python's sorted()
.
.. sourcecode:: jinja
{% for city in cities|sort %}
...
{% endfor %}
Parameters
- reverse: Sort descending instead of ascending.
- case_sensitive: When sorting strings, sort upper and lower case separately.
- attribute: When sorting objects or dicts, an attribute or
key to sort by. Can use dot notation like
"address.city"
. Can be a list of attributes like"age,name"
.
The sort is stable, it does not change the relative order of elements that compare equal. This makes it is possible to chain sorts on different attributes and ordering.
.. sourcecode:: jinja
{% for user in users|sort(attribute="name")
|sort(reverse=true, attribute="age") %}
...
{% endfor %}
As a shortcut to chaining when the direction is the same for all attributes, pass a comma separate list of attributes.
.. sourcecode:: jinja
{% for user in users|sort(attribute="age,name") %}
...
{% endfor %}
Changed in version 2.11.0:
The attribute
parameter can be a comma separated list of
attributes, e.g. "age,name"
.
Changed in version 2.6:
The attribute
parameter was added.
441@pass_environment 442def do_unique( 443 environment: "Environment", 444 value: "t.Iterable[V]", 445 case_sensitive: bool = False, 446 attribute: t.Optional[t.Union[str, int]] = None, 447) -> "t.Iterator[V]": 448 """Returns a list of unique items from the given iterable. 449 450 .. sourcecode:: jinja 451 452 {{ ['foo', 'bar', 'foobar', 'FooBar']|unique|list }} 453 -> ['foo', 'bar', 'foobar'] 454 455 The unique items are yielded in the same order as their first occurrence in 456 the iterable passed to the filter. 457 458 :param case_sensitive: Treat upper and lower case strings as distinct. 459 :param attribute: Filter objects with unique values for this attribute. 460 """ 461 getter = make_attrgetter( 462 environment, attribute, postprocess=ignore_case if not case_sensitive else None 463 ) 464 seen = set() 465 466 for item in value: 467 key = getter(item) 468 469 if key not in seen: 470 seen.add(key) 471 yield item
Returns a list of unique items from the given iterable.
.. sourcecode:: jinja
{{ ['foo', 'bar', 'foobar', 'FooBar']|unique|list }}
-> ['foo', 'bar', 'foobar']
The unique items are yielded in the same order as their first occurrence in the iterable passed to the filter.
Parameters
- case_sensitive: Treat upper and lower case strings as distinct.
- attribute: Filter objects with unique values for this attribute.
494@pass_environment 495def do_min( 496 environment: "Environment", 497 value: "t.Iterable[V]", 498 case_sensitive: bool = False, 499 attribute: t.Optional[t.Union[str, int]] = None, 500) -> "t.Union[V, Undefined]": 501 """Return the smallest item from the sequence. 502 503 .. sourcecode:: jinja 504 505 {{ [1, 2, 3]|min }} 506 -> 1 507 508 :param case_sensitive: Treat upper and lower case strings as distinct. 509 :param attribute: Get the object with the min value of this attribute. 510 """ 511 return _min_or_max(environment, value, min, case_sensitive, attribute)
Return the smallest item from the sequence.
.. sourcecode:: jinja
{{ [1, 2, 3]|min }}
-> 1
Parameters
- case_sensitive: Treat upper and lower case strings as distinct.
- attribute: Get the object with the min value of this attribute.
514@pass_environment 515def do_max( 516 environment: "Environment", 517 value: "t.Iterable[V]", 518 case_sensitive: bool = False, 519 attribute: t.Optional[t.Union[str, int]] = None, 520) -> "t.Union[V, Undefined]": 521 """Return the largest item from the sequence. 522 523 .. sourcecode:: jinja 524 525 {{ [1, 2, 3]|max }} 526 -> 3 527 528 :param case_sensitive: Treat upper and lower case strings as distinct. 529 :param attribute: Get the object with the max value of this attribute. 530 """ 531 return _min_or_max(environment, value, max, case_sensitive, attribute)
Return the largest item from the sequence.
.. sourcecode:: jinja
{{ [1, 2, 3]|max }}
-> 3
Parameters
- case_sensitive: Treat upper and lower case strings as distinct.
- attribute: Get the object with the max value of this attribute.
534def do_default( 535 value: V, 536 default_value: V = "", # type: ignore 537 boolean: bool = False, 538) -> V: 539 """If the value is undefined it will return the passed default value, 540 otherwise the value of the variable: 541 542 .. sourcecode:: jinja 543 544 {{ my_variable|default('my_variable is not defined') }} 545 546 This will output the value of ``my_variable`` if the variable was 547 defined, otherwise ``'my_variable is not defined'``. If you want 548 to use default with variables that evaluate to false you have to 549 set the second parameter to `true`: 550 551 .. sourcecode:: jinja 552 553 {{ ''|default('the string was empty', true) }} 554 555 .. versionchanged:: 2.11 556 It's now possible to configure the :class:`~jinja2.Environment` with 557 :class:`~jinja2.ChainableUndefined` to make the `default` filter work 558 on nested elements and attributes that may contain undefined values 559 in the chain without getting an :exc:`~jinja2.UndefinedError`. 560 """ 561 if isinstance(value, Undefined) or (boolean and not value): 562 return default_value 563 564 return value
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) }}
Changed in version 2.11:
It's now possible to configure the ~jinja2.Environment
with
~jinja2.ChainableUndefined
to make the default
filter work
on nested elements and attributes that may contain undefined values
in the chain without getting an ~jinja2.UndefinedError
.
567@pass_eval_context 568def sync_do_join( 569 eval_ctx: "EvalContext", 570 value: t.Iterable[t.Any], 571 d: str = "", 572 attribute: t.Optional[t.Union[str, int]] = None, 573) -> str: 574 """Return a string which is the concatenation of the strings in the 575 sequence. The separator between elements is an empty string per 576 default, you can define it with the optional parameter: 577 578 .. sourcecode:: jinja 579 580 {{ [1, 2, 3]|join('|') }} 581 -> 1|2|3 582 583 {{ [1, 2, 3]|join }} 584 -> 123 585 586 It is also possible to join certain attributes of an object: 587 588 .. sourcecode:: jinja 589 590 {{ users|join(', ', attribute='username') }} 591 592 .. versionadded:: 2.6 593 The `attribute` parameter was added. 594 """ 595 if attribute is not None: 596 value = map(make_attrgetter(eval_ctx.environment, attribute), value) 597 598 # no automatic escaping? joining is a lot easier then 599 if not eval_ctx.autoescape: 600 return str(d).join(map(str, value)) 601 602 # if the delimiter doesn't have an html representation we check 603 # if any of the items has. If yes we do a coercion to Markup 604 if not hasattr(d, "__html__"): 605 value = list(value) 606 do_escape = False 607 608 for idx, item in enumerate(value): 609 if hasattr(item, "__html__"): 610 do_escape = True 611 else: 612 value[idx] = str(item) 613 614 if do_escape: 615 d = escape(d) 616 else: 617 d = str(d) 618 619 return d.join(value) 620 621 # no html involved, to normal joining 622 return soft_str(d).join(map(soft_str, value))
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') }}
New in version 2.6:
The attribute
parameter was added.
567@pass_eval_context 568def sync_do_join( 569 eval_ctx: "EvalContext", 570 value: t.Iterable[t.Any], 571 d: str = "", 572 attribute: t.Optional[t.Union[str, int]] = None, 573) -> str: 574 """Return a string which is the concatenation of the strings in the 575 sequence. The separator between elements is an empty string per 576 default, you can define it with the optional parameter: 577 578 .. sourcecode:: jinja 579 580 {{ [1, 2, 3]|join('|') }} 581 -> 1|2|3 582 583 {{ [1, 2, 3]|join }} 584 -> 123 585 586 It is also possible to join certain attributes of an object: 587 588 .. sourcecode:: jinja 589 590 {{ users|join(', ', attribute='username') }} 591 592 .. versionadded:: 2.6 593 The `attribute` parameter was added. 594 """ 595 if attribute is not None: 596 value = map(make_attrgetter(eval_ctx.environment, attribute), value) 597 598 # no automatic escaping? joining is a lot easier then 599 if not eval_ctx.autoescape: 600 return str(d).join(map(str, value)) 601 602 # if the delimiter doesn't have an html representation we check 603 # if any of the items has. If yes we do a coercion to Markup 604 if not hasattr(d, "__html__"): 605 value = list(value) 606 do_escape = False 607 608 for idx, item in enumerate(value): 609 if hasattr(item, "__html__"): 610 do_escape = True 611 else: 612 value[idx] = str(item) 613 614 if do_escape: 615 d = escape(d) 616 else: 617 d = str(d) 618 619 return d.join(value) 620 621 # no html involved, to normal joining 622 return soft_str(d).join(map(soft_str, value))
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') }}
New in version 2.6:
The attribute
parameter was added.
635def do_center(value: str, width: int = 80) -> str: 636 """Centers the value in a field of a given width.""" 637 return soft_str(value).center(width)
Centers the value in a field of a given width.
640@pass_environment 641def sync_do_first( 642 environment: "Environment", seq: "t.Iterable[V]" 643) -> "t.Union[V, Undefined]": 644 """Return the first item of a sequence.""" 645 try: 646 return next(iter(seq)) 647 except StopIteration: 648 return environment.undefined("No first item, sequence was empty.")
Return the first item of a sequence.
640@pass_environment 641def sync_do_first( 642 environment: "Environment", seq: "t.Iterable[V]" 643) -> "t.Union[V, Undefined]": 644 """Return the first item of a sequence.""" 645 try: 646 return next(iter(seq)) 647 except StopIteration: 648 return environment.undefined("No first item, sequence was empty.")
Return the first item of a sequence.
661@pass_environment 662def do_last( 663 environment: "Environment", seq: "t.Reversible[V]" 664) -> "t.Union[V, Undefined]": 665 """Return the last item of a sequence. 666 667 Note: Does not work with generators. You may want to explicitly 668 convert it to a list: 669 670 .. sourcecode:: jinja 671 672 {{ data | selectattr('name', '==', 'Jinja') | list | last }} 673 """ 674 try: 675 return next(iter(reversed(seq))) 676 except StopIteration: 677 return environment.undefined("No last item, sequence was empty.")
Return the last item of a sequence.
Note: Does not work with generators. You may want to explicitly convert it to a list:
.. sourcecode:: jinja
{{ data | selectattr('name', '==', 'Jinja') | list | last }}
683@pass_context 684def do_random(context: "Context", seq: "t.Sequence[V]") -> "t.Union[V, Undefined]": 685 """Return a random item from the sequence.""" 686 try: 687 return random.choice(seq) 688 except IndexError: 689 return context.environment.undefined("No random item, sequence was empty.")
Return a random item from the sequence.
692def do_filesizeformat(value: t.Union[str, float, int], binary: bool = False) -> str: 693 """Format the value like a 'human-readable' file size (i.e. 13 kB, 694 4.1 MB, 102 Bytes, etc). Per default decimal prefixes are used (Mega, 695 Giga, etc.), if the second parameter is set to `True` the binary 696 prefixes are used (Mebi, Gibi). 697 """ 698 bytes = float(value) 699 base = 1024 if binary else 1000 700 prefixes = [ 701 ("KiB" if binary else "kB"), 702 ("MiB" if binary else "MB"), 703 ("GiB" if binary else "GB"), 704 ("TiB" if binary else "TB"), 705 ("PiB" if binary else "PB"), 706 ("EiB" if binary else "EB"), 707 ("ZiB" if binary else "ZB"), 708 ("YiB" if binary else "YB"), 709 ] 710 711 if bytes == 1: 712 return "1 Byte" 713 elif bytes < base: 714 return f"{int(bytes)} Bytes" 715 else: 716 for i, prefix in enumerate(prefixes): 717 unit = base ** (i + 2) 718 719 if bytes < unit: 720 return f"{base * bytes / unit:.1f} {prefix}" 721 722 return f"{base * bytes / unit:.1f} {prefix}"
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).
725def do_pprint(value: t.Any) -> str: 726 """Pretty print a variable. Useful for debugging.""" 727 return pformat(value)
Pretty print a variable. Useful for debugging.
733@pass_eval_context 734def do_urlize( 735 eval_ctx: "EvalContext", 736 value: str, 737 trim_url_limit: t.Optional[int] = None, 738 nofollow: bool = False, 739 target: t.Optional[str] = None, 740 rel: t.Optional[str] = None, 741 extra_schemes: t.Optional[t.Iterable[str]] = None, 742) -> str: 743 """Convert URLs in text into clickable links. 744 745 This may not recognize links in some situations. Usually, a more 746 comprehensive formatter, such as a Markdown library, is a better 747 choice. 748 749 Works on ``http://``, ``https://``, ``www.``, ``mailto:``, and email 750 addresses. Links with trailing punctuation (periods, commas, closing 751 parentheses) and leading punctuation (opening parentheses) are 752 recognized excluding the punctuation. Email addresses that include 753 header fields are not recognized (for example, 754 ``mailto:address@example.com?cc=copy@example.com``). 755 756 :param value: Original text containing URLs to link. 757 :param trim_url_limit: Shorten displayed URL values to this length. 758 :param nofollow: Add the ``rel=nofollow`` attribute to links. 759 :param target: Add the ``target`` attribute to links. 760 :param rel: Add the ``rel`` attribute to links. 761 :param extra_schemes: Recognize URLs that start with these schemes 762 in addition to the default behavior. Defaults to 763 ``env.policies["urlize.extra_schemes"]``, which defaults to no 764 extra schemes. 765 766 .. versionchanged:: 3.0 767 The ``extra_schemes`` parameter was added. 768 769 .. versionchanged:: 3.0 770 Generate ``https://`` links for URLs without a scheme. 771 772 .. versionchanged:: 3.0 773 The parsing rules were updated. Recognize email addresses with 774 or without the ``mailto:`` scheme. Validate IP addresses. Ignore 775 parentheses and brackets in more cases. 776 777 .. versionchanged:: 2.8 778 The ``target`` parameter was added. 779 """ 780 policies = eval_ctx.environment.policies 781 rel_parts = set((rel or "").split()) 782 783 if nofollow: 784 rel_parts.add("nofollow") 785 786 rel_parts.update((policies["urlize.rel"] or "").split()) 787 rel = " ".join(sorted(rel_parts)) or None 788 789 if target is None: 790 target = policies["urlize.target"] 791 792 if extra_schemes is None: 793 extra_schemes = policies["urlize.extra_schemes"] or () 794 795 for scheme in extra_schemes: 796 if _uri_scheme_re.fullmatch(scheme) is None: 797 raise FilterArgumentError(f"{scheme!r} is not a valid URI scheme prefix.") 798 799 rv = urlize( 800 value, 801 trim_url_limit=trim_url_limit, 802 rel=rel, 803 target=target, 804 extra_schemes=extra_schemes, 805 ) 806 807 if eval_ctx.autoescape: 808 rv = Markup(rv) 809 810 return rv
Convert URLs in text into clickable links.
This may not recognize links in some situations. Usually, a more comprehensive formatter, such as a Markdown library, is a better choice.
Works on http://
, https://
, www.
, mailto:
, and email
addresses. Links with trailing punctuation (periods, commas, closing
parentheses) and leading punctuation (opening parentheses) are
recognized excluding the punctuation. Email addresses that include
header fields are not recognized (for example,
mailto:address@example.com?cc=copy@example.com
).
Parameters
- value: Original text containing URLs to link.
- trim_url_limit: Shorten displayed URL values to this length.
- nofollow: Add the
rel=nofollow
attribute to links. - target: Add the
target
attribute to links. - rel: Add the
rel
attribute to links. - extra_schemes: Recognize URLs that start with these schemes
in addition to the default behavior. Defaults to
env.policies["urlize.extra_schemes"]
, which defaults to no extra schemes.
Changed in version 3.0:
The extra_schemes
parameter was added.
Changed in version 3.0:
Generate https://
links for URLs without a scheme.
Changed in version 3.0:
The parsing rules were updated. Recognize email addresses with
or without the mailto:
scheme. Validate IP addresses. Ignore
parentheses and brackets in more cases.
Changed in version 2.8:
The target
parameter was added.
813def do_indent( 814 s: str, width: t.Union[int, str] = 4, first: bool = False, blank: bool = False 815) -> str: 816 """Return a copy of the string with each line indented by 4 spaces. The 817 first line and blank lines are not indented by default. 818 819 :param width: Number of spaces, or a string, to indent by. 820 :param first: Don't skip indenting the first line. 821 :param blank: Don't skip indenting empty lines. 822 823 .. versionchanged:: 3.0 824 ``width`` can be a string. 825 826 .. versionchanged:: 2.10 827 Blank lines are not indented by default. 828 829 Rename the ``indentfirst`` argument to ``first``. 830 """ 831 if isinstance(width, str): 832 indention = width 833 else: 834 indention = " " * width 835 836 newline = "\n" 837 838 if isinstance(s, Markup): 839 indention = Markup(indention) 840 newline = Markup(newline) 841 842 s += newline # this quirk is necessary for splitlines method 843 844 if blank: 845 rv = (newline + indention).join(s.splitlines()) 846 else: 847 lines = s.splitlines() 848 rv = lines.pop(0) 849 850 if lines: 851 rv += newline + newline.join( 852 indention + line if line else line for line in lines 853 ) 854 855 if first: 856 rv = indention + rv 857 858 return rv
Return a copy of the string with each line indented by 4 spaces. The first line and blank lines are not indented by default.
Parameters
- width: Number of spaces, or a string, to indent by.
- first: Don't skip indenting the first line.
- blank: Don't skip indenting empty lines.
Changed in version 3.0:
width
can be a string.
Changed in version 2.10: Blank lines are not indented by default.
Rename the indentfirst
argument to first
.
861@pass_environment 862def do_truncate( 863 env: "Environment", 864 s: str, 865 length: int = 255, 866 killwords: bool = False, 867 end: str = "...", 868 leeway: t.Optional[int] = None, 869) -> str: 870 """Return a truncated copy of the string. The length is specified 871 with the first parameter which defaults to ``255``. If the second 872 parameter is ``true`` the filter will cut the text at length. Otherwise 873 it will discard the last word. If the text was in fact 874 truncated it will append an ellipsis sign (``"..."``). If you want a 875 different ellipsis sign than ``"..."`` you can specify it using the 876 third parameter. Strings that only exceed the length by the tolerance 877 margin given in the fourth parameter will not be truncated. 878 879 .. sourcecode:: jinja 880 881 {{ "foo bar baz qux"|truncate(9) }} 882 -> "foo..." 883 {{ "foo bar baz qux"|truncate(9, True) }} 884 -> "foo ba..." 885 {{ "foo bar baz qux"|truncate(11) }} 886 -> "foo bar baz qux" 887 {{ "foo bar baz qux"|truncate(11, False, '...', 0) }} 888 -> "foo bar..." 889 890 The default leeway on newer Jinja versions is 5 and was 0 before but 891 can be reconfigured globally. 892 """ 893 if leeway is None: 894 leeway = env.policies["truncate.leeway"] 895 896 assert length >= len(end), f"expected length >= {len(end)}, got {length}" 897 assert leeway >= 0, f"expected leeway >= 0, got {leeway}" 898 899 if len(s) <= length + leeway: 900 return s 901 902 if killwords: 903 return s[: length - len(end)] + end 904 905 result = s[: length - len(end)].rsplit(" ", 1)[0] 906 return result + end
Return a truncated copy of the string. The length is specified
with the first parameter which defaults to 255
. If the second
parameter is true
the filter will cut the text at length. Otherwise
it will discard the last word. If the text was in fact
truncated it will append an ellipsis sign ("..."
). If you want a
different ellipsis sign than "..."
you can specify it using the
third parameter. Strings that only exceed the length by the tolerance
margin given in the fourth parameter will not be truncated.
.. sourcecode:: jinja
{{ "foo bar baz qux"|truncate(9) }}
-> "foo..."
{{ "foo bar baz qux"|truncate(9, True) }}
-> "foo ba..."
{{ "foo bar baz qux"|truncate(11) }}
-> "foo bar baz qux"
{{ "foo bar baz qux"|truncate(11, False, '...', 0) }}
-> "foo bar..."
The default leeway on newer Jinja versions is 5 and was 0 before but can be reconfigured globally.
909@pass_environment 910def do_wordwrap( 911 environment: "Environment", 912 s: str, 913 width: int = 79, 914 break_long_words: bool = True, 915 wrapstring: t.Optional[str] = None, 916 break_on_hyphens: bool = True, 917) -> str: 918 """Wrap a string to the given width. Existing newlines are treated 919 as paragraphs to be wrapped separately. 920 921 :param s: Original text to wrap. 922 :param width: Maximum length of wrapped lines. 923 :param break_long_words: If a word is longer than ``width``, break 924 it across lines. 925 :param break_on_hyphens: If a word contains hyphens, it may be split 926 across lines. 927 :param wrapstring: String to join each wrapped line. Defaults to 928 :attr:`Environment.newline_sequence`. 929 930 .. versionchanged:: 2.11 931 Existing newlines are treated as paragraphs wrapped separately. 932 933 .. versionchanged:: 2.11 934 Added the ``break_on_hyphens`` parameter. 935 936 .. versionchanged:: 2.7 937 Added the ``wrapstring`` parameter. 938 """ 939 import textwrap 940 941 if wrapstring is None: 942 wrapstring = environment.newline_sequence 943 944 # textwrap.wrap doesn't consider existing newlines when wrapping. 945 # If the string has a newline before width, wrap will still insert 946 # a newline at width, resulting in a short line. Instead, split and 947 # wrap each paragraph individually. 948 return wrapstring.join( 949 [ 950 wrapstring.join( 951 textwrap.wrap( 952 line, 953 width=width, 954 expand_tabs=False, 955 replace_whitespace=False, 956 break_long_words=break_long_words, 957 break_on_hyphens=break_on_hyphens, 958 ) 959 ) 960 for line in s.splitlines() 961 ] 962 )
Wrap a string to the given width. Existing newlines are treated as paragraphs to be wrapped separately.
Parameters
- s: Original text to wrap.
- width: Maximum length of wrapped lines.
- break_long_words: If a word is longer than
width
, break it across lines. - break_on_hyphens: If a word contains hyphens, it may be split across lines.
- wrapstring: String to join each wrapped line. Defaults to
Environment.newline_sequence
.
Changed in version 2.11: Existing newlines are treated as paragraphs wrapped separately.
Changed in version 2.11:
Added the break_on_hyphens
parameter.
Changed in version 2.7:
Added the wrapstring
parameter.
968def do_wordcount(s: str) -> int: 969 """Count the words in that string.""" 970 return len(_word_re.findall(soft_str(s)))
Count the words in that string.
973def do_int(value: t.Any, default: int = 0, base: int = 10) -> int: 974 """Convert the value into an integer. If the 975 conversion doesn't work it will return ``0``. You can 976 override this default using the first parameter. You 977 can also override the default base (10) in the second 978 parameter, which handles input with prefixes such as 979 0b, 0o and 0x for bases 2, 8 and 16 respectively. 980 The base is ignored for decimal numbers and non-string values. 981 """ 982 try: 983 if isinstance(value, str): 984 return int(value, base) 985 986 return int(value) 987 except (TypeError, ValueError): 988 # this quirk is necessary so that "42.23"|int gives 42. 989 try: 990 return int(float(value)) 991 except (TypeError, ValueError): 992 return default
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. You
can also override the default base (10) in the second
parameter, which handles input with prefixes such as
0b, 0o and 0x for bases 2, 8 and 16 respectively.
The base is ignored for decimal numbers and non-string values.
995def do_float(value: t.Any, default: float = 0.0) -> float: 996 """Convert the value into a floating point number. If the 997 conversion doesn't work it will return ``0.0``. You can 998 override this default using the first parameter. 999 """ 1000 try: 1001 return float(value) 1002 except (TypeError, ValueError): 1003 return default
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.
1006def do_format(value: str, *args: t.Any, **kwargs: t.Any) -> str: 1007 """Apply the given values to a `printf-style`_ format string, like 1008 ``string % values``. 1009 1010 .. sourcecode:: jinja 1011 1012 {{ "%s, %s!"|format(greeting, name) }} 1013 Hello, World! 1014 1015 In most cases it should be more convenient and efficient to use the 1016 ``%`` operator or :meth:`str.format`. 1017 1018 .. code-block:: text 1019 1020 {{ "%s, %s!" % (greeting, name) }} 1021 {{ "{}, {}!".format(greeting, name) }} 1022 1023 .. _printf-style: https://docs.python.org/library/stdtypes.html 1024 #printf-style-string-formatting 1025 """ 1026 if args and kwargs: 1027 raise FilterArgumentError( 1028 "can't handle positional and keyword arguments at the same time" 1029 ) 1030 1031 return soft_str(value) % (kwargs or args)
Apply the given values to a printf-style format string, like
string % values
.
.. sourcecode:: jinja
{{ "%s, %s!"|format(greeting, name) }}
Hello, World!
In most cases it should be more convenient and efficient to use the
%
operator or str.format()
.
{{ "%s, %s!" % (greeting, name) }}
{{ "{}, {}!".format(greeting, name) }}
#printf-style-string-formatting
1034def do_trim(value: str, chars: t.Optional[str] = None) -> str: 1035 """Strip leading and trailing characters, by default whitespace.""" 1036 return soft_str(value).strip(chars)
Strip leading and trailing characters, by default whitespace.
1047def sync_do_slice( 1048 value: "t.Collection[V]", slices: int, fill_with: "t.Optional[V]" = None 1049) -> "t.Iterator[t.List[V]]": 1050 """Slice an iterator and return a list of lists containing 1051 those items. Useful if you want to create a div containing 1052 three ul tags that represent columns: 1053 1054 .. sourcecode:: html+jinja 1055 1056 <div class="columnwrapper"> 1057 {%- for column in items|slice(3) %} 1058 <ul class="column-{{ loop.index }}"> 1059 {%- for item in column %} 1060 <li>{{ item }}</li> 1061 {%- endfor %} 1062 </ul> 1063 {%- endfor %} 1064 </div> 1065 1066 If you pass it a second argument it's used to fill missing 1067 values on the last iteration. 1068 """ 1069 seq = list(value) 1070 length = len(seq) 1071 items_per_slice = length // slices 1072 slices_with_extra = length % slices 1073 offset = 0 1074 1075 for slice_number in range(slices): 1076 start = offset + slice_number * items_per_slice 1077 1078 if slice_number < slices_with_extra: 1079 offset += 1 1080 1081 end = offset + (slice_number + 1) * items_per_slice 1082 tmp = seq[start:end] 1083 1084 if fill_with is not None and slice_number >= slices_with_extra: 1085 tmp.append(fill_with) 1086 1087 yield tmp
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="columnwrapper">
{%- 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.
1047def sync_do_slice( 1048 value: "t.Collection[V]", slices: int, fill_with: "t.Optional[V]" = None 1049) -> "t.Iterator[t.List[V]]": 1050 """Slice an iterator and return a list of lists containing 1051 those items. Useful if you want to create a div containing 1052 three ul tags that represent columns: 1053 1054 .. sourcecode:: html+jinja 1055 1056 <div class="columnwrapper"> 1057 {%- for column in items|slice(3) %} 1058 <ul class="column-{{ loop.index }}"> 1059 {%- for item in column %} 1060 <li>{{ item }}</li> 1061 {%- endfor %} 1062 </ul> 1063 {%- endfor %} 1064 </div> 1065 1066 If you pass it a second argument it's used to fill missing 1067 values on the last iteration. 1068 """ 1069 seq = list(value) 1070 length = len(seq) 1071 items_per_slice = length // slices 1072 slices_with_extra = length % slices 1073 offset = 0 1074 1075 for slice_number in range(slices): 1076 start = offset + slice_number * items_per_slice 1077 1078 if slice_number < slices_with_extra: 1079 offset += 1 1080 1081 end = offset + (slice_number + 1) * items_per_slice 1082 tmp = seq[start:end] 1083 1084 if fill_with is not None and slice_number >= slices_with_extra: 1085 tmp.append(fill_with) 1086 1087 yield tmp
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="columnwrapper">
{%- 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.
1099def do_batch( 1100 value: "t.Iterable[V]", linecount: int, fill_with: "t.Optional[V]" = None 1101) -> "t.Iterator[t.List[V]]": 1102 """ 1103 A filter that batches items. It works pretty much like `slice` 1104 just the other way round. It returns a list of lists with the 1105 given number of items. If you provide a second parameter this 1106 is used to fill up missing items. See this example: 1107 1108 .. sourcecode:: html+jinja 1109 1110 <table> 1111 {%- for row in items|batch(3, ' ') %} 1112 <tr> 1113 {%- for column in row %} 1114 <td>{{ column }}</td> 1115 {%- endfor %} 1116 </tr> 1117 {%- endfor %} 1118 </table> 1119 """ 1120 tmp: "t.List[V]" = [] 1121 1122 for item in value: 1123 if len(tmp) == linecount: 1124 yield tmp 1125 tmp = [] 1126 1127 tmp.append(item) 1128 1129 if tmp: 1130 if fill_with is not None and len(tmp) < linecount: 1131 tmp += [fill_with] * (linecount - len(tmp)) 1132 1133 yield tmp
A filter that batches items. It works pretty much like slice
just the other way round. It returns a list of lists with the
given number of items. If you provide a second parameter this
is used to fill up missing items. See this example:
.. sourcecode:: html+jinja
<table>
{%- for row in items|batch(3, ' ') %}
<tr>
{%- for column in row %}
<td>{{ column }}</td>
{%- endfor %}
</tr>
{%- endfor %}
</table>
1136def do_round( 1137 value: float, 1138 precision: int = 0, 1139 method: 'te.Literal["common", "ceil", "floor"]' = "common", 1140) -> float: 1141 """Round the number to a given precision. The first 1142 parameter specifies the precision (default is ``0``), the 1143 second the rounding method: 1144 1145 - ``'common'`` rounds either up or down 1146 - ``'ceil'`` always rounds up 1147 - ``'floor'`` always rounds down 1148 1149 If you don't specify a method ``'common'`` is used. 1150 1151 .. sourcecode:: jinja 1152 1153 {{ 42.55|round }} 1154 -> 43.0 1155 {{ 42.55|round(1, 'floor') }} 1156 -> 42.5 1157 1158 Note that even if rounded to 0 precision, a float is returned. If 1159 you need a real integer, pipe it through `int`: 1160 1161 .. sourcecode:: jinja 1162 1163 {{ 42.55|round|int }} 1164 -> 43 1165 """ 1166 if method not in {"common", "ceil", "floor"}: 1167 raise FilterArgumentError("method must be common, ceil or floor") 1168 1169 if method == "common": 1170 return round(value, precision) 1171 1172 func = getattr(math, method) 1173 return t.cast(float, func(value * (10**precision)) / (10**precision))
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
1189@pass_environment 1190def sync_do_groupby( 1191 environment: "Environment", 1192 value: "t.Iterable[V]", 1193 attribute: t.Union[str, int], 1194 default: t.Optional[t.Any] = None, 1195 case_sensitive: bool = False, 1196) -> "t.List[_GroupTuple]": 1197 """Group a sequence of objects by an attribute using Python's 1198 :func:`itertools.groupby`. The attribute can use dot notation for 1199 nested access, like ``"address.city"``. Unlike Python's ``groupby``, 1200 the values are sorted first so only one group is returned for each 1201 unique value. 1202 1203 For example, a list of ``User`` objects with a ``city`` attribute 1204 can be rendered in groups. In this example, ``grouper`` refers to 1205 the ``city`` value of the group. 1206 1207 .. sourcecode:: html+jinja 1208 1209 <ul>{% for city, items in users|groupby("city") %} 1210 <li>{{ city }} 1211 <ul>{% for user in items %} 1212 <li>{{ user.name }} 1213 {% endfor %}</ul> 1214 </li> 1215 {% endfor %}</ul> 1216 1217 ``groupby`` yields namedtuples of ``(grouper, list)``, which 1218 can be used instead of the tuple unpacking above. ``grouper`` is the 1219 value of the attribute, and ``list`` is the items with that value. 1220 1221 .. sourcecode:: html+jinja 1222 1223 <ul>{% for group in users|groupby("city") %} 1224 <li>{{ group.grouper }}: {{ group.list|join(", ") }} 1225 {% endfor %}</ul> 1226 1227 You can specify a ``default`` value to use if an object in the list 1228 does not have the given attribute. 1229 1230 .. sourcecode:: jinja 1231 1232 <ul>{% for city, items in users|groupby("city", default="NY") %} 1233 <li>{{ city }}: {{ items|map(attribute="name")|join(", ") }}</li> 1234 {% endfor %}</ul> 1235 1236 Like the :func:`~jinja-filters.sort` filter, sorting and grouping is 1237 case-insensitive by default. The ``key`` for each group will have 1238 the case of the first item in that group of values. For example, if 1239 a list of users has cities ``["CA", "NY", "ca"]``, the "CA" group 1240 will have two values. This can be disabled by passing 1241 ``case_sensitive=True``. 1242 1243 .. versionchanged:: 3.1 1244 Added the ``case_sensitive`` parameter. Sorting and grouping is 1245 case-insensitive by default, matching other filters that do 1246 comparisons. 1247 1248 .. versionchanged:: 3.0 1249 Added the ``default`` parameter. 1250 1251 .. versionchanged:: 2.6 1252 The attribute supports dot notation for nested access. 1253 """ 1254 expr = make_attrgetter( 1255 environment, 1256 attribute, 1257 postprocess=ignore_case if not case_sensitive else None, 1258 default=default, 1259 ) 1260 out = [ 1261 _GroupTuple(key, list(values)) 1262 for key, values in groupby(sorted(value, key=expr), expr) 1263 ] 1264 1265 if not case_sensitive: 1266 # Return the real key from the first value instead of the lowercase key. 1267 output_expr = make_attrgetter(environment, attribute, default=default) 1268 out = [_GroupTuple(output_expr(values[0]), values) for _, values in out] 1269 1270 return out
Group a sequence of objects by an attribute using Python's
itertools.groupby()
. The attribute can use dot notation for
nested access, like "address.city"
. Unlike Python's groupby
,
the values are sorted first so only one group is returned for each
unique value.
For example, a list of User
objects with a city
attribute
can be rendered in groups. In this example, grouper
refers to
the city
value of the group.
.. sourcecode:: html+jinja
<ul>{% for city, items in users|groupby("city") %}
<li>{{ city }}
<ul>{% for user in items %}
<li>{{ user.name }}
{% endfor %}</ul>
</li>
{% endfor %}</ul>
groupby
yields namedtuples of (grouper, list)
, which
can be used instead of the tuple unpacking above. grouper
is the
value of the attribute, and list
is the items with that value.
.. sourcecode:: html+jinja
<ul>{% for group in users|groupby("city") %}
<li>{{ group.grouper }}: {{ group.list|join(", ") }}
{% endfor %}</ul>
You can specify a default
value to use if an object in the list
does not have the given attribute.
.. sourcecode:: jinja
<ul>{% for city, items in users|groupby("city", default="NY") %}
<li>{{ city }}: {{ items|map(attribute="name")|join(", ") }}</li>
{% endfor %}</ul>
Like the ~jinja-filters.sort()
filter, sorting and grouping is
case-insensitive by default. The key
for each group will have
the case of the first item in that group of values. For example, if
a list of users has cities ["CA", "NY", "ca"]
, the "CA" group
will have two values. This can be disabled by passing
case_sensitive=True
.
Changed in version 3.1:
Added the case_sensitive
parameter. Sorting and grouping is
case-insensitive by default, matching other filters that do
comparisons.
Changed in version 3.0:
Added the default
parameter.
Changed in version 2.6: The attribute supports dot notation for nested access.
1189@pass_environment 1190def sync_do_groupby( 1191 environment: "Environment", 1192 value: "t.Iterable[V]", 1193 attribute: t.Union[str, int], 1194 default: t.Optional[t.Any] = None, 1195 case_sensitive: bool = False, 1196) -> "t.List[_GroupTuple]": 1197 """Group a sequence of objects by an attribute using Python's 1198 :func:`itertools.groupby`. The attribute can use dot notation for 1199 nested access, like ``"address.city"``. Unlike Python's ``groupby``, 1200 the values are sorted first so only one group is returned for each 1201 unique value. 1202 1203 For example, a list of ``User`` objects with a ``city`` attribute 1204 can be rendered in groups. In this example, ``grouper`` refers to 1205 the ``city`` value of the group. 1206 1207 .. sourcecode:: html+jinja 1208 1209 <ul>{% for city, items in users|groupby("city") %} 1210 <li>{{ city }} 1211 <ul>{% for user in items %} 1212 <li>{{ user.name }} 1213 {% endfor %}</ul> 1214 </li> 1215 {% endfor %}</ul> 1216 1217 ``groupby`` yields namedtuples of ``(grouper, list)``, which 1218 can be used instead of the tuple unpacking above. ``grouper`` is the 1219 value of the attribute, and ``list`` is the items with that value. 1220 1221 .. sourcecode:: html+jinja 1222 1223 <ul>{% for group in users|groupby("city") %} 1224 <li>{{ group.grouper }}: {{ group.list|join(", ") }} 1225 {% endfor %}</ul> 1226 1227 You can specify a ``default`` value to use if an object in the list 1228 does not have the given attribute. 1229 1230 .. sourcecode:: jinja 1231 1232 <ul>{% for city, items in users|groupby("city", default="NY") %} 1233 <li>{{ city }}: {{ items|map(attribute="name")|join(", ") }}</li> 1234 {% endfor %}</ul> 1235 1236 Like the :func:`~jinja-filters.sort` filter, sorting and grouping is 1237 case-insensitive by default. The ``key`` for each group will have 1238 the case of the first item in that group of values. For example, if 1239 a list of users has cities ``["CA", "NY", "ca"]``, the "CA" group 1240 will have two values. This can be disabled by passing 1241 ``case_sensitive=True``. 1242 1243 .. versionchanged:: 3.1 1244 Added the ``case_sensitive`` parameter. Sorting and grouping is 1245 case-insensitive by default, matching other filters that do 1246 comparisons. 1247 1248 .. versionchanged:: 3.0 1249 Added the ``default`` parameter. 1250 1251 .. versionchanged:: 2.6 1252 The attribute supports dot notation for nested access. 1253 """ 1254 expr = make_attrgetter( 1255 environment, 1256 attribute, 1257 postprocess=ignore_case if not case_sensitive else None, 1258 default=default, 1259 ) 1260 out = [ 1261 _GroupTuple(key, list(values)) 1262 for key, values in groupby(sorted(value, key=expr), expr) 1263 ] 1264 1265 if not case_sensitive: 1266 # Return the real key from the first value instead of the lowercase key. 1267 output_expr = make_attrgetter(environment, attribute, default=default) 1268 out = [_GroupTuple(output_expr(values[0]), values) for _, values in out] 1269 1270 return out
Group a sequence of objects by an attribute using Python's
itertools.groupby()
. The attribute can use dot notation for
nested access, like "address.city"
. Unlike Python's groupby
,
the values are sorted first so only one group is returned for each
unique value.
For example, a list of User
objects with a city
attribute
can be rendered in groups. In this example, grouper
refers to
the city
value of the group.
.. sourcecode:: html+jinja
<ul>{% for city, items in users|groupby("city") %}
<li>{{ city }}
<ul>{% for user in items %}
<li>{{ user.name }}
{% endfor %}</ul>
</li>
{% endfor %}</ul>
groupby
yields namedtuples of (grouper, list)
, which
can be used instead of the tuple unpacking above. grouper
is the
value of the attribute, and list
is the items with that value.
.. sourcecode:: html+jinja
<ul>{% for group in users|groupby("city") %}
<li>{{ group.grouper }}: {{ group.list|join(", ") }}
{% endfor %}</ul>
You can specify a default
value to use if an object in the list
does not have the given attribute.
.. sourcecode:: jinja
<ul>{% for city, items in users|groupby("city", default="NY") %}
<li>{{ city }}: {{ items|map(attribute="name")|join(", ") }}</li>
{% endfor %}</ul>
Like the ~jinja-filters.sort()
filter, sorting and grouping is
case-insensitive by default. The key
for each group will have
the case of the first item in that group of values. For example, if
a list of users has cities ["CA", "NY", "ca"]
, the "CA" group
will have two values. This can be disabled by passing
case_sensitive=True
.
Changed in version 3.1:
Added the case_sensitive
parameter. Sorting and grouping is
case-insensitive by default, matching other filters that do
comparisons.
Changed in version 3.0:
Added the default
parameter.
Changed in version 2.6: The attribute supports dot notation for nested access.
1300@pass_environment 1301def sync_do_sum( 1302 environment: "Environment", 1303 iterable: "t.Iterable[V]", 1304 attribute: t.Optional[t.Union[str, int]] = None, 1305 start: V = 0, # type: ignore 1306) -> V: 1307 """Returns the sum of a sequence of numbers plus the value of parameter 1308 'start' (which defaults to 0). When the sequence is empty it returns 1309 start. 1310 1311 It is also possible to sum up only certain attributes: 1312 1313 .. sourcecode:: jinja 1314 1315 Total: {{ items|sum(attribute='price') }} 1316 1317 .. versionchanged:: 2.6 1318 The ``attribute`` parameter was added to allow summing up over 1319 attributes. Also the ``start`` parameter was moved on to the right. 1320 """ 1321 if attribute is not None: 1322 iterable = map(make_attrgetter(environment, attribute), iterable) 1323 1324 return sum(iterable, start) # type: ignore[no-any-return, call-overload]
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') }}
Changed in version 2.6:
The attribute
parameter was added to allow summing up over
attributes. Also the start
parameter was moved on to the right.
1300@pass_environment 1301def sync_do_sum( 1302 environment: "Environment", 1303 iterable: "t.Iterable[V]", 1304 attribute: t.Optional[t.Union[str, int]] = None, 1305 start: V = 0, # type: ignore 1306) -> V: 1307 """Returns the sum of a sequence of numbers plus the value of parameter 1308 'start' (which defaults to 0). When the sequence is empty it returns 1309 start. 1310 1311 It is also possible to sum up only certain attributes: 1312 1313 .. sourcecode:: jinja 1314 1315 Total: {{ items|sum(attribute='price') }} 1316 1317 .. versionchanged:: 2.6 1318 The ``attribute`` parameter was added to allow summing up over 1319 attributes. Also the ``start`` parameter was moved on to the right. 1320 """ 1321 if attribute is not None: 1322 iterable = map(make_attrgetter(environment, attribute), iterable) 1323 1324 return sum(iterable, start) # type: ignore[no-any-return, call-overload]
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') }}
Changed in version 2.6:
The attribute
parameter was added to allow summing up over
attributes. Also the start
parameter was moved on to the right.
1349def sync_do_list(value: "t.Iterable[V]") -> "t.List[V]": 1350 """Convert the value into a list. If it was a string the returned list 1351 will be a list of characters. 1352 """ 1353 return list(value)
Convert the value into a list. If it was a string the returned list will be a list of characters.
1349def sync_do_list(value: "t.Iterable[V]") -> "t.List[V]": 1350 """Convert the value into a list. If it was a string the returned list 1351 will be a list of characters. 1352 """ 1353 return list(value)
Convert the value into a list. If it was a string the returned list will be a list of characters.
1361def do_mark_safe(value: str) -> Markup: 1362 """Mark the value as safe which means that in an environment with automatic 1363 escaping enabled this variable will not be escaped. 1364 """ 1365 return Markup(value)
Mark the value as safe which means that in an environment with automatic escaping enabled this variable will not be escaped.
1368def do_mark_unsafe(value: str) -> str: 1369 """Mark a value as unsafe. This is the reverse operation for :func:`safe`.""" 1370 return str(value)
Mark a value as unsafe. This is the reverse operation for safe()
.
1381def do_reverse(value: t.Union[str, t.Iterable[V]]) -> t.Union[str, t.Iterable[V]]: 1382 """Reverse the object or return an iterator that iterates over it the other 1383 way round. 1384 """ 1385 if isinstance(value, str): 1386 return value[::-1] 1387 1388 try: 1389 return reversed(value) # type: ignore 1390 except TypeError: 1391 try: 1392 rv = list(value) 1393 rv.reverse() 1394 return rv 1395 except TypeError as e: 1396 raise FilterArgumentError("argument must be iterable") from e
Reverse the object or return an iterator that iterates over it the other way round.
1399@pass_environment 1400def do_attr( 1401 environment: "Environment", obj: t.Any, name: str 1402) -> t.Union[Undefined, t.Any]: 1403 """Get an attribute of an object. ``foo|attr("bar")`` works like 1404 ``foo.bar`` just that always an attribute is returned and items are not 1405 looked up. 1406 1407 See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details. 1408 """ 1409 try: 1410 name = str(name) 1411 except UnicodeError: 1412 pass 1413 else: 1414 try: 1415 value = getattr(obj, name) 1416 except AttributeError: 1417 pass 1418 else: 1419 if environment.sandboxed: 1420 environment = t.cast("SandboxedEnvironment", environment) 1421 1422 if not environment.is_safe_attribute(obj, name, value): 1423 return environment.unsafe_undefined(obj, name) 1424 1425 return value 1426 1427 return environment.undefined(obj=obj, name=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.
1450@pass_context 1451def sync_do_map( 1452 context: "Context", value: t.Iterable[t.Any], *args: t.Any, **kwargs: t.Any 1453) -> t.Iterable[t.Any]: 1454 """Applies a filter on a sequence of objects or looks up an attribute. 1455 This is useful when dealing with lists of objects but you are really 1456 only interested in a certain value of it. 1457 1458 The basic usage is mapping on an attribute. Imagine you have a list 1459 of users but you are only interested in a list of usernames: 1460 1461 .. sourcecode:: jinja 1462 1463 Users on this page: {{ users|map(attribute='username')|join(', ') }} 1464 1465 You can specify a ``default`` value to use if an object in the list 1466 does not have the given attribute. 1467 1468 .. sourcecode:: jinja 1469 1470 {{ users|map(attribute="username", default="Anonymous")|join(", ") }} 1471 1472 Alternatively you can let it invoke a filter by passing the name of the 1473 filter and the arguments afterwards. A good example would be applying a 1474 text conversion filter on a sequence: 1475 1476 .. sourcecode:: jinja 1477 1478 Users on this page: {{ titles|map('lower')|join(', ') }} 1479 1480 Similar to a generator comprehension such as: 1481 1482 .. code-block:: python 1483 1484 (u.username for u in users) 1485 (getattr(u, "username", "Anonymous") for u in users) 1486 (do_lower(x) for x in titles) 1487 1488 .. versionchanged:: 2.11.0 1489 Added the ``default`` parameter. 1490 1491 .. versionadded:: 2.7 1492 """ 1493 if value: 1494 func = prepare_map(context, args, kwargs) 1495 1496 for item in value: 1497 yield func(item)
Applies a filter on a sequence of objects or looks up an attribute. This is useful when dealing with lists of objects but you are really only interested in a certain value of it.
The basic usage is mapping on an attribute. Imagine you have a list of users but you are only interested in a list of usernames:
.. sourcecode:: jinja
Users on this page: {{ users|map(attribute='username')|join(', ') }}
You can specify a default
value to use if an object in the list
does not have the given attribute.
.. sourcecode:: jinja
{{ users|map(attribute="username", default="Anonymous")|join(", ") }}
Alternatively you can let it invoke a filter by passing the name of the filter and the arguments afterwards. A good example would be applying a text conversion filter on a sequence:
.. sourcecode:: jinja
Users on this page: {{ titles|map('lower')|join(', ') }}
Similar to a generator comprehension such as:
(u.username for u in users)
(getattr(u, "username", "Anonymous") for u in users)
(do_lower(x) for x in titles)
Changed in version 2.11.0:
Added the default
parameter.
New in version 2.7.
1450@pass_context 1451def sync_do_map( 1452 context: "Context", value: t.Iterable[t.Any], *args: t.Any, **kwargs: t.Any 1453) -> t.Iterable[t.Any]: 1454 """Applies a filter on a sequence of objects or looks up an attribute. 1455 This is useful when dealing with lists of objects but you are really 1456 only interested in a certain value of it. 1457 1458 The basic usage is mapping on an attribute. Imagine you have a list 1459 of users but you are only interested in a list of usernames: 1460 1461 .. sourcecode:: jinja 1462 1463 Users on this page: {{ users|map(attribute='username')|join(', ') }} 1464 1465 You can specify a ``default`` value to use if an object in the list 1466 does not have the given attribute. 1467 1468 .. sourcecode:: jinja 1469 1470 {{ users|map(attribute="username", default="Anonymous")|join(", ") }} 1471 1472 Alternatively you can let it invoke a filter by passing the name of the 1473 filter and the arguments afterwards. A good example would be applying a 1474 text conversion filter on a sequence: 1475 1476 .. sourcecode:: jinja 1477 1478 Users on this page: {{ titles|map('lower')|join(', ') }} 1479 1480 Similar to a generator comprehension such as: 1481 1482 .. code-block:: python 1483 1484 (u.username for u in users) 1485 (getattr(u, "username", "Anonymous") for u in users) 1486 (do_lower(x) for x in titles) 1487 1488 .. versionchanged:: 2.11.0 1489 Added the ``default`` parameter. 1490 1491 .. versionadded:: 2.7 1492 """ 1493 if value: 1494 func = prepare_map(context, args, kwargs) 1495 1496 for item in value: 1497 yield func(item)
Applies a filter on a sequence of objects or looks up an attribute. This is useful when dealing with lists of objects but you are really only interested in a certain value of it.
The basic usage is mapping on an attribute. Imagine you have a list of users but you are only interested in a list of usernames:
.. sourcecode:: jinja
Users on this page: {{ users|map(attribute='username')|join(', ') }}
You can specify a default
value to use if an object in the list
does not have the given attribute.
.. sourcecode:: jinja
{{ users|map(attribute="username", default="Anonymous")|join(", ") }}
Alternatively you can let it invoke a filter by passing the name of the filter and the arguments afterwards. A good example would be applying a text conversion filter on a sequence:
.. sourcecode:: jinja
Users on this page: {{ titles|map('lower')|join(', ') }}
Similar to a generator comprehension such as:
(u.username for u in users)
(getattr(u, "username", "Anonymous") for u in users)
(do_lower(x) for x in titles)
Changed in version 2.11.0:
Added the default
parameter.
New in version 2.7.
1534@pass_context 1535def sync_do_select( 1536 context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any 1537) -> "t.Iterator[V]": 1538 """Filters a sequence of objects by applying a test to each object, 1539 and only selecting the objects with the test succeeding. 1540 1541 If no test is specified, each object will be evaluated as a boolean. 1542 1543 Example usage: 1544 1545 .. sourcecode:: jinja 1546 1547 {{ numbers|select("odd") }} 1548 {{ numbers|select("odd") }} 1549 {{ numbers|select("divisibleby", 3) }} 1550 {{ numbers|select("lessthan", 42) }} 1551 {{ strings|select("equalto", "mystring") }} 1552 1553 Similar to a generator comprehension such as: 1554 1555 .. code-block:: python 1556 1557 (n for n in numbers if test_odd(n)) 1558 (n for n in numbers if test_divisibleby(n, 3)) 1559 1560 .. versionadded:: 2.7 1561 """ 1562 return select_or_reject(context, value, args, kwargs, lambda x: x, False)
Filters a sequence of objects by applying a test to each object, and only selecting the objects with the test succeeding.
If no test is specified, each object will be evaluated as a boolean.
Example usage:
.. sourcecode:: jinja
{{ numbers|select("odd") }}
{{ numbers|select("odd") }}
{{ numbers|select("divisibleby", 3) }}
{{ numbers|select("lessthan", 42) }}
{{ strings|select("equalto", "mystring") }}
Similar to a generator comprehension such as:
(n for n in numbers if test_odd(n))
(n for n in numbers if test_divisibleby(n, 3))
New in version 2.7.
1534@pass_context 1535def sync_do_select( 1536 context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any 1537) -> "t.Iterator[V]": 1538 """Filters a sequence of objects by applying a test to each object, 1539 and only selecting the objects with the test succeeding. 1540 1541 If no test is specified, each object will be evaluated as a boolean. 1542 1543 Example usage: 1544 1545 .. sourcecode:: jinja 1546 1547 {{ numbers|select("odd") }} 1548 {{ numbers|select("odd") }} 1549 {{ numbers|select("divisibleby", 3) }} 1550 {{ numbers|select("lessthan", 42) }} 1551 {{ strings|select("equalto", "mystring") }} 1552 1553 Similar to a generator comprehension such as: 1554 1555 .. code-block:: python 1556 1557 (n for n in numbers if test_odd(n)) 1558 (n for n in numbers if test_divisibleby(n, 3)) 1559 1560 .. versionadded:: 2.7 1561 """ 1562 return select_or_reject(context, value, args, kwargs, lambda x: x, False)
Filters a sequence of objects by applying a test to each object, and only selecting the objects with the test succeeding.
If no test is specified, each object will be evaluated as a boolean.
Example usage:
.. sourcecode:: jinja
{{ numbers|select("odd") }}
{{ numbers|select("odd") }}
{{ numbers|select("divisibleby", 3) }}
{{ numbers|select("lessthan", 42) }}
{{ strings|select("equalto", "mystring") }}
Similar to a generator comprehension such as:
(n for n in numbers if test_odd(n))
(n for n in numbers if test_divisibleby(n, 3))
New in version 2.7.
1575@pass_context 1576def sync_do_reject( 1577 context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any 1578) -> "t.Iterator[V]": 1579 """Filters a sequence of objects by applying a test to each object, 1580 and rejecting the objects with the test succeeding. 1581 1582 If no test is specified, each object will be evaluated as a boolean. 1583 1584 Example usage: 1585 1586 .. sourcecode:: jinja 1587 1588 {{ numbers|reject("odd") }} 1589 1590 Similar to a generator comprehension such as: 1591 1592 .. code-block:: python 1593 1594 (n for n in numbers if not test_odd(n)) 1595 1596 .. versionadded:: 2.7 1597 """ 1598 return select_or_reject(context, value, args, kwargs, lambda x: not x, False)
Filters a sequence of objects by applying a test to each object, and rejecting the objects with the test succeeding.
If no test is specified, each object will be evaluated as a boolean.
Example usage:
.. sourcecode:: jinja
{{ numbers|reject("odd") }}
Similar to a generator comprehension such as:
(n for n in numbers if not test_odd(n))
New in version 2.7.
1575@pass_context 1576def sync_do_reject( 1577 context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any 1578) -> "t.Iterator[V]": 1579 """Filters a sequence of objects by applying a test to each object, 1580 and rejecting the objects with the test succeeding. 1581 1582 If no test is specified, each object will be evaluated as a boolean. 1583 1584 Example usage: 1585 1586 .. sourcecode:: jinja 1587 1588 {{ numbers|reject("odd") }} 1589 1590 Similar to a generator comprehension such as: 1591 1592 .. code-block:: python 1593 1594 (n for n in numbers if not test_odd(n)) 1595 1596 .. versionadded:: 2.7 1597 """ 1598 return select_or_reject(context, value, args, kwargs, lambda x: not x, False)
Filters a sequence of objects by applying a test to each object, and rejecting the objects with the test succeeding.
If no test is specified, each object will be evaluated as a boolean.
Example usage:
.. sourcecode:: jinja
{{ numbers|reject("odd") }}
Similar to a generator comprehension such as:
(n for n in numbers if not test_odd(n))
New in version 2.7.
1611@pass_context 1612def sync_do_selectattr( 1613 context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any 1614) -> "t.Iterator[V]": 1615 """Filters a sequence of objects by applying a test to the specified 1616 attribute of each object, and only selecting the objects with the 1617 test succeeding. 1618 1619 If no test is specified, the attribute's value will be evaluated as 1620 a boolean. 1621 1622 Example usage: 1623 1624 .. sourcecode:: jinja 1625 1626 {{ users|selectattr("is_active") }} 1627 {{ users|selectattr("email", "none") }} 1628 1629 Similar to a generator comprehension such as: 1630 1631 .. code-block:: python 1632 1633 (u for user in users if user.is_active) 1634 (u for user in users if test_none(user.email)) 1635 1636 .. versionadded:: 2.7 1637 """ 1638 return select_or_reject(context, value, args, kwargs, lambda x: x, True)
Filters a sequence of objects by applying a test to the specified attribute of each object, and only selecting the objects with the test succeeding.
If no test is specified, the attribute's value will be evaluated as a boolean.
Example usage:
.. sourcecode:: jinja
{{ users|selectattr("is_active") }}
{{ users|selectattr("email", "none") }}
Similar to a generator comprehension such as:
(u for user in users if user.is_active)
(u for user in users if test_none(user.email))
New in version 2.7.
1611@pass_context 1612def sync_do_selectattr( 1613 context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any 1614) -> "t.Iterator[V]": 1615 """Filters a sequence of objects by applying a test to the specified 1616 attribute of each object, and only selecting the objects with the 1617 test succeeding. 1618 1619 If no test is specified, the attribute's value will be evaluated as 1620 a boolean. 1621 1622 Example usage: 1623 1624 .. sourcecode:: jinja 1625 1626 {{ users|selectattr("is_active") }} 1627 {{ users|selectattr("email", "none") }} 1628 1629 Similar to a generator comprehension such as: 1630 1631 .. code-block:: python 1632 1633 (u for user in users if user.is_active) 1634 (u for user in users if test_none(user.email)) 1635 1636 .. versionadded:: 2.7 1637 """ 1638 return select_or_reject(context, value, args, kwargs, lambda x: x, True)
Filters a sequence of objects by applying a test to the specified attribute of each object, and only selecting the objects with the test succeeding.
If no test is specified, the attribute's value will be evaluated as a boolean.
Example usage:
.. sourcecode:: jinja
{{ users|selectattr("is_active") }}
{{ users|selectattr("email", "none") }}
Similar to a generator comprehension such as:
(u for user in users if user.is_active)
(u for user in users if test_none(user.email))
New in version 2.7.
1651@pass_context 1652def sync_do_rejectattr( 1653 context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any 1654) -> "t.Iterator[V]": 1655 """Filters a sequence of objects by applying a test to the specified 1656 attribute of each object, and rejecting the objects with the test 1657 succeeding. 1658 1659 If no test is specified, the attribute's value will be evaluated as 1660 a boolean. 1661 1662 .. sourcecode:: jinja 1663 1664 {{ users|rejectattr("is_active") }} 1665 {{ users|rejectattr("email", "none") }} 1666 1667 Similar to a generator comprehension such as: 1668 1669 .. code-block:: python 1670 1671 (u for user in users if not user.is_active) 1672 (u for user in users if not test_none(user.email)) 1673 1674 .. versionadded:: 2.7 1675 """ 1676 return select_or_reject(context, value, args, kwargs, lambda x: not x, True)
Filters a sequence of objects by applying a test to the specified attribute of each object, and rejecting the objects with the test succeeding.
If no test is specified, the attribute's value will be evaluated as a boolean.
.. sourcecode:: jinja
{{ users|rejectattr("is_active") }}
{{ users|rejectattr("email", "none") }}
Similar to a generator comprehension such as:
(u for user in users if not user.is_active)
(u for user in users if not test_none(user.email))
New in version 2.7.
1651@pass_context 1652def sync_do_rejectattr( 1653 context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any 1654) -> "t.Iterator[V]": 1655 """Filters a sequence of objects by applying a test to the specified 1656 attribute of each object, and rejecting the objects with the test 1657 succeeding. 1658 1659 If no test is specified, the attribute's value will be evaluated as 1660 a boolean. 1661 1662 .. sourcecode:: jinja 1663 1664 {{ users|rejectattr("is_active") }} 1665 {{ users|rejectattr("email", "none") }} 1666 1667 Similar to a generator comprehension such as: 1668 1669 .. code-block:: python 1670 1671 (u for user in users if not user.is_active) 1672 (u for user in users if not test_none(user.email)) 1673 1674 .. versionadded:: 2.7 1675 """ 1676 return select_or_reject(context, value, args, kwargs, lambda x: not x, True)
Filters a sequence of objects by applying a test to the specified attribute of each object, and rejecting the objects with the test succeeding.
If no test is specified, the attribute's value will be evaluated as a boolean.
.. sourcecode:: jinja
{{ users|rejectattr("is_active") }}
{{ users|rejectattr("email", "none") }}
Similar to a generator comprehension such as:
(u for user in users if not user.is_active)
(u for user in users if not test_none(user.email))
New in version 2.7.
1689@pass_eval_context 1690def do_tojson( 1691 eval_ctx: "EvalContext", value: t.Any, indent: t.Optional[int] = None 1692) -> Markup: 1693 """Serialize an object to a string of JSON, and mark it safe to 1694 render in HTML. This filter is only for use in HTML documents. 1695 1696 The returned string is safe to render in HTML documents and 1697 ``<script>`` tags. The exception is in HTML attributes that are 1698 double quoted; either use single quotes or the ``|forceescape`` 1699 filter. 1700 1701 :param value: The object to serialize to JSON. 1702 :param indent: The ``indent`` parameter passed to ``dumps``, for 1703 pretty-printing the value. 1704 1705 .. versionadded:: 2.9 1706 """ 1707 policies = eval_ctx.environment.policies 1708 dumps = policies["json.dumps_function"] 1709 kwargs = policies["json.dumps_kwargs"] 1710 1711 if indent is not None: 1712 kwargs = kwargs.copy() 1713 kwargs["indent"] = indent 1714 1715 return htmlsafe_json_dumps(value, dumps=dumps, **kwargs)
Serialize an object to a string of JSON, and mark it safe to render in HTML. This filter is only for use in HTML documents.
The returned string is safe to render in HTML documents and
<script>
tags. The exception is in HTML attributes that are
double quoted; either use single quotes or the |forceescape
filter.
Parameters
- value: The object to serialize to JSON.
- indent: The
indent
parameter passed todumps
, for pretty-printing the value.
New in version 2.9.
1718def prepare_map( 1719 context: "Context", args: t.Tuple[t.Any, ...], kwargs: t.Dict[str, t.Any] 1720) -> t.Callable[[t.Any], t.Any]: 1721 if not args and "attribute" in kwargs: 1722 attribute = kwargs.pop("attribute") 1723 default = kwargs.pop("default", None) 1724 1725 if kwargs: 1726 raise FilterArgumentError( 1727 f"Unexpected keyword argument {next(iter(kwargs))!r}" 1728 ) 1729 1730 func = make_attrgetter(context.environment, attribute, default=default) 1731 else: 1732 try: 1733 name = args[0] 1734 args = args[1:] 1735 except LookupError: 1736 raise FilterArgumentError("map requires a filter argument") from None 1737 1738 def func(item: t.Any) -> t.Any: 1739 return context.environment.call_filter( 1740 name, item, args, kwargs, context=context 1741 ) 1742 1743 return func
1746def prepare_select_or_reject( 1747 context: "Context", 1748 args: t.Tuple[t.Any, ...], 1749 kwargs: t.Dict[str, t.Any], 1750 modfunc: t.Callable[[t.Any], t.Any], 1751 lookup_attr: bool, 1752) -> t.Callable[[t.Any], t.Any]: 1753 if lookup_attr: 1754 try: 1755 attr = args[0] 1756 except LookupError: 1757 raise FilterArgumentError("Missing parameter for attribute name") from None 1758 1759 transfunc = make_attrgetter(context.environment, attr) 1760 off = 1 1761 else: 1762 off = 0 1763 1764 def transfunc(x: V) -> V: 1765 return x 1766 1767 try: 1768 name = args[off] 1769 args = args[1 + off :] 1770 1771 def func(item: t.Any) -> t.Any: 1772 return context.environment.call_test(name, item, args, kwargs) 1773 1774 except LookupError: 1775 func = bool # type: ignore 1776 1777 return lambda item: modfunc(func(transfunc(item)))
1780def select_or_reject( 1781 context: "Context", 1782 value: "t.Iterable[V]", 1783 args: t.Tuple[t.Any, ...], 1784 kwargs: t.Dict[str, t.Any], 1785 modfunc: t.Callable[[t.Any], t.Any], 1786 lookup_attr: bool, 1787) -> "t.Iterator[V]": 1788 if value: 1789 func = prepare_select_or_reject(context, args, kwargs, modfunc, lookup_attr) 1790 1791 for item in value: 1792 if func(item): 1793 yield item
1796async def async_select_or_reject( 1797 context: "Context", 1798 value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", 1799 args: t.Tuple[t.Any, ...], 1800 kwargs: t.Dict[str, t.Any], 1801 modfunc: t.Callable[[t.Any], t.Any], 1802 lookup_attr: bool, 1803) -> "t.AsyncIterator[V]": 1804 if value: 1805 func = prepare_select_or_reject(context, args, kwargs, modfunc, lookup_attr) 1806 1807 async for item in auto_aiter(value): 1808 if func(item): 1809 yield item