jinja2.filters

Built-in template filters used with the | operator.

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

For use as a postprocessor for make_attrgetter(). Converts strings to lowercase and returns other types as-is.

def make_attrgetter( environment: jinja2.environment.Environment, attribute: Union[str, int, NoneType], postprocess: Optional[Callable[[Any], Any]] = None, default: Optional[Any] = None) -> Callable[[Any], Any]:
58def make_attrgetter(
59    environment: "Environment",
60    attribute: t.Optional[t.Union[str, int]],
61    postprocess: t.Optional[t.Callable[[t.Any], t.Any]] = None,
62    default: t.Optional[t.Any] = None,
63) -> t.Callable[[t.Any], t.Any]:
64    """Returns a callable that looks up the given attribute from a
65    passed object with the rules of the environment.  Dots are allowed
66    to access attributes of attributes.  Integer parts in paths are
67    looked up as integers.
68    """
69    parts = _prepare_attribute_parts(attribute)
70
71    def attrgetter(item: t.Any) -> t.Any:
72        for part in parts:
73            item = environment.getitem(item, part)
74
75            if default is not None and isinstance(item, Undefined):
76                item = default
77
78        if postprocess is not None:
79            item = postprocess(item)
80
81        return item
82
83    return attrgetter

Returns a callable that looks up the given attribute from a passed object with the rules of the environment. Dots are allowed to access attributes of attributes. Integer parts in paths are looked up as integers.

def make_multi_attrgetter( environment: jinja2.environment.Environment, attribute: Union[str, int, NoneType], postprocess: Optional[Callable[[Any], Any]] = None) -> Callable[[Any], List[Any]]:
 86def make_multi_attrgetter(
 87    environment: "Environment",
 88    attribute: t.Optional[t.Union[str, int]],
 89    postprocess: t.Optional[t.Callable[[t.Any], t.Any]] = None,
 90) -> t.Callable[[t.Any], t.List[t.Any]]:
 91    """Returns a callable that looks up the given comma separated
 92    attributes from a passed object with the rules of the environment.
 93    Dots are allowed to access attributes of each attribute.  Integer
 94    parts in paths are looked up as integers.
 95
 96    The value returned by the returned callable is a list of extracted
 97    attribute values.
 98
 99    Examples of attribute: "attr1,attr2", "attr1.inner1.0,attr2.inner2.0", etc.
100    """
101    if isinstance(attribute, str):
102        split: t.Sequence[t.Union[str, int, None]] = attribute.split(",")
103    else:
104        split = [attribute]
105
106    parts = [_prepare_attribute_parts(item) for item in split]
107
108    def attrgetter(item: t.Any) -> t.List[t.Any]:
109        items = [None] * len(parts)
110
111        for i, attribute_part in enumerate(parts):
112            item_i = item
113
114            for part in attribute_part:
115                item_i = environment.getitem(item_i, part)
116
117            if postprocess is not None:
118                item_i = postprocess(item_i)
119
120            items[i] = item_i
121
122        return items
123
124    return attrgetter

Returns a callable that looks up the given comma separated attributes from a passed object with the rules of the environment. Dots are allowed to access attributes of each attribute. Integer parts in paths are looked up as integers.

The value returned by the returned callable is a list of extracted attribute values.

Examples of attribute: "attr1,attr2", "attr1.inner1.0,attr2.inner2.0", etc.

def do_forceescape(value: Union[str, jinja2.filters.HasHTML]) -> markupsafe.Markup:
139def do_forceescape(value: "t.Union[str, HasHTML]") -> Markup:
140    """Enforce HTML escaping.  This will probably double escape variables."""
141    if hasattr(value, "__html__"):
142        value = t.cast("HasHTML", value).__html__()
143
144    return escape(str(value))

Enforce HTML escaping. This will probably double escape variables.

def do_urlencode(value: Union[str, Mapping[str, Any], Iterable[Tuple[str, Any]]]) -> str:
147def do_urlencode(
148    value: t.Union[str, t.Mapping[str, t.Any], t.Iterable[t.Tuple[str, t.Any]]],
149) -> str:
150    """Quote data for use in a URL path or query using UTF-8.
151
152    Basic wrapper around :func:`urllib.parse.quote` when given a
153    string, or :func:`urllib.parse.urlencode` for a dict or iterable.
154
155    :param value: Data to quote. A string will be quoted directly. A
156        dict or iterable of ``(key, value)`` pairs will be joined as a
157        query string.
158
159    When given a string, "/" is not quoted. HTTP servers treat "/" and
160    "%2F" equivalently in paths. If you need quoted slashes, use the
161    ``|replace("/", "%2F")`` filter.
162
163    .. versionadded:: 2.7
164    """
165    if isinstance(value, str) or not isinstance(value, abc.Iterable):
166        return url_quote(value)
167
168    if isinstance(value, dict):
169        items: t.Iterable[t.Tuple[str, t.Any]] = value.items()
170    else:
171        items = value  # type: ignore
172
173    return "&".join(
174        f"{url_quote(k, for_qs=True)}={url_quote(v, for_qs=True)}" for k, v in items
175    )

Quote data for use in a URL path or query using UTF-8.

Basic wrapper around urllib.parse.quote() when given a string, or urllib.parse.urlencode() for a dict or iterable.

Parameters
  • value: Data to quote. A string will be quoted directly. A dict or iterable of (key, value) pairs will be joined as a query string.

When given a string, "/" is not quoted. HTTP servers treat "/" and "%2F" equivalently in paths. If you need quoted slashes, use the |replace("/", "%2F") filter.

New in version 2.7.

@pass_eval_context
def do_replace( eval_ctx: jinja2.nodes.EvalContext, s: str, old: str, new: str, count: Optional[int] = None) -> str:
178@pass_eval_context
179def do_replace(
180    eval_ctx: "EvalContext", s: str, old: str, new: str, count: t.Optional[int] = None
181) -> str:
182    """Return a copy of the value with all occurrences of a substring
183    replaced with a new one. The first argument is the substring
184    that should be replaced, the second is the replacement string.
185    If the optional third argument ``count`` is given, only the first
186    ``count`` occurrences are replaced:
187
188    .. sourcecode:: jinja
189
190        {{ "Hello World"|replace("Hello", "Goodbye") }}
191            -> Goodbye World
192
193        {{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
194            -> d'oh, d'oh, aaargh
195    """
196    if count is None:
197        count = -1
198
199    if not eval_ctx.autoescape:
200        return str(s).replace(str(old), str(new), count)
201
202    if (
203        hasattr(old, "__html__")
204        or hasattr(new, "__html__")
205        and not hasattr(s, "__html__")
206    ):
207        s = escape(s)
208    else:
209        s = soft_str(s)
210
211    return s.replace(soft_str(old), soft_str(new), count)

Return a copy of the value with all occurrences of a substring replaced with a new one. The first argument is the substring that should be replaced, the second is the replacement string. If the optional third argument count is given, only the first count occurrences are replaced:

.. sourcecode:: jinja

{{ "Hello World"|replace("Hello", "Goodbye") }}
    -> Goodbye World

{{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
    -> d'oh, d'oh, aaargh
def do_upper(s: str) -> str:
214def do_upper(s: str) -> str:
215    """Convert a value to uppercase."""
216    return soft_str(s).upper()

Convert a value to uppercase.

def do_lower(s: str) -> str:
219def do_lower(s: str) -> str:
220    """Convert a value to lowercase."""
221    return soft_str(s).lower()

Convert a value to lowercase.

def do_items( value: Union[Mapping[~K, ~V], jinja2.runtime.Undefined]) -> Iterator[Tuple[~K, ~V]]:
224def do_items(value: t.Union[t.Mapping[K, V], Undefined]) -> t.Iterator[t.Tuple[K, V]]:
225    """Return an iterator over the ``(key, value)`` items of a mapping.
226
227    ``x|items`` is the same as ``x.items()``, except if ``x`` is
228    undefined an empty iterator is returned.
229
230    This filter is useful if you expect the template to be rendered with
231    an implementation of Jinja in another programming language that does
232    not have a ``.items()`` method on its mapping type.
233
234    .. code-block:: html+jinja
235
236        <dl>
237        {% for key, value in my_dict|items %}
238            <dt>{{ key }}
239            <dd>{{ value }}
240        {% endfor %}
241        </dl>
242
243    .. versionadded:: 3.1
244    """
245    if isinstance(value, Undefined):
246        return
247
248    if not isinstance(value, abc.Mapping):
249        raise TypeError("Can only get item pairs from a mapping.")
250
251    yield from value.items()

Return an iterator over the (key, value) items of a mapping.

x|items is the same as x.items(), except if x is undefined an empty iterator is returned.

This filter is useful if you expect the template to be rendered with an implementation of Jinja in another programming language that does not have a .items() method on its mapping type.

<dl>
{% for key, value in my_dict|items %}
    <dt>{{ key }}
    <dd>{{ value }}
{% endfor %}
</dl>

New in version 3.1.

@pass_eval_context
def do_xmlattr( eval_ctx: jinja2.nodes.EvalContext, d: Mapping[str, Any], autospace: bool = True) -> str:
259@pass_eval_context
260def do_xmlattr(
261    eval_ctx: "EvalContext", d: t.Mapping[str, t.Any], autospace: bool = True
262) -> str:
263    """Create an SGML/XML attribute string based on the items in a dict.
264
265    **Values** that are neither ``none`` nor ``undefined`` are automatically
266    escaped, safely allowing untrusted user input.
267
268    User input should not be used as **keys** to this filter. If any key
269    contains a space, ``/`` solidus, ``>`` greater-than sign, or ``=`` equals
270    sign, this fails with a ``ValueError``. Regardless of this, user input
271    should never be used as keys to this filter, or must be separately validated
272    first.
273
274    .. sourcecode:: html+jinja
275
276        <ul{{ {'class': 'my_list', 'missing': none,
277                'id': 'list-%d'|format(variable)}|xmlattr }}>
278        ...
279        </ul>
280
281    Results in something like this:
282
283    .. sourcecode:: html
284
285        <ul class="my_list" id="list-42">
286        ...
287        </ul>
288
289    As you can see it automatically prepends a space in front of the item
290    if the filter returned something unless the second parameter is false.
291
292    .. versionchanged:: 3.1.4
293        Keys with ``/`` solidus, ``>`` greater-than sign, or ``=`` equals sign
294        are not allowed.
295
296    .. versionchanged:: 3.1.3
297        Keys with spaces are not allowed.
298    """
299    items = []
300
301    for key, value in d.items():
302        if value is None or isinstance(value, Undefined):
303            continue
304
305        if _attr_key_re.search(key) is not None:
306            raise ValueError(f"Invalid character in attribute name: {key!r}")
307
308        items.append(f'{escape(key)}="{escape(value)}"')
309
310    rv = " ".join(items)
311
312    if autospace and rv:
313        rv = " " + rv
314
315    if eval_ctx.autoescape:
316        rv = Markup(rv)
317
318    return rv

Create an SGML/XML attribute string based on the items in a dict.

Values that are neither none nor undefined are automatically escaped, safely allowing untrusted user input.

User input should not be used as keys to this filter. If any key contains a space, / solidus, > greater-than sign, or = equals sign, this fails with a ValueError. Regardless of this, user input should never be used as keys to this filter, or must be separately validated first.

.. sourcecode:: html+jinja

<ul{{ {'class': 'my_list', 'missing': none,
        'id': 'list-%d'|format(variable)}|xmlattr }}>
...
</ul>

Results in something like this:

.. sourcecode:: html

<ul class="my_list" id="list-42">
...
</ul>

As you can see it automatically prepends a space in front of the item if the filter returned something unless the second parameter is false.

Changed in version 3.1.4: Keys with / solidus, > greater-than sign, or = equals sign are not allowed.

Changed in version 3.1.3: Keys with spaces are not allowed.

def do_capitalize(s: str) -> str:
321def do_capitalize(s: str) -> str:
322    """Capitalize a value. The first character will be uppercase, all others
323    lowercase.
324    """
325    return soft_str(s).capitalize()

Capitalize a value. The first character will be uppercase, all others lowercase.

def do_title(s: str) -> str:
331def do_title(s: str) -> str:
332    """Return a titlecased version of the value. I.e. words will start with
333    uppercase letters, all remaining characters are lowercase.
334    """
335    return "".join(
336        [
337            item[0].upper() + item[1:].lower()
338            for item in _word_beginning_split_re.split(soft_str(s))
339            if item
340        ]
341    )

Return a titlecased version of the value. I.e. words will start with uppercase letters, all remaining characters are lowercase.

def do_dictsort( value: Mapping[~K, ~V], case_sensitive: bool = False, by: Literal['key', 'value'] = 'key', reverse: bool = False) -> List[Tuple[~K, ~V]]:
344def do_dictsort(
345    value: t.Mapping[K, V],
346    case_sensitive: bool = False,
347    by: 'te.Literal["key", "value"]' = "key",
348    reverse: bool = False,
349) -> t.List[t.Tuple[K, V]]:
350    """Sort a dict and yield (key, value) pairs. Python dicts may not
351    be in the order you want to display them in, so sort them first.
352
353    .. sourcecode:: jinja
354
355        {% for key, value in mydict|dictsort %}
356            sort the dict by key, case insensitive
357
358        {% for key, value in mydict|dictsort(reverse=true) %}
359            sort the dict by key, case insensitive, reverse order
360
361        {% for key, value in mydict|dictsort(true) %}
362            sort the dict by key, case sensitive
363
364        {% for key, value in mydict|dictsort(false, 'value') %}
365            sort the dict by value, case insensitive
366    """
367    if by == "key":
368        pos = 0
369    elif by == "value":
370        pos = 1
371    else:
372        raise FilterArgumentError('You can only sort by either "key" or "value"')
373
374    def sort_func(item: t.Tuple[t.Any, t.Any]) -> t.Any:
375        value = item[pos]
376
377        if not case_sensitive:
378            value = ignore_case(value)
379
380        return value
381
382    return sorted(value.items(), key=sort_func, reverse=reverse)

Sort a dict and yield (key, value) pairs. Python dicts may not be in the order you want to display them in, so sort them first.

.. sourcecode:: jinja

{% for key, value in mydict|dictsort %}
    sort the dict by key, case insensitive

{% for key, value in mydict|dictsort(reverse=true) %}
    sort the dict by key, case insensitive, reverse order

{% for key, value in mydict|dictsort(true) %}
    sort the dict by key, case sensitive

{% for key, value in mydict|dictsort(false, 'value') %}
    sort the dict by value, case insensitive
@pass_environment
def do_sort( environment: jinja2.environment.Environment, value: Iterable[~V], reverse: bool = False, case_sensitive: bool = False, attribute: Union[str, int, NoneType] = None) -> List[~V]:
385@pass_environment
386def do_sort(
387    environment: "Environment",
388    value: "t.Iterable[V]",
389    reverse: bool = False,
390    case_sensitive: bool = False,
391    attribute: t.Optional[t.Union[str, int]] = None,
392) -> "t.List[V]":
393    """Sort an iterable using Python's :func:`sorted`.
394
395    .. sourcecode:: jinja
396
397        {% for city in cities|sort %}
398            ...
399        {% endfor %}
400
401    :param reverse: Sort descending instead of ascending.
402    :param case_sensitive: When sorting strings, sort upper and lower
403        case separately.
404    :param attribute: When sorting objects or dicts, an attribute or
405        key to sort by. Can use dot notation like ``"address.city"``.
406        Can be a list of attributes like ``"age,name"``.
407
408    The sort is stable, it does not change the relative order of
409    elements that compare equal. This makes it is possible to chain
410    sorts on different attributes and ordering.
411
412    .. sourcecode:: jinja
413
414        {% for user in users|sort(attribute="name")
415            |sort(reverse=true, attribute="age") %}
416            ...
417        {% endfor %}
418
419    As a shortcut to chaining when the direction is the same for all
420    attributes, pass a comma separate list of attributes.
421
422    .. sourcecode:: jinja
423
424        {% for user in users|sort(attribute="age,name") %}
425            ...
426        {% endfor %}
427
428    .. versionchanged:: 2.11.0
429        The ``attribute`` parameter can be a comma separated list of
430        attributes, e.g. ``"age,name"``.
431
432    .. versionchanged:: 2.6
433       The ``attribute`` parameter was added.
434    """
435    key_func = make_multi_attrgetter(
436        environment, attribute, postprocess=ignore_case if not case_sensitive else None
437    )
438    return sorted(value, key=key_func, reverse=reverse)

Sort an iterable using Python's sorted().

.. sourcecode:: jinja

{% for city in cities|sort %}
    ...
{% endfor %}
Parameters
  • reverse: Sort descending instead of ascending.
  • case_sensitive: When sorting strings, sort upper and lower case separately.
  • attribute: When sorting objects or dicts, an attribute or key to sort by. Can use dot notation like "address.city". Can be a list of attributes like "age,name".

The sort is stable, it does not change the relative order of elements that compare equal. This makes it is possible to chain sorts on different attributes and ordering.

.. sourcecode:: jinja

{% for user in users|sort(attribute="name")
    |sort(reverse=true, attribute="age") %}
    ...
{% endfor %}

As a shortcut to chaining when the direction is the same for all attributes, pass a comma separate list of attributes.

.. sourcecode:: jinja

{% for user in users|sort(attribute="age,name") %}
    ...
{% endfor %}

Changed in version 2.11.0: The attribute parameter can be a comma separated list of attributes, e.g. "age,name".

Changed in version 2.6: The attribute parameter was added.

@pass_environment
def do_unique( environment: jinja2.environment.Environment, value: Iterable[~V], case_sensitive: bool = False, attribute: Union[str, int, NoneType] = None) -> Iterator[~V]:
441@pass_environment
442def do_unique(
443    environment: "Environment",
444    value: "t.Iterable[V]",
445    case_sensitive: bool = False,
446    attribute: t.Optional[t.Union[str, int]] = None,
447) -> "t.Iterator[V]":
448    """Returns a list of unique items from the given iterable.
449
450    .. sourcecode:: jinja
451
452        {{ ['foo', 'bar', 'foobar', 'FooBar']|unique|list }}
453            -> ['foo', 'bar', 'foobar']
454
455    The unique items are yielded in the same order as their first occurrence in
456    the iterable passed to the filter.
457
458    :param case_sensitive: Treat upper and lower case strings as distinct.
459    :param attribute: Filter objects with unique values for this attribute.
460    """
461    getter = make_attrgetter(
462        environment, attribute, postprocess=ignore_case if not case_sensitive else None
463    )
464    seen = set()
465
466    for item in value:
467        key = getter(item)
468
469        if key not in seen:
470            seen.add(key)
471            yield item

Returns a list of unique items from the given iterable.

.. sourcecode:: jinja

{{ ['foo', 'bar', 'foobar', 'FooBar']|unique|list }}
    -> ['foo', 'bar', 'foobar']

The unique items are yielded in the same order as their first occurrence in the iterable passed to the filter.

Parameters
  • case_sensitive: Treat upper and lower case strings as distinct.
  • attribute: Filter objects with unique values for this attribute.
@pass_environment
def do_min( environment: jinja2.environment.Environment, value: Iterable[~V], case_sensitive: bool = False, attribute: Union[str, int, NoneType] = None) -> Union[~V, jinja2.runtime.Undefined]:
494@pass_environment
495def do_min(
496    environment: "Environment",
497    value: "t.Iterable[V]",
498    case_sensitive: bool = False,
499    attribute: t.Optional[t.Union[str, int]] = None,
500) -> "t.Union[V, Undefined]":
501    """Return the smallest item from the sequence.
502
503    .. sourcecode:: jinja
504
505        {{ [1, 2, 3]|min }}
506            -> 1
507
508    :param case_sensitive: Treat upper and lower case strings as distinct.
509    :param attribute: Get the object with the min value of this attribute.
510    """
511    return _min_or_max(environment, value, min, case_sensitive, attribute)

Return the smallest item from the sequence.

.. sourcecode:: jinja

{{ [1, 2, 3]|min }}
    -> 1
Parameters
  • case_sensitive: Treat upper and lower case strings as distinct.
  • attribute: Get the object with the min value of this attribute.
@pass_environment
def do_max( environment: jinja2.environment.Environment, value: Iterable[~V], case_sensitive: bool = False, attribute: Union[str, int, NoneType] = None) -> Union[~V, jinja2.runtime.Undefined]:
514@pass_environment
515def do_max(
516    environment: "Environment",
517    value: "t.Iterable[V]",
518    case_sensitive: bool = False,
519    attribute: t.Optional[t.Union[str, int]] = None,
520) -> "t.Union[V, Undefined]":
521    """Return the largest item from the sequence.
522
523    .. sourcecode:: jinja
524
525        {{ [1, 2, 3]|max }}
526            -> 3
527
528    :param case_sensitive: Treat upper and lower case strings as distinct.
529    :param attribute: Get the object with the max value of this attribute.
530    """
531    return _min_or_max(environment, value, max, case_sensitive, attribute)

Return the largest item from the sequence.

.. sourcecode:: jinja

{{ [1, 2, 3]|max }}
    -> 3
Parameters
  • case_sensitive: Treat upper and lower case strings as distinct.
  • attribute: Get the object with the max value of this attribute.
def do_default(value: ~V, default_value: ~V = '', boolean: bool = False) -> ~V:
534def do_default(
535    value: V,
536    default_value: V = "",  # type: ignore
537    boolean: bool = False,
538) -> V:
539    """If the value is undefined it will return the passed default value,
540    otherwise the value of the variable:
541
542    .. sourcecode:: jinja
543
544        {{ my_variable|default('my_variable is not defined') }}
545
546    This will output the value of ``my_variable`` if the variable was
547    defined, otherwise ``'my_variable is not defined'``. If you want
548    to use default with variables that evaluate to false you have to
549    set the second parameter to `true`:
550
551    .. sourcecode:: jinja
552
553        {{ ''|default('the string was empty', true) }}
554
555    .. versionchanged:: 2.11
556       It's now possible to configure the :class:`~jinja2.Environment` with
557       :class:`~jinja2.ChainableUndefined` to make the `default` filter work
558       on nested elements and attributes that may contain undefined values
559       in the chain without getting an :exc:`~jinja2.UndefinedError`.
560    """
561    if isinstance(value, Undefined) or (boolean and not value):
562        return default_value
563
564    return value

If the value is undefined it will return the passed default value, otherwise the value of the variable:

.. sourcecode:: jinja

{{ my_variable|default('my_variable is not defined') }}

This will output the value of my_variable if the variable was defined, otherwise 'my_variable is not defined'. If you want to use default with variables that evaluate to false you have to set the second parameter to true:

.. sourcecode:: jinja

{{ ''|default('the string was empty', true) }}

Changed in version 2.11: It's now possible to configure the ~jinja2.Environment with ~jinja2.ChainableUndefined to make the default filter work on nested elements and attributes that may contain undefined values in the chain without getting an ~jinja2.UndefinedError.

@pass_eval_context
def sync_do_join( eval_ctx: jinja2.nodes.EvalContext, value: Iterable[Any], d: str = '', attribute: Union[str, int, NoneType] = None) -> str:
567@pass_eval_context
568def sync_do_join(
569    eval_ctx: "EvalContext",
570    value: t.Iterable[t.Any],
571    d: str = "",
572    attribute: t.Optional[t.Union[str, int]] = None,
573) -> str:
574    """Return a string which is the concatenation of the strings in the
575    sequence. The separator between elements is an empty string per
576    default, you can define it with the optional parameter:
577
578    .. sourcecode:: jinja
579
580        {{ [1, 2, 3]|join('|') }}
581            -> 1|2|3
582
583        {{ [1, 2, 3]|join }}
584            -> 123
585
586    It is also possible to join certain attributes of an object:
587
588    .. sourcecode:: jinja
589
590        {{ users|join(', ', attribute='username') }}
591
592    .. versionadded:: 2.6
593       The `attribute` parameter was added.
594    """
595    if attribute is not None:
596        value = map(make_attrgetter(eval_ctx.environment, attribute), value)
597
598    # no automatic escaping?  joining is a lot easier then
599    if not eval_ctx.autoescape:
600        return str(d).join(map(str, value))
601
602    # if the delimiter doesn't have an html representation we check
603    # if any of the items has.  If yes we do a coercion to Markup
604    if not hasattr(d, "__html__"):
605        value = list(value)
606        do_escape = False
607
608        for idx, item in enumerate(value):
609            if hasattr(item, "__html__"):
610                do_escape = True
611            else:
612                value[idx] = str(item)
613
614        if do_escape:
615            d = escape(d)
616        else:
617            d = str(d)
618
619        return d.join(value)
620
621    # no html involved, to normal joining
622    return soft_str(d).join(map(soft_str, value))

Return a string which is the concatenation of the strings in the sequence. The separator between elements is an empty string per default, you can define it with the optional parameter:

.. sourcecode:: jinja

{{ [1, 2, 3]|join('|') }}
    -> 1|2|3

{{ [1, 2, 3]|join }}
    -> 123

It is also possible to join certain attributes of an object:

.. sourcecode:: jinja

{{ users|join(', ', attribute='username') }}

New in version 2.6: The attribute parameter was added.

@pass_eval_context
def do_join( eval_ctx: jinja2.nodes.EvalContext, value: Iterable[Any], d: str = '', attribute: Union[str, int, NoneType] = None) -> str:
567@pass_eval_context
568def sync_do_join(
569    eval_ctx: "EvalContext",
570    value: t.Iterable[t.Any],
571    d: str = "",
572    attribute: t.Optional[t.Union[str, int]] = None,
573) -> str:
574    """Return a string which is the concatenation of the strings in the
575    sequence. The separator between elements is an empty string per
576    default, you can define it with the optional parameter:
577
578    .. sourcecode:: jinja
579
580        {{ [1, 2, 3]|join('|') }}
581            -> 1|2|3
582
583        {{ [1, 2, 3]|join }}
584            -> 123
585
586    It is also possible to join certain attributes of an object:
587
588    .. sourcecode:: jinja
589
590        {{ users|join(', ', attribute='username') }}
591
592    .. versionadded:: 2.6
593       The `attribute` parameter was added.
594    """
595    if attribute is not None:
596        value = map(make_attrgetter(eval_ctx.environment, attribute), value)
597
598    # no automatic escaping?  joining is a lot easier then
599    if not eval_ctx.autoescape:
600        return str(d).join(map(str, value))
601
602    # if the delimiter doesn't have an html representation we check
603    # if any of the items has.  If yes we do a coercion to Markup
604    if not hasattr(d, "__html__"):
605        value = list(value)
606        do_escape = False
607
608        for idx, item in enumerate(value):
609            if hasattr(item, "__html__"):
610                do_escape = True
611            else:
612                value[idx] = str(item)
613
614        if do_escape:
615            d = escape(d)
616        else:
617            d = str(d)
618
619        return d.join(value)
620
621    # no html involved, to normal joining
622    return soft_str(d).join(map(soft_str, value))

Return a string which is the concatenation of the strings in the sequence. The separator between elements is an empty string per default, you can define it with the optional parameter:

.. sourcecode:: jinja

{{ [1, 2, 3]|join('|') }}
    -> 1|2|3

{{ [1, 2, 3]|join }}
    -> 123

It is also possible to join certain attributes of an object:

.. sourcecode:: jinja

{{ users|join(', ', attribute='username') }}

New in version 2.6: The attribute parameter was added.

def do_center(value: str, width: int = 80) -> str:
635def do_center(value: str, width: int = 80) -> str:
636    """Centers the value in a field of a given width."""
637    return soft_str(value).center(width)

Centers the value in a field of a given width.

@pass_environment
def sync_do_first( environment: jinja2.environment.Environment, seq: Iterable[~V]) -> Union[~V, jinja2.runtime.Undefined]:
640@pass_environment
641def sync_do_first(
642    environment: "Environment", seq: "t.Iterable[V]"
643) -> "t.Union[V, Undefined]":
644    """Return the first item of a sequence."""
645    try:
646        return next(iter(seq))
647    except StopIteration:
648        return environment.undefined("No first item, sequence was empty.")

Return the first item of a sequence.

@pass_environment
def do_first( environment: jinja2.environment.Environment, seq: Iterable[~V]) -> Union[~V, jinja2.runtime.Undefined]:
640@pass_environment
641def sync_do_first(
642    environment: "Environment", seq: "t.Iterable[V]"
643) -> "t.Union[V, Undefined]":
644    """Return the first item of a sequence."""
645    try:
646        return next(iter(seq))
647    except StopIteration:
648        return environment.undefined("No first item, sequence was empty.")

Return the first item of a sequence.

@pass_environment
def do_last( environment: jinja2.environment.Environment, seq: Reversible[~V]) -> Union[~V, jinja2.runtime.Undefined]:
661@pass_environment
662def do_last(
663    environment: "Environment", seq: "t.Reversible[V]"
664) -> "t.Union[V, Undefined]":
665    """Return the last item of a sequence.
666
667    Note: Does not work with generators. You may want to explicitly
668    convert it to a list:
669
670    .. sourcecode:: jinja
671
672        {{ data | selectattr('name', '==', 'Jinja') | list | last }}
673    """
674    try:
675        return next(iter(reversed(seq)))
676    except StopIteration:
677        return environment.undefined("No last item, sequence was empty.")

Return the last item of a sequence.

Note: Does not work with generators. You may want to explicitly convert it to a list:

.. sourcecode:: jinja

{{ data | selectattr('name', '==', 'Jinja') | list | last }}
@pass_context
def do_random( context: jinja2.runtime.Context, seq: Sequence[~V]) -> Union[~V, jinja2.runtime.Undefined]:
683@pass_context
684def do_random(context: "Context", seq: "t.Sequence[V]") -> "t.Union[V, Undefined]":
685    """Return a random item from the sequence."""
686    try:
687        return random.choice(seq)
688    except IndexError:
689        return context.environment.undefined("No random item, sequence was empty.")

Return a random item from the sequence.

def do_filesizeformat(value: Union[str, float, int], binary: bool = False) -> str:
692def do_filesizeformat(value: t.Union[str, float, int], binary: bool = False) -> str:
693    """Format the value like a 'human-readable' file size (i.e. 13 kB,
694    4.1 MB, 102 Bytes, etc).  Per default decimal prefixes are used (Mega,
695    Giga, etc.), if the second parameter is set to `True` the binary
696    prefixes are used (Mebi, Gibi).
697    """
698    bytes = float(value)
699    base = 1024 if binary else 1000
700    prefixes = [
701        ("KiB" if binary else "kB"),
702        ("MiB" if binary else "MB"),
703        ("GiB" if binary else "GB"),
704        ("TiB" if binary else "TB"),
705        ("PiB" if binary else "PB"),
706        ("EiB" if binary else "EB"),
707        ("ZiB" if binary else "ZB"),
708        ("YiB" if binary else "YB"),
709    ]
710
711    if bytes == 1:
712        return "1 Byte"
713    elif bytes < base:
714        return f"{int(bytes)} Bytes"
715    else:
716        for i, prefix in enumerate(prefixes):
717            unit = base ** (i + 2)
718
719            if bytes < unit:
720                return f"{base * bytes / unit:.1f} {prefix}"
721
722        return f"{base * bytes / unit:.1f} {prefix}"

Format the value like a 'human-readable' file size (i.e. 13 kB, 4.1 MB, 102 Bytes, etc). Per default decimal prefixes are used (Mega, Giga, etc.), if the second parameter is set to True the binary prefixes are used (Mebi, Gibi).

def do_pprint(value: Any) -> str:
725def do_pprint(value: t.Any) -> str:
726    """Pretty print a variable. Useful for debugging."""
727    return pformat(value)

Pretty print a variable. Useful for debugging.

@pass_eval_context
def do_urlize( eval_ctx: jinja2.nodes.EvalContext, value: str, trim_url_limit: Optional[int] = None, nofollow: bool = False, target: Optional[str] = None, rel: Optional[str] = None, extra_schemes: Optional[Iterable[str]] = None) -> str:
733@pass_eval_context
734def do_urlize(
735    eval_ctx: "EvalContext",
736    value: str,
737    trim_url_limit: t.Optional[int] = None,
738    nofollow: bool = False,
739    target: t.Optional[str] = None,
740    rel: t.Optional[str] = None,
741    extra_schemes: t.Optional[t.Iterable[str]] = None,
742) -> str:
743    """Convert URLs in text into clickable links.
744
745    This may not recognize links in some situations. Usually, a more
746    comprehensive formatter, such as a Markdown library, is a better
747    choice.
748
749    Works on ``http://``, ``https://``, ``www.``, ``mailto:``, and email
750    addresses. Links with trailing punctuation (periods, commas, closing
751    parentheses) and leading punctuation (opening parentheses) are
752    recognized excluding the punctuation. Email addresses that include
753    header fields are not recognized (for example,
754    ``mailto:address@example.com?cc=copy@example.com``).
755
756    :param value: Original text containing URLs to link.
757    :param trim_url_limit: Shorten displayed URL values to this length.
758    :param nofollow: Add the ``rel=nofollow`` attribute to links.
759    :param target: Add the ``target`` attribute to links.
760    :param rel: Add the ``rel`` attribute to links.
761    :param extra_schemes: Recognize URLs that start with these schemes
762        in addition to the default behavior. Defaults to
763        ``env.policies["urlize.extra_schemes"]``, which defaults to no
764        extra schemes.
765
766    .. versionchanged:: 3.0
767        The ``extra_schemes`` parameter was added.
768
769    .. versionchanged:: 3.0
770        Generate ``https://`` links for URLs without a scheme.
771
772    .. versionchanged:: 3.0
773        The parsing rules were updated. Recognize email addresses with
774        or without the ``mailto:`` scheme. Validate IP addresses. Ignore
775        parentheses and brackets in more cases.
776
777    .. versionchanged:: 2.8
778       The ``target`` parameter was added.
779    """
780    policies = eval_ctx.environment.policies
781    rel_parts = set((rel or "").split())
782
783    if nofollow:
784        rel_parts.add("nofollow")
785
786    rel_parts.update((policies["urlize.rel"] or "").split())
787    rel = " ".join(sorted(rel_parts)) or None
788
789    if target is None:
790        target = policies["urlize.target"]
791
792    if extra_schemes is None:
793        extra_schemes = policies["urlize.extra_schemes"] or ()
794
795    for scheme in extra_schemes:
796        if _uri_scheme_re.fullmatch(scheme) is None:
797            raise FilterArgumentError(f"{scheme!r} is not a valid URI scheme prefix.")
798
799    rv = urlize(
800        value,
801        trim_url_limit=trim_url_limit,
802        rel=rel,
803        target=target,
804        extra_schemes=extra_schemes,
805    )
806
807    if eval_ctx.autoescape:
808        rv = Markup(rv)
809
810    return rv

Convert URLs in text into clickable links.

This may not recognize links in some situations. Usually, a more comprehensive formatter, such as a Markdown library, is a better choice.

Works on http://, https://, www., mailto:, and email addresses. Links with trailing punctuation (periods, commas, closing parentheses) and leading punctuation (opening parentheses) are recognized excluding the punctuation. Email addresses that include header fields are not recognized (for example, mailto:address@example.com?cc=copy@example.com).

Parameters
  • value: Original text containing URLs to link.
  • trim_url_limit: Shorten displayed URL values to this length.
  • nofollow: Add the rel=nofollow attribute to links.
  • target: Add the target attribute to links.
  • rel: Add the rel attribute to links.
  • extra_schemes: Recognize URLs that start with these schemes in addition to the default behavior. Defaults to env.policies["urlize.extra_schemes"], which defaults to no extra schemes.

Changed in version 3.0: The extra_schemes parameter was added.

Changed in version 3.0: Generate https:// links for URLs without a scheme.

Changed in version 3.0: The parsing rules were updated. Recognize email addresses with or without the mailto: scheme. Validate IP addresses. Ignore parentheses and brackets in more cases.

Changed in version 2.8: The target parameter was added.

def do_indent( s: str, width: Union[int, str] = 4, first: bool = False, blank: bool = False) -> str:
813def do_indent(
814    s: str, width: t.Union[int, str] = 4, first: bool = False, blank: bool = False
815) -> str:
816    """Return a copy of the string with each line indented by 4 spaces. The
817    first line and blank lines are not indented by default.
818
819    :param width: Number of spaces, or a string, to indent by.
820    :param first: Don't skip indenting the first line.
821    :param blank: Don't skip indenting empty lines.
822
823    .. versionchanged:: 3.0
824        ``width`` can be a string.
825
826    .. versionchanged:: 2.10
827        Blank lines are not indented by default.
828
829        Rename the ``indentfirst`` argument to ``first``.
830    """
831    if isinstance(width, str):
832        indention = width
833    else:
834        indention = " " * width
835
836    newline = "\n"
837
838    if isinstance(s, Markup):
839        indention = Markup(indention)
840        newline = Markup(newline)
841
842    s += newline  # this quirk is necessary for splitlines method
843
844    if blank:
845        rv = (newline + indention).join(s.splitlines())
846    else:
847        lines = s.splitlines()
848        rv = lines.pop(0)
849
850        if lines:
851            rv += newline + newline.join(
852                indention + line if line else line for line in lines
853            )
854
855    if first:
856        rv = indention + rv
857
858    return rv

Return a copy of the string with each line indented by 4 spaces. The first line and blank lines are not indented by default.

Parameters
  • width: Number of spaces, or a string, to indent by.
  • first: Don't skip indenting the first line.
  • blank: Don't skip indenting empty lines.

Changed in version 3.0: width can be a string.

Changed in version 2.10: Blank lines are not indented by default.

Rename the indentfirst argument to first.

@pass_environment
def do_truncate( env: jinja2.environment.Environment, s: str, length: int = 255, killwords: bool = False, end: str = '...', leeway: Optional[int] = None) -> str:
861@pass_environment
862def do_truncate(
863    env: "Environment",
864    s: str,
865    length: int = 255,
866    killwords: bool = False,
867    end: str = "...",
868    leeway: t.Optional[int] = None,
869) -> str:
870    """Return a truncated copy of the string. The length is specified
871    with the first parameter which defaults to ``255``. If the second
872    parameter is ``true`` the filter will cut the text at length. Otherwise
873    it will discard the last word. If the text was in fact
874    truncated it will append an ellipsis sign (``"..."``). If you want a
875    different ellipsis sign than ``"..."`` you can specify it using the
876    third parameter. Strings that only exceed the length by the tolerance
877    margin given in the fourth parameter will not be truncated.
878
879    .. sourcecode:: jinja
880
881        {{ "foo bar baz qux"|truncate(9) }}
882            -> "foo..."
883        {{ "foo bar baz qux"|truncate(9, True) }}
884            -> "foo ba..."
885        {{ "foo bar baz qux"|truncate(11) }}
886            -> "foo bar baz qux"
887        {{ "foo bar baz qux"|truncate(11, False, '...', 0) }}
888            -> "foo bar..."
889
890    The default leeway on newer Jinja versions is 5 and was 0 before but
891    can be reconfigured globally.
892    """
893    if leeway is None:
894        leeway = env.policies["truncate.leeway"]
895
896    assert length >= len(end), f"expected length >= {len(end)}, got {length}"
897    assert leeway >= 0, f"expected leeway >= 0, got {leeway}"
898
899    if len(s) <= length + leeway:
900        return s
901
902    if killwords:
903        return s[: length - len(end)] + end
904
905    result = s[: length - len(end)].rsplit(" ", 1)[0]
906    return result + end

Return a truncated copy of the string. The length is specified with the first parameter which defaults to 255. If the second parameter is true the filter will cut the text at length. Otherwise it will discard the last word. If the text was in fact truncated it will append an ellipsis sign ("..."). If you want a different ellipsis sign than "..." you can specify it using the third parameter. Strings that only exceed the length by the tolerance margin given in the fourth parameter will not be truncated.

.. sourcecode:: jinja

{{ "foo bar baz qux"|truncate(9) }}
    -> "foo..."
{{ "foo bar baz qux"|truncate(9, True) }}
    -> "foo ba..."
{{ "foo bar baz qux"|truncate(11) }}
    -> "foo bar baz qux"
{{ "foo bar baz qux"|truncate(11, False, '...', 0) }}
    -> "foo bar..."

The default leeway on newer Jinja versions is 5 and was 0 before but can be reconfigured globally.

@pass_environment
def do_wordwrap( environment: jinja2.environment.Environment, s: str, width: int = 79, break_long_words: bool = True, wrapstring: Optional[str] = None, break_on_hyphens: bool = True) -> str:
909@pass_environment
910def do_wordwrap(
911    environment: "Environment",
912    s: str,
913    width: int = 79,
914    break_long_words: bool = True,
915    wrapstring: t.Optional[str] = None,
916    break_on_hyphens: bool = True,
917) -> str:
918    """Wrap a string to the given width. Existing newlines are treated
919    as paragraphs to be wrapped separately.
920
921    :param s: Original text to wrap.
922    :param width: Maximum length of wrapped lines.
923    :param break_long_words: If a word is longer than ``width``, break
924        it across lines.
925    :param break_on_hyphens: If a word contains hyphens, it may be split
926        across lines.
927    :param wrapstring: String to join each wrapped line. Defaults to
928        :attr:`Environment.newline_sequence`.
929
930    .. versionchanged:: 2.11
931        Existing newlines are treated as paragraphs wrapped separately.
932
933    .. versionchanged:: 2.11
934        Added the ``break_on_hyphens`` parameter.
935
936    .. versionchanged:: 2.7
937        Added the ``wrapstring`` parameter.
938    """
939    import textwrap
940
941    if wrapstring is None:
942        wrapstring = environment.newline_sequence
943
944    # textwrap.wrap doesn't consider existing newlines when wrapping.
945    # If the string has a newline before width, wrap will still insert
946    # a newline at width, resulting in a short line. Instead, split and
947    # wrap each paragraph individually.
948    return wrapstring.join(
949        [
950            wrapstring.join(
951                textwrap.wrap(
952                    line,
953                    width=width,
954                    expand_tabs=False,
955                    replace_whitespace=False,
956                    break_long_words=break_long_words,
957                    break_on_hyphens=break_on_hyphens,
958                )
959            )
960            for line in s.splitlines()
961        ]
962    )

Wrap a string to the given width. Existing newlines are treated as paragraphs to be wrapped separately.

Parameters
  • s: Original text to wrap.
  • width: Maximum length of wrapped lines.
  • break_long_words: If a word is longer than width, break it across lines.
  • break_on_hyphens: If a word contains hyphens, it may be split across lines.
  • wrapstring: String to join each wrapped line. Defaults to Environment.newline_sequence.

Changed in version 2.11: Existing newlines are treated as paragraphs wrapped separately.

Changed in version 2.11: Added the break_on_hyphens parameter.

Changed in version 2.7: Added the wrapstring parameter.

def do_wordcount(s: str) -> int:
968def do_wordcount(s: str) -> int:
969    """Count the words in that string."""
970    return len(_word_re.findall(soft_str(s)))

Count the words in that string.

def do_int(value: Any, default: int = 0, base: int = 10) -> int:
973def do_int(value: t.Any, default: int = 0, base: int = 10) -> int:
974    """Convert the value into an integer. If the
975    conversion doesn't work it will return ``0``. You can
976    override this default using the first parameter. You
977    can also override the default base (10) in the second
978    parameter, which handles input with prefixes such as
979    0b, 0o and 0x for bases 2, 8 and 16 respectively.
980    The base is ignored for decimal numbers and non-string values.
981    """
982    try:
983        if isinstance(value, str):
984            return int(value, base)
985
986        return int(value)
987    except (TypeError, ValueError):
988        # this quirk is necessary so that "42.23"|int gives 42.
989        try:
990            return int(float(value))
991        except (TypeError, ValueError):
992            return default

Convert the value into an integer. If the conversion doesn't work it will return 0. You can override this default using the first parameter. You can also override the default base (10) in the second parameter, which handles input with prefixes such as 0b, 0o and 0x for bases 2, 8 and 16 respectively. The base is ignored for decimal numbers and non-string values.

def do_float(value: Any, default: float = 0.0) -> float:
 995def do_float(value: t.Any, default: float = 0.0) -> float:
 996    """Convert the value into a floating point number. If the
 997    conversion doesn't work it will return ``0.0``. You can
 998    override this default using the first parameter.
 999    """
1000    try:
1001        return float(value)
1002    except (TypeError, ValueError):
1003        return default

Convert the value into a floating point number. If the conversion doesn't work it will return 0.0. You can override this default using the first parameter.

def do_format(value: str, *args: Any, **kwargs: Any) -> str:
1006def do_format(value: str, *args: t.Any, **kwargs: t.Any) -> str:
1007    """Apply the given values to a `printf-style`_ format string, like
1008    ``string % values``.
1009
1010    .. sourcecode:: jinja
1011
1012        {{ "%s, %s!"|format(greeting, name) }}
1013        Hello, World!
1014
1015    In most cases it should be more convenient and efficient to use the
1016    ``%`` operator or :meth:`str.format`.
1017
1018    .. code-block:: text
1019
1020        {{ "%s, %s!" % (greeting, name) }}
1021        {{ "{}, {}!".format(greeting, name) }}
1022
1023    .. _printf-style: https://docs.python.org/library/stdtypes.html
1024        #printf-style-string-formatting
1025    """
1026    if args and kwargs:
1027        raise FilterArgumentError(
1028            "can't handle positional and keyword arguments at the same time"
1029        )
1030
1031    return soft_str(value) % (kwargs or args)

Apply the given values to a printf-style format string, like string % values.

.. sourcecode:: jinja

{{ "%s, %s!"|format(greeting, name) }}
Hello, World!

In most cases it should be more convenient and efficient to use the % operator or str.format().

{{ "%s, %s!" % (greeting, name) }}
{{ "{}, {}!".format(greeting, name) }}
#printf-style-string-formatting
def do_trim(value: str, chars: Optional[str] = None) -> str:
1034def do_trim(value: str, chars: t.Optional[str] = None) -> str:
1035    """Strip leading and trailing characters, by default whitespace."""
1036    return soft_str(value).strip(chars)

Strip leading and trailing characters, by default whitespace.

def do_striptags(value: Union[str, jinja2.filters.HasHTML]) -> str:
1039def do_striptags(value: "t.Union[str, HasHTML]") -> str:
1040    """Strip SGML/XML tags and replace adjacent whitespace by one space."""
1041    if hasattr(value, "__html__"):
1042        value = t.cast("HasHTML", value).__html__()
1043
1044    return Markup(str(value)).striptags()

Strip SGML/XML tags and replace adjacent whitespace by one space.

def sync_do_slice( value: Collection[~V], slices: int, fill_with: Optional[~V] = None) -> Iterator[List[~V]]:
1047def sync_do_slice(
1048    value: "t.Collection[V]", slices: int, fill_with: "t.Optional[V]" = None
1049) -> "t.Iterator[t.List[V]]":
1050    """Slice an iterator and return a list of lists containing
1051    those items. Useful if you want to create a div containing
1052    three ul tags that represent columns:
1053
1054    .. sourcecode:: html+jinja
1055
1056        <div class="columnwrapper">
1057          {%- for column in items|slice(3) %}
1058            <ul class="column-{{ loop.index }}">
1059            {%- for item in column %}
1060              <li>{{ item }}</li>
1061            {%- endfor %}
1062            </ul>
1063          {%- endfor %}
1064        </div>
1065
1066    If you pass it a second argument it's used to fill missing
1067    values on the last iteration.
1068    """
1069    seq = list(value)
1070    length = len(seq)
1071    items_per_slice = length // slices
1072    slices_with_extra = length % slices
1073    offset = 0
1074
1075    for slice_number in range(slices):
1076        start = offset + slice_number * items_per_slice
1077
1078        if slice_number < slices_with_extra:
1079            offset += 1
1080
1081        end = offset + (slice_number + 1) * items_per_slice
1082        tmp = seq[start:end]
1083
1084        if fill_with is not None and slice_number >= slices_with_extra:
1085            tmp.append(fill_with)
1086
1087        yield tmp

Slice an iterator and return a list of lists containing those items. Useful if you want to create a div containing three ul tags that represent columns:

.. sourcecode:: html+jinja

<div class="columnwrapper">
  {%- for column in items|slice(3) %}
    <ul class="column-{{ loop.index }}">
    {%- for item in column %}
      <li>{{ item }}</li>
    {%- endfor %}
    </ul>
  {%- endfor %}
</div>

If you pass it a second argument it's used to fill missing values on the last iteration.

def do_slice( value: Collection[~V], slices: int, fill_with: Optional[~V] = None) -> Iterator[List[~V]]:
1047def sync_do_slice(
1048    value: "t.Collection[V]", slices: int, fill_with: "t.Optional[V]" = None
1049) -> "t.Iterator[t.List[V]]":
1050    """Slice an iterator and return a list of lists containing
1051    those items. Useful if you want to create a div containing
1052    three ul tags that represent columns:
1053
1054    .. sourcecode:: html+jinja
1055
1056        <div class="columnwrapper">
1057          {%- for column in items|slice(3) %}
1058            <ul class="column-{{ loop.index }}">
1059            {%- for item in column %}
1060              <li>{{ item }}</li>
1061            {%- endfor %}
1062            </ul>
1063          {%- endfor %}
1064        </div>
1065
1066    If you pass it a second argument it's used to fill missing
1067    values on the last iteration.
1068    """
1069    seq = list(value)
1070    length = len(seq)
1071    items_per_slice = length // slices
1072    slices_with_extra = length % slices
1073    offset = 0
1074
1075    for slice_number in range(slices):
1076        start = offset + slice_number * items_per_slice
1077
1078        if slice_number < slices_with_extra:
1079            offset += 1
1080
1081        end = offset + (slice_number + 1) * items_per_slice
1082        tmp = seq[start:end]
1083
1084        if fill_with is not None and slice_number >= slices_with_extra:
1085            tmp.append(fill_with)
1086
1087        yield tmp

Slice an iterator and return a list of lists containing those items. Useful if you want to create a div containing three ul tags that represent columns:

.. sourcecode:: html+jinja

<div class="columnwrapper">
  {%- for column in items|slice(3) %}
    <ul class="column-{{ loop.index }}">
    {%- for item in column %}
      <li>{{ item }}</li>
    {%- endfor %}
    </ul>
  {%- endfor %}
</div>

If you pass it a second argument it's used to fill missing values on the last iteration.

def do_batch( value: Iterable[~V], linecount: int, fill_with: Optional[~V] = None) -> Iterator[List[~V]]:
1099def do_batch(
1100    value: "t.Iterable[V]", linecount: int, fill_with: "t.Optional[V]" = None
1101) -> "t.Iterator[t.List[V]]":
1102    """
1103    A filter that batches items. It works pretty much like `slice`
1104    just the other way round. It returns a list of lists with the
1105    given number of items. If you provide a second parameter this
1106    is used to fill up missing items. See this example:
1107
1108    .. sourcecode:: html+jinja
1109
1110        <table>
1111        {%- for row in items|batch(3, '&nbsp;') %}
1112          <tr>
1113          {%- for column in row %}
1114            <td>{{ column }}</td>
1115          {%- endfor %}
1116          </tr>
1117        {%- endfor %}
1118        </table>
1119    """
1120    tmp: "t.List[V]" = []
1121
1122    for item in value:
1123        if len(tmp) == linecount:
1124            yield tmp
1125            tmp = []
1126
1127        tmp.append(item)
1128
1129    if tmp:
1130        if fill_with is not None and len(tmp) < linecount:
1131            tmp += [fill_with] * (linecount - len(tmp))
1132
1133        yield tmp

A filter that batches items. It works pretty much like slice just the other way round. It returns a list of lists with the given number of items. If you provide a second parameter this is used to fill up missing items. See this example:

.. sourcecode:: html+jinja

<table>
{%- for row in items|batch(3, '&nbsp;') %}
  <tr>
  {%- for column in row %}
    <td>{{ column }}</td>
  {%- endfor %}
  </tr>
{%- endfor %}
</table>
def do_round( value: float, precision: int = 0, method: Literal['common', 'ceil', 'floor'] = 'common') -> float:
1136def do_round(
1137    value: float,
1138    precision: int = 0,
1139    method: 'te.Literal["common", "ceil", "floor"]' = "common",
1140) -> float:
1141    """Round the number to a given precision. The first
1142    parameter specifies the precision (default is ``0``), the
1143    second the rounding method:
1144
1145    - ``'common'`` rounds either up or down
1146    - ``'ceil'`` always rounds up
1147    - ``'floor'`` always rounds down
1148
1149    If you don't specify a method ``'common'`` is used.
1150
1151    .. sourcecode:: jinja
1152
1153        {{ 42.55|round }}
1154            -> 43.0
1155        {{ 42.55|round(1, 'floor') }}
1156            -> 42.5
1157
1158    Note that even if rounded to 0 precision, a float is returned.  If
1159    you need a real integer, pipe it through `int`:
1160
1161    .. sourcecode:: jinja
1162
1163        {{ 42.55|round|int }}
1164            -> 43
1165    """
1166    if method not in {"common", "ceil", "floor"}:
1167        raise FilterArgumentError("method must be common, ceil or floor")
1168
1169    if method == "common":
1170        return round(value, precision)
1171
1172    func = getattr(math, method)
1173    return t.cast(float, func(value * (10**precision)) / (10**precision))

Round the number to a given precision. The first parameter specifies the precision (default is 0), the second the rounding method:

  • 'common' rounds either up or down
  • 'ceil' always rounds up
  • 'floor' always rounds down

If you don't specify a method 'common' is used.

.. sourcecode:: jinja

{{ 42.55|round }}
    -> 43.0
{{ 42.55|round(1, 'floor') }}
    -> 42.5

Note that even if rounded to 0 precision, a float is returned. If you need a real integer, pipe it through int:

.. sourcecode:: jinja

{{ 42.55|round|int }}
    -> 43
@pass_environment
def sync_do_groupby( environment: jinja2.environment.Environment, value: Iterable[~V], attribute: Union[str, int], default: Optional[Any] = None, case_sensitive: bool = False) -> List[jinja2.filters._GroupTuple]:
1189@pass_environment
1190def sync_do_groupby(
1191    environment: "Environment",
1192    value: "t.Iterable[V]",
1193    attribute: t.Union[str, int],
1194    default: t.Optional[t.Any] = None,
1195    case_sensitive: bool = False,
1196) -> "t.List[_GroupTuple]":
1197    """Group a sequence of objects by an attribute using Python's
1198    :func:`itertools.groupby`. The attribute can use dot notation for
1199    nested access, like ``"address.city"``. Unlike Python's ``groupby``,
1200    the values are sorted first so only one group is returned for each
1201    unique value.
1202
1203    For example, a list of ``User`` objects with a ``city`` attribute
1204    can be rendered in groups. In this example, ``grouper`` refers to
1205    the ``city`` value of the group.
1206
1207    .. sourcecode:: html+jinja
1208
1209        <ul>{% for city, items in users|groupby("city") %}
1210          <li>{{ city }}
1211            <ul>{% for user in items %}
1212              <li>{{ user.name }}
1213            {% endfor %}</ul>
1214          </li>
1215        {% endfor %}</ul>
1216
1217    ``groupby`` yields namedtuples of ``(grouper, list)``, which
1218    can be used instead of the tuple unpacking above. ``grouper`` is the
1219    value of the attribute, and ``list`` is the items with that value.
1220
1221    .. sourcecode:: html+jinja
1222
1223        <ul>{% for group in users|groupby("city") %}
1224          <li>{{ group.grouper }}: {{ group.list|join(", ") }}
1225        {% endfor %}</ul>
1226
1227    You can specify a ``default`` value to use if an object in the list
1228    does not have the given attribute.
1229
1230    .. sourcecode:: jinja
1231
1232        <ul>{% for city, items in users|groupby("city", default="NY") %}
1233          <li>{{ city }}: {{ items|map(attribute="name")|join(", ") }}</li>
1234        {% endfor %}</ul>
1235
1236    Like the :func:`~jinja-filters.sort` filter, sorting and grouping is
1237    case-insensitive by default. The ``key`` for each group will have
1238    the case of the first item in that group of values. For example, if
1239    a list of users has cities ``["CA", "NY", "ca"]``, the "CA" group
1240    will have two values. This can be disabled by passing
1241    ``case_sensitive=True``.
1242
1243    .. versionchanged:: 3.1
1244        Added the ``case_sensitive`` parameter. Sorting and grouping is
1245        case-insensitive by default, matching other filters that do
1246        comparisons.
1247
1248    .. versionchanged:: 3.0
1249        Added the ``default`` parameter.
1250
1251    .. versionchanged:: 2.6
1252        The attribute supports dot notation for nested access.
1253    """
1254    expr = make_attrgetter(
1255        environment,
1256        attribute,
1257        postprocess=ignore_case if not case_sensitive else None,
1258        default=default,
1259    )
1260    out = [
1261        _GroupTuple(key, list(values))
1262        for key, values in groupby(sorted(value, key=expr), expr)
1263    ]
1264
1265    if not case_sensitive:
1266        # Return the real key from the first value instead of the lowercase key.
1267        output_expr = make_attrgetter(environment, attribute, default=default)
1268        out = [_GroupTuple(output_expr(values[0]), values) for _, values in out]
1269
1270    return out

Group a sequence of objects by an attribute using Python's itertools.groupby(). The attribute can use dot notation for nested access, like "address.city". Unlike Python's groupby, the values are sorted first so only one group is returned for each unique value.

For example, a list of User objects with a city attribute can be rendered in groups. In this example, grouper refers to the city value of the group.

.. sourcecode:: html+jinja

<ul>{% for city, items in users|groupby("city") %}
  <li>{{ city }}
    <ul>{% for user in items %}
      <li>{{ user.name }}
    {% endfor %}</ul>
  </li>
{% endfor %}</ul>

groupby yields namedtuples of (grouper, list), which can be used instead of the tuple unpacking above. grouper is the value of the attribute, and list is the items with that value.

.. sourcecode:: html+jinja

<ul>{% for group in users|groupby("city") %}
  <li>{{ group.grouper }}: {{ group.list|join(", ") }}
{% endfor %}</ul>

You can specify a default value to use if an object in the list does not have the given attribute.

.. sourcecode:: jinja

<ul>{% for city, items in users|groupby("city", default="NY") %}
  <li>{{ city }}: {{ items|map(attribute="name")|join(", ") }}</li>
{% endfor %}</ul>

Like the ~jinja-filters.sort() filter, sorting and grouping is case-insensitive by default. The key for each group will have the case of the first item in that group of values. For example, if a list of users has cities ["CA", "NY", "ca"], the "CA" group will have two values. This can be disabled by passing case_sensitive=True.

Changed in version 3.1: Added the case_sensitive parameter. Sorting and grouping is case-insensitive by default, matching other filters that do comparisons.

Changed in version 3.0: Added the default parameter.

Changed in version 2.6: The attribute supports dot notation for nested access.

@pass_environment
def do_groupby( environment: jinja2.environment.Environment, value: Iterable[~V], attribute: Union[str, int], default: Optional[Any] = None, case_sensitive: bool = False) -> List[jinja2.filters._GroupTuple]:
1189@pass_environment
1190def sync_do_groupby(
1191    environment: "Environment",
1192    value: "t.Iterable[V]",
1193    attribute: t.Union[str, int],
1194    default: t.Optional[t.Any] = None,
1195    case_sensitive: bool = False,
1196) -> "t.List[_GroupTuple]":
1197    """Group a sequence of objects by an attribute using Python's
1198    :func:`itertools.groupby`. The attribute can use dot notation for
1199    nested access, like ``"address.city"``. Unlike Python's ``groupby``,
1200    the values are sorted first so only one group is returned for each
1201    unique value.
1202
1203    For example, a list of ``User`` objects with a ``city`` attribute
1204    can be rendered in groups. In this example, ``grouper`` refers to
1205    the ``city`` value of the group.
1206
1207    .. sourcecode:: html+jinja
1208
1209        <ul>{% for city, items in users|groupby("city") %}
1210          <li>{{ city }}
1211            <ul>{% for user in items %}
1212              <li>{{ user.name }}
1213            {% endfor %}</ul>
1214          </li>
1215        {% endfor %}</ul>
1216
1217    ``groupby`` yields namedtuples of ``(grouper, list)``, which
1218    can be used instead of the tuple unpacking above. ``grouper`` is the
1219    value of the attribute, and ``list`` is the items with that value.
1220
1221    .. sourcecode:: html+jinja
1222
1223        <ul>{% for group in users|groupby("city") %}
1224          <li>{{ group.grouper }}: {{ group.list|join(", ") }}
1225        {% endfor %}</ul>
1226
1227    You can specify a ``default`` value to use if an object in the list
1228    does not have the given attribute.
1229
1230    .. sourcecode:: jinja
1231
1232        <ul>{% for city, items in users|groupby("city", default="NY") %}
1233          <li>{{ city }}: {{ items|map(attribute="name")|join(", ") }}</li>
1234        {% endfor %}</ul>
1235
1236    Like the :func:`~jinja-filters.sort` filter, sorting and grouping is
1237    case-insensitive by default. The ``key`` for each group will have
1238    the case of the first item in that group of values. For example, if
1239    a list of users has cities ``["CA", "NY", "ca"]``, the "CA" group
1240    will have two values. This can be disabled by passing
1241    ``case_sensitive=True``.
1242
1243    .. versionchanged:: 3.1
1244        Added the ``case_sensitive`` parameter. Sorting and grouping is
1245        case-insensitive by default, matching other filters that do
1246        comparisons.
1247
1248    .. versionchanged:: 3.0
1249        Added the ``default`` parameter.
1250
1251    .. versionchanged:: 2.6
1252        The attribute supports dot notation for nested access.
1253    """
1254    expr = make_attrgetter(
1255        environment,
1256        attribute,
1257        postprocess=ignore_case if not case_sensitive else None,
1258        default=default,
1259    )
1260    out = [
1261        _GroupTuple(key, list(values))
1262        for key, values in groupby(sorted(value, key=expr), expr)
1263    ]
1264
1265    if not case_sensitive:
1266        # Return the real key from the first value instead of the lowercase key.
1267        output_expr = make_attrgetter(environment, attribute, default=default)
1268        out = [_GroupTuple(output_expr(values[0]), values) for _, values in out]
1269
1270    return out

Group a sequence of objects by an attribute using Python's itertools.groupby(). The attribute can use dot notation for nested access, like "address.city". Unlike Python's groupby, the values are sorted first so only one group is returned for each unique value.

For example, a list of User objects with a city attribute can be rendered in groups. In this example, grouper refers to the city value of the group.

.. sourcecode:: html+jinja

<ul>{% for city, items in users|groupby("city") %}
  <li>{{ city }}
    <ul>{% for user in items %}
      <li>{{ user.name }}
    {% endfor %}</ul>
  </li>
{% endfor %}</ul>

groupby yields namedtuples of (grouper, list), which can be used instead of the tuple unpacking above. grouper is the value of the attribute, and list is the items with that value.

.. sourcecode:: html+jinja

<ul>{% for group in users|groupby("city") %}
  <li>{{ group.grouper }}: {{ group.list|join(", ") }}
{% endfor %}</ul>

You can specify a default value to use if an object in the list does not have the given attribute.

.. sourcecode:: jinja

<ul>{% for city, items in users|groupby("city", default="NY") %}
  <li>{{ city }}: {{ items|map(attribute="name")|join(", ") }}</li>
{% endfor %}</ul>

Like the ~jinja-filters.sort() filter, sorting and grouping is case-insensitive by default. The key for each group will have the case of the first item in that group of values. For example, if a list of users has cities ["CA", "NY", "ca"], the "CA" group will have two values. This can be disabled by passing case_sensitive=True.

Changed in version 3.1: Added the case_sensitive parameter. Sorting and grouping is case-insensitive by default, matching other filters that do comparisons.

Changed in version 3.0: Added the default parameter.

Changed in version 2.6: The attribute supports dot notation for nested access.

@pass_environment
def sync_do_sum( environment: jinja2.environment.Environment, iterable: Iterable[~V], attribute: Union[str, int, NoneType] = None, start: ~V = 0) -> ~V:
1300@pass_environment
1301def sync_do_sum(
1302    environment: "Environment",
1303    iterable: "t.Iterable[V]",
1304    attribute: t.Optional[t.Union[str, int]] = None,
1305    start: V = 0,  # type: ignore
1306) -> V:
1307    """Returns the sum of a sequence of numbers plus the value of parameter
1308    'start' (which defaults to 0).  When the sequence is empty it returns
1309    start.
1310
1311    It is also possible to sum up only certain attributes:
1312
1313    .. sourcecode:: jinja
1314
1315        Total: {{ items|sum(attribute='price') }}
1316
1317    .. versionchanged:: 2.6
1318       The ``attribute`` parameter was added to allow summing up over
1319       attributes.  Also the ``start`` parameter was moved on to the right.
1320    """
1321    if attribute is not None:
1322        iterable = map(make_attrgetter(environment, attribute), iterable)
1323
1324    return sum(iterable, start)  # type: ignore[no-any-return, call-overload]

Returns the sum of a sequence of numbers plus the value of parameter 'start' (which defaults to 0). When the sequence is empty it returns start.

It is also possible to sum up only certain attributes:

.. sourcecode:: jinja

Total: {{ items|sum(attribute='price') }}

Changed in version 2.6: The attribute parameter was added to allow summing up over attributes. Also the start parameter was moved on to the right.

@pass_environment
def do_sum( environment: jinja2.environment.Environment, iterable: Iterable[~V], attribute: Union[str, int, NoneType] = None, start: ~V = 0) -> ~V:
1300@pass_environment
1301def sync_do_sum(
1302    environment: "Environment",
1303    iterable: "t.Iterable[V]",
1304    attribute: t.Optional[t.Union[str, int]] = None,
1305    start: V = 0,  # type: ignore
1306) -> V:
1307    """Returns the sum of a sequence of numbers plus the value of parameter
1308    'start' (which defaults to 0).  When the sequence is empty it returns
1309    start.
1310
1311    It is also possible to sum up only certain attributes:
1312
1313    .. sourcecode:: jinja
1314
1315        Total: {{ items|sum(attribute='price') }}
1316
1317    .. versionchanged:: 2.6
1318       The ``attribute`` parameter was added to allow summing up over
1319       attributes.  Also the ``start`` parameter was moved on to the right.
1320    """
1321    if attribute is not None:
1322        iterable = map(make_attrgetter(environment, attribute), iterable)
1323
1324    return sum(iterable, start)  # type: ignore[no-any-return, call-overload]

Returns the sum of a sequence of numbers plus the value of parameter 'start' (which defaults to 0). When the sequence is empty it returns start.

It is also possible to sum up only certain attributes:

.. sourcecode:: jinja

Total: {{ items|sum(attribute='price') }}

Changed in version 2.6: The attribute parameter was added to allow summing up over attributes. Also the start parameter was moved on to the right.

def sync_do_list(value: Iterable[~V]) -> List[~V]:
1349def sync_do_list(value: "t.Iterable[V]") -> "t.List[V]":
1350    """Convert the value into a list.  If it was a string the returned list
1351    will be a list of characters.
1352    """
1353    return list(value)

Convert the value into a list. If it was a string the returned list will be a list of characters.

def do_list(value: Iterable[~V]) -> List[~V]:
1349def sync_do_list(value: "t.Iterable[V]") -> "t.List[V]":
1350    """Convert the value into a list.  If it was a string the returned list
1351    will be a list of characters.
1352    """
1353    return list(value)

Convert the value into a list. If it was a string the returned list will be a list of characters.

def do_mark_safe(value: str) -> markupsafe.Markup:
1361def do_mark_safe(value: str) -> Markup:
1362    """Mark the value as safe which means that in an environment with automatic
1363    escaping enabled this variable will not be escaped.
1364    """
1365    return Markup(value)

Mark the value as safe which means that in an environment with automatic escaping enabled this variable will not be escaped.

def do_mark_unsafe(value: str) -> str:
1368def do_mark_unsafe(value: str) -> str:
1369    """Mark a value as unsafe.  This is the reverse operation for :func:`safe`."""
1370    return str(value)

Mark a value as unsafe. This is the reverse operation for safe().

def do_reverse(value: Union[str, Iterable[~V]]) -> Union[str, Iterable[~V]]:
1381def do_reverse(value: t.Union[str, t.Iterable[V]]) -> t.Union[str, t.Iterable[V]]:
1382    """Reverse the object or return an iterator that iterates over it the other
1383    way round.
1384    """
1385    if isinstance(value, str):
1386        return value[::-1]
1387
1388    try:
1389        return reversed(value)  # type: ignore
1390    except TypeError:
1391        try:
1392            rv = list(value)
1393            rv.reverse()
1394            return rv
1395        except TypeError as e:
1396            raise FilterArgumentError("argument must be iterable") from e

Reverse the object or return an iterator that iterates over it the other way round.

@pass_environment
def do_attr( environment: jinja2.environment.Environment, obj: Any, name: str) -> Union[jinja2.runtime.Undefined, Any]:
1399@pass_environment
1400def do_attr(
1401    environment: "Environment", obj: t.Any, name: str
1402) -> t.Union[Undefined, t.Any]:
1403    """Get an attribute of an object.  ``foo|attr("bar")`` works like
1404    ``foo.bar`` just that always an attribute is returned and items are not
1405    looked up.
1406
1407    See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details.
1408    """
1409    try:
1410        name = str(name)
1411    except UnicodeError:
1412        pass
1413    else:
1414        try:
1415            value = getattr(obj, name)
1416        except AttributeError:
1417            pass
1418        else:
1419            if environment.sandboxed:
1420                environment = t.cast("SandboxedEnvironment", environment)
1421
1422                if not environment.is_safe_attribute(obj, name, value):
1423                    return environment.unsafe_undefined(obj, name)
1424
1425            return value
1426
1427    return environment.undefined(obj=obj, name=name)

Get an attribute of an object. foo|attr("bar") works like foo.bar just that always an attribute is returned and items are not looked up.

See :ref:Notes on subscriptions <notes-on-subscriptions> for more details.

@pass_context
def sync_do_map( context: jinja2.runtime.Context, value: Iterable[Any], *args: Any, **kwargs: Any) -> Iterable[Any]:
1450@pass_context
1451def sync_do_map(
1452    context: "Context", value: t.Iterable[t.Any], *args: t.Any, **kwargs: t.Any
1453) -> t.Iterable[t.Any]:
1454    """Applies a filter on a sequence of objects or looks up an attribute.
1455    This is useful when dealing with lists of objects but you are really
1456    only interested in a certain value of it.
1457
1458    The basic usage is mapping on an attribute.  Imagine you have a list
1459    of users but you are only interested in a list of usernames:
1460
1461    .. sourcecode:: jinja
1462
1463        Users on this page: {{ users|map(attribute='username')|join(', ') }}
1464
1465    You can specify a ``default`` value to use if an object in the list
1466    does not have the given attribute.
1467
1468    .. sourcecode:: jinja
1469
1470        {{ users|map(attribute="username", default="Anonymous")|join(", ") }}
1471
1472    Alternatively you can let it invoke a filter by passing the name of the
1473    filter and the arguments afterwards.  A good example would be applying a
1474    text conversion filter on a sequence:
1475
1476    .. sourcecode:: jinja
1477
1478        Users on this page: {{ titles|map('lower')|join(', ') }}
1479
1480    Similar to a generator comprehension such as:
1481
1482    .. code-block:: python
1483
1484        (u.username for u in users)
1485        (getattr(u, "username", "Anonymous") for u in users)
1486        (do_lower(x) for x in titles)
1487
1488    .. versionchanged:: 2.11.0
1489        Added the ``default`` parameter.
1490
1491    .. versionadded:: 2.7
1492    """
1493    if value:
1494        func = prepare_map(context, args, kwargs)
1495
1496        for item in value:
1497            yield func(item)

Applies a filter on a sequence of objects or looks up an attribute. This is useful when dealing with lists of objects but you are really only interested in a certain value of it.

The basic usage is mapping on an attribute. Imagine you have a list of users but you are only interested in a list of usernames:

.. sourcecode:: jinja

Users on this page: {{ users|map(attribute='username')|join(', ') }}

You can specify a default value to use if an object in the list does not have the given attribute.

.. sourcecode:: jinja

{{ users|map(attribute="username", default="Anonymous")|join(", ") }}

Alternatively you can let it invoke a filter by passing the name of the filter and the arguments afterwards. A good example would be applying a text conversion filter on a sequence:

.. sourcecode:: jinja

Users on this page: {{ titles|map('lower')|join(', ') }}

Similar to a generator comprehension such as:

(u.username for u in users)
(getattr(u, "username", "Anonymous") for u in users)
(do_lower(x) for x in titles)

Changed in version 2.11.0: Added the default parameter.

New in version 2.7.

@pass_context
def do_map( context: jinja2.runtime.Context, value: Iterable[Any], *args: Any, **kwargs: Any) -> Iterable[Any]:
1450@pass_context
1451def sync_do_map(
1452    context: "Context", value: t.Iterable[t.Any], *args: t.Any, **kwargs: t.Any
1453) -> t.Iterable[t.Any]:
1454    """Applies a filter on a sequence of objects or looks up an attribute.
1455    This is useful when dealing with lists of objects but you are really
1456    only interested in a certain value of it.
1457
1458    The basic usage is mapping on an attribute.  Imagine you have a list
1459    of users but you are only interested in a list of usernames:
1460
1461    .. sourcecode:: jinja
1462
1463        Users on this page: {{ users|map(attribute='username')|join(', ') }}
1464
1465    You can specify a ``default`` value to use if an object in the list
1466    does not have the given attribute.
1467
1468    .. sourcecode:: jinja
1469
1470        {{ users|map(attribute="username", default="Anonymous")|join(", ") }}
1471
1472    Alternatively you can let it invoke a filter by passing the name of the
1473    filter and the arguments afterwards.  A good example would be applying a
1474    text conversion filter on a sequence:
1475
1476    .. sourcecode:: jinja
1477
1478        Users on this page: {{ titles|map('lower')|join(', ') }}
1479
1480    Similar to a generator comprehension such as:
1481
1482    .. code-block:: python
1483
1484        (u.username for u in users)
1485        (getattr(u, "username", "Anonymous") for u in users)
1486        (do_lower(x) for x in titles)
1487
1488    .. versionchanged:: 2.11.0
1489        Added the ``default`` parameter.
1490
1491    .. versionadded:: 2.7
1492    """
1493    if value:
1494        func = prepare_map(context, args, kwargs)
1495
1496        for item in value:
1497            yield func(item)

Applies a filter on a sequence of objects or looks up an attribute. This is useful when dealing with lists of objects but you are really only interested in a certain value of it.

The basic usage is mapping on an attribute. Imagine you have a list of users but you are only interested in a list of usernames:

.. sourcecode:: jinja

Users on this page: {{ users|map(attribute='username')|join(', ') }}

You can specify a default value to use if an object in the list does not have the given attribute.

.. sourcecode:: jinja

{{ users|map(attribute="username", default="Anonymous")|join(", ") }}

Alternatively you can let it invoke a filter by passing the name of the filter and the arguments afterwards. A good example would be applying a text conversion filter on a sequence:

.. sourcecode:: jinja

Users on this page: {{ titles|map('lower')|join(', ') }}

Similar to a generator comprehension such as:

(u.username for u in users)
(getattr(u, "username", "Anonymous") for u in users)
(do_lower(x) for x in titles)

Changed in version 2.11.0: Added the default parameter.

New in version 2.7.

@pass_context
def sync_do_select( context: jinja2.runtime.Context, value: Iterable[~V], *args: Any, **kwargs: Any) -> Iterator[~V]:
1534@pass_context
1535def sync_do_select(
1536    context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
1537) -> "t.Iterator[V]":
1538    """Filters a sequence of objects by applying a test to each object,
1539    and only selecting the objects with the test succeeding.
1540
1541    If no test is specified, each object will be evaluated as a boolean.
1542
1543    Example usage:
1544
1545    .. sourcecode:: jinja
1546
1547        {{ numbers|select("odd") }}
1548        {{ numbers|select("odd") }}
1549        {{ numbers|select("divisibleby", 3) }}
1550        {{ numbers|select("lessthan", 42) }}
1551        {{ strings|select("equalto", "mystring") }}
1552
1553    Similar to a generator comprehension such as:
1554
1555    .. code-block:: python
1556
1557        (n for n in numbers if test_odd(n))
1558        (n for n in numbers if test_divisibleby(n, 3))
1559
1560    .. versionadded:: 2.7
1561    """
1562    return select_or_reject(context, value, args, kwargs, lambda x: x, False)

Filters a sequence of objects by applying a test to each object, and only selecting the objects with the test succeeding.

If no test is specified, each object will be evaluated as a boolean.

Example usage:

.. sourcecode:: jinja

{{ numbers|select("odd") }}
{{ numbers|select("odd") }}
{{ numbers|select("divisibleby", 3) }}
{{ numbers|select("lessthan", 42) }}
{{ strings|select("equalto", "mystring") }}

Similar to a generator comprehension such as:

(n for n in numbers if test_odd(n))
(n for n in numbers if test_divisibleby(n, 3))

New in version 2.7.

@pass_context
def do_select( context: jinja2.runtime.Context, value: Iterable[~V], *args: Any, **kwargs: Any) -> Iterator[~V]:
1534@pass_context
1535def sync_do_select(
1536    context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
1537) -> "t.Iterator[V]":
1538    """Filters a sequence of objects by applying a test to each object,
1539    and only selecting the objects with the test succeeding.
1540
1541    If no test is specified, each object will be evaluated as a boolean.
1542
1543    Example usage:
1544
1545    .. sourcecode:: jinja
1546
1547        {{ numbers|select("odd") }}
1548        {{ numbers|select("odd") }}
1549        {{ numbers|select("divisibleby", 3) }}
1550        {{ numbers|select("lessthan", 42) }}
1551        {{ strings|select("equalto", "mystring") }}
1552
1553    Similar to a generator comprehension such as:
1554
1555    .. code-block:: python
1556
1557        (n for n in numbers if test_odd(n))
1558        (n for n in numbers if test_divisibleby(n, 3))
1559
1560    .. versionadded:: 2.7
1561    """
1562    return select_or_reject(context, value, args, kwargs, lambda x: x, False)

Filters a sequence of objects by applying a test to each object, and only selecting the objects with the test succeeding.

If no test is specified, each object will be evaluated as a boolean.

Example usage:

.. sourcecode:: jinja

{{ numbers|select("odd") }}
{{ numbers|select("odd") }}
{{ numbers|select("divisibleby", 3) }}
{{ numbers|select("lessthan", 42) }}
{{ strings|select("equalto", "mystring") }}

Similar to a generator comprehension such as:

(n for n in numbers if test_odd(n))
(n for n in numbers if test_divisibleby(n, 3))

New in version 2.7.

@pass_context
def sync_do_reject( context: jinja2.runtime.Context, value: Iterable[~V], *args: Any, **kwargs: Any) -> Iterator[~V]:
1575@pass_context
1576def sync_do_reject(
1577    context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
1578) -> "t.Iterator[V]":
1579    """Filters a sequence of objects by applying a test to each object,
1580    and rejecting the objects with the test succeeding.
1581
1582    If no test is specified, each object will be evaluated as a boolean.
1583
1584    Example usage:
1585
1586    .. sourcecode:: jinja
1587
1588        {{ numbers|reject("odd") }}
1589
1590    Similar to a generator comprehension such as:
1591
1592    .. code-block:: python
1593
1594        (n for n in numbers if not test_odd(n))
1595
1596    .. versionadded:: 2.7
1597    """
1598    return select_or_reject(context, value, args, kwargs, lambda x: not x, False)

Filters a sequence of objects by applying a test to each object, and rejecting the objects with the test succeeding.

If no test is specified, each object will be evaluated as a boolean.

Example usage:

.. sourcecode:: jinja

{{ numbers|reject("odd") }}

Similar to a generator comprehension such as:

(n for n in numbers if not test_odd(n))

New in version 2.7.

@pass_context
def do_reject( context: jinja2.runtime.Context, value: Iterable[~V], *args: Any, **kwargs: Any) -> Iterator[~V]:
1575@pass_context
1576def sync_do_reject(
1577    context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
1578) -> "t.Iterator[V]":
1579    """Filters a sequence of objects by applying a test to each object,
1580    and rejecting the objects with the test succeeding.
1581
1582    If no test is specified, each object will be evaluated as a boolean.
1583
1584    Example usage:
1585
1586    .. sourcecode:: jinja
1587
1588        {{ numbers|reject("odd") }}
1589
1590    Similar to a generator comprehension such as:
1591
1592    .. code-block:: python
1593
1594        (n for n in numbers if not test_odd(n))
1595
1596    .. versionadded:: 2.7
1597    """
1598    return select_or_reject(context, value, args, kwargs, lambda x: not x, False)

Filters a sequence of objects by applying a test to each object, and rejecting the objects with the test succeeding.

If no test is specified, each object will be evaluated as a boolean.

Example usage:

.. sourcecode:: jinja

{{ numbers|reject("odd") }}

Similar to a generator comprehension such as:

(n for n in numbers if not test_odd(n))

New in version 2.7.

@pass_context
def sync_do_selectattr( context: jinja2.runtime.Context, value: Iterable[~V], *args: Any, **kwargs: Any) -> Iterator[~V]:
1611@pass_context
1612def sync_do_selectattr(
1613    context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
1614) -> "t.Iterator[V]":
1615    """Filters a sequence of objects by applying a test to the specified
1616    attribute of each object, and only selecting the objects with the
1617    test succeeding.
1618
1619    If no test is specified, the attribute's value will be evaluated as
1620    a boolean.
1621
1622    Example usage:
1623
1624    .. sourcecode:: jinja
1625
1626        {{ users|selectattr("is_active") }}
1627        {{ users|selectattr("email", "none") }}
1628
1629    Similar to a generator comprehension such as:
1630
1631    .. code-block:: python
1632
1633        (u for user in users if user.is_active)
1634        (u for user in users if test_none(user.email))
1635
1636    .. versionadded:: 2.7
1637    """
1638    return select_or_reject(context, value, args, kwargs, lambda x: x, True)

Filters a sequence of objects by applying a test to the specified attribute of each object, and only selecting the objects with the test succeeding.

If no test is specified, the attribute's value will be evaluated as a boolean.

Example usage:

.. sourcecode:: jinja

{{ users|selectattr("is_active") }}
{{ users|selectattr("email", "none") }}

Similar to a generator comprehension such as:

(u for user in users if user.is_active)
(u for user in users if test_none(user.email))

New in version 2.7.

@pass_context
def do_selectattr( context: jinja2.runtime.Context, value: Iterable[~V], *args: Any, **kwargs: Any) -> Iterator[~V]:
1611@pass_context
1612def sync_do_selectattr(
1613    context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
1614) -> "t.Iterator[V]":
1615    """Filters a sequence of objects by applying a test to the specified
1616    attribute of each object, and only selecting the objects with the
1617    test succeeding.
1618
1619    If no test is specified, the attribute's value will be evaluated as
1620    a boolean.
1621
1622    Example usage:
1623
1624    .. sourcecode:: jinja
1625
1626        {{ users|selectattr("is_active") }}
1627        {{ users|selectattr("email", "none") }}
1628
1629    Similar to a generator comprehension such as:
1630
1631    .. code-block:: python
1632
1633        (u for user in users if user.is_active)
1634        (u for user in users if test_none(user.email))
1635
1636    .. versionadded:: 2.7
1637    """
1638    return select_or_reject(context, value, args, kwargs, lambda x: x, True)

Filters a sequence of objects by applying a test to the specified attribute of each object, and only selecting the objects with the test succeeding.

If no test is specified, the attribute's value will be evaluated as a boolean.

Example usage:

.. sourcecode:: jinja

{{ users|selectattr("is_active") }}
{{ users|selectattr("email", "none") }}

Similar to a generator comprehension such as:

(u for user in users if user.is_active)
(u for user in users if test_none(user.email))

New in version 2.7.

@pass_context
def sync_do_rejectattr( context: jinja2.runtime.Context, value: Iterable[~V], *args: Any, **kwargs: Any) -> Iterator[~V]:
1651@pass_context
1652def sync_do_rejectattr(
1653    context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
1654) -> "t.Iterator[V]":
1655    """Filters a sequence of objects by applying a test to the specified
1656    attribute of each object, and rejecting the objects with the test
1657    succeeding.
1658
1659    If no test is specified, the attribute's value will be evaluated as
1660    a boolean.
1661
1662    .. sourcecode:: jinja
1663
1664        {{ users|rejectattr("is_active") }}
1665        {{ users|rejectattr("email", "none") }}
1666
1667    Similar to a generator comprehension such as:
1668
1669    .. code-block:: python
1670
1671        (u for user in users if not user.is_active)
1672        (u for user in users if not test_none(user.email))
1673
1674    .. versionadded:: 2.7
1675    """
1676    return select_or_reject(context, value, args, kwargs, lambda x: not x, True)

Filters a sequence of objects by applying a test to the specified attribute of each object, and rejecting the objects with the test succeeding.

If no test is specified, the attribute's value will be evaluated as a boolean.

.. sourcecode:: jinja

{{ users|rejectattr("is_active") }}
{{ users|rejectattr("email", "none") }}

Similar to a generator comprehension such as:

(u for user in users if not user.is_active)
(u for user in users if not test_none(user.email))

New in version 2.7.

@pass_context
def do_rejectattr( context: jinja2.runtime.Context, value: Iterable[~V], *args: Any, **kwargs: Any) -> Iterator[~V]:
1651@pass_context
1652def sync_do_rejectattr(
1653    context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
1654) -> "t.Iterator[V]":
1655    """Filters a sequence of objects by applying a test to the specified
1656    attribute of each object, and rejecting the objects with the test
1657    succeeding.
1658
1659    If no test is specified, the attribute's value will be evaluated as
1660    a boolean.
1661
1662    .. sourcecode:: jinja
1663
1664        {{ users|rejectattr("is_active") }}
1665        {{ users|rejectattr("email", "none") }}
1666
1667    Similar to a generator comprehension such as:
1668
1669    .. code-block:: python
1670
1671        (u for user in users if not user.is_active)
1672        (u for user in users if not test_none(user.email))
1673
1674    .. versionadded:: 2.7
1675    """
1676    return select_or_reject(context, value, args, kwargs, lambda x: not x, True)

Filters a sequence of objects by applying a test to the specified attribute of each object, and rejecting the objects with the test succeeding.

If no test is specified, the attribute's value will be evaluated as a boolean.

.. sourcecode:: jinja

{{ users|rejectattr("is_active") }}
{{ users|rejectattr("email", "none") }}

Similar to a generator comprehension such as:

(u for user in users if not user.is_active)
(u for user in users if not test_none(user.email))

New in version 2.7.

@pass_eval_context
def do_tojson( eval_ctx: jinja2.nodes.EvalContext, value: Any, indent: Optional[int] = None) -> markupsafe.Markup:
1689@pass_eval_context
1690def do_tojson(
1691    eval_ctx: "EvalContext", value: t.Any, indent: t.Optional[int] = None
1692) -> Markup:
1693    """Serialize an object to a string of JSON, and mark it safe to
1694    render in HTML. This filter is only for use in HTML documents.
1695
1696    The returned string is safe to render in HTML documents and
1697    ``<script>`` tags. The exception is in HTML attributes that are
1698    double quoted; either use single quotes or the ``|forceescape``
1699    filter.
1700
1701    :param value: The object to serialize to JSON.
1702    :param indent: The ``indent`` parameter passed to ``dumps``, for
1703        pretty-printing the value.
1704
1705    .. versionadded:: 2.9
1706    """
1707    policies = eval_ctx.environment.policies
1708    dumps = policies["json.dumps_function"]
1709    kwargs = policies["json.dumps_kwargs"]
1710
1711    if indent is not None:
1712        kwargs = kwargs.copy()
1713        kwargs["indent"] = indent
1714
1715    return htmlsafe_json_dumps(value, dumps=dumps, **kwargs)

Serialize an object to a string of JSON, and mark it safe to render in HTML. This filter is only for use in HTML documents.

The returned string is safe to render in HTML documents and <script> tags. The exception is in HTML attributes that are double quoted; either use single quotes or the |forceescape filter.

Parameters
  • value: The object to serialize to JSON.
  • indent: The indent parameter passed to dumps, for pretty-printing the value.

New in version 2.9.

def prepare_map( context: jinja2.runtime.Context, args: Tuple[Any, ...], kwargs: Dict[str, Any]) -> Callable[[Any], Any]:
1718def prepare_map(
1719    context: "Context", args: t.Tuple[t.Any, ...], kwargs: t.Dict[str, t.Any]
1720) -> t.Callable[[t.Any], t.Any]:
1721    if not args and "attribute" in kwargs:
1722        attribute = kwargs.pop("attribute")
1723        default = kwargs.pop("default", None)
1724
1725        if kwargs:
1726            raise FilterArgumentError(
1727                f"Unexpected keyword argument {next(iter(kwargs))!r}"
1728            )
1729
1730        func = make_attrgetter(context.environment, attribute, default=default)
1731    else:
1732        try:
1733            name = args[0]
1734            args = args[1:]
1735        except LookupError:
1736            raise FilterArgumentError("map requires a filter argument") from None
1737
1738        def func(item: t.Any) -> t.Any:
1739            return context.environment.call_filter(
1740                name, item, args, kwargs, context=context
1741            )
1742
1743    return func
def prepare_select_or_reject( context: jinja2.runtime.Context, args: Tuple[Any, ...], kwargs: Dict[str, Any], modfunc: Callable[[Any], Any], lookup_attr: bool) -> Callable[[Any], Any]:
1746def prepare_select_or_reject(
1747    context: "Context",
1748    args: t.Tuple[t.Any, ...],
1749    kwargs: t.Dict[str, t.Any],
1750    modfunc: t.Callable[[t.Any], t.Any],
1751    lookup_attr: bool,
1752) -> t.Callable[[t.Any], t.Any]:
1753    if lookup_attr:
1754        try:
1755            attr = args[0]
1756        except LookupError:
1757            raise FilterArgumentError("Missing parameter for attribute name") from None
1758
1759        transfunc = make_attrgetter(context.environment, attr)
1760        off = 1
1761    else:
1762        off = 0
1763
1764        def transfunc(x: V) -> V:
1765            return x
1766
1767    try:
1768        name = args[off]
1769        args = args[1 + off :]
1770
1771        def func(item: t.Any) -> t.Any:
1772            return context.environment.call_test(name, item, args, kwargs)
1773
1774    except LookupError:
1775        func = bool  # type: ignore
1776
1777    return lambda item: modfunc(func(transfunc(item)))
def select_or_reject( context: jinja2.runtime.Context, value: Iterable[~V], args: Tuple[Any, ...], kwargs: Dict[str, Any], modfunc: Callable[[Any], Any], lookup_attr: bool) -> Iterator[~V]:
1780def select_or_reject(
1781    context: "Context",
1782    value: "t.Iterable[V]",
1783    args: t.Tuple[t.Any, ...],
1784    kwargs: t.Dict[str, t.Any],
1785    modfunc: t.Callable[[t.Any], t.Any],
1786    lookup_attr: bool,
1787) -> "t.Iterator[V]":
1788    if value:
1789        func = prepare_select_or_reject(context, args, kwargs, modfunc, lookup_attr)
1790
1791        for item in value:
1792            if func(item):
1793                yield item
async def async_select_or_reject( context: jinja2.runtime.Context, value: Union[AsyncIterable[~V], Iterable[~V]], args: Tuple[Any, ...], kwargs: Dict[str, Any], modfunc: Callable[[Any], Any], lookup_attr: bool) -> AsyncIterator[~V]:
1796async def async_select_or_reject(
1797    context: "Context",
1798    value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
1799    args: t.Tuple[t.Any, ...],
1800    kwargs: t.Dict[str, t.Any],
1801    modfunc: t.Callable[[t.Any], t.Any],
1802    lookup_attr: bool,
1803) -> "t.AsyncIterator[V]":
1804    if value:
1805        func = prepare_select_or_reject(context, args, kwargs, modfunc, lookup_attr)
1806
1807        async for item in auto_aiter(value):
1808            if func(item):
1809                yield item
FILTERS = {'abs': <built-in function abs>, 'attr': <function do_attr>, 'batch': <function do_batch>, 'capitalize': <function do_capitalize>, 'center': <function do_center>, 'count': <built-in function len>, 'd': <function do_default>, 'default': <function do_default>, 'dictsort': <function do_dictsort>, 'e': <built-in function escape>, 'escape': <built-in function escape>, 'filesizeformat': <function do_filesizeformat>, 'first': <function do_first>, 'float': <function do_float>, 'forceescape': <function do_forceescape>, 'format': <function do_format>, 'groupby': <function do_groupby>, 'indent': <function do_indent>, 'int': <function do_int>, 'join': <function do_join>, 'last': <function do_last>, 'length': <built-in function len>, 'list': <function do_list>, 'lower': <function do_lower>, 'items': <function do_items>, 'map': <function do_map>, 'min': <function do_min>, 'max': <function do_max>, 'pprint': <function do_pprint>, 'random': <function do_random>, 'reject': <function do_reject>, 'rejectattr': <function do_rejectattr>, 'replace': <function do_replace>, 'reverse': <function do_reverse>, 'round': <function do_round>, 'safe': <function do_mark_safe>, 'select': <function do_select>, 'selectattr': <function do_selectattr>, 'slice': <function do_slice>, 'sort': <function do_sort>, 'string': <built-in function soft_str>, 'striptags': <function do_striptags>, 'sum': <function do_sum>, 'title': <function do_title>, 'trim': <function do_trim>, 'truncate': <function do_truncate>, 'unique': <function do_unique>, 'upper': <function do_upper>, 'urlencode': <function do_urlencode>, 'urlize': <function do_urlize>, 'wordcount': <function do_wordcount>, 'wordwrap': <function do_wordwrap>, 'xmlattr': <function do_xmlattr>, 'tojson': <function do_tojson>}