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