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 sync_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
 473@async_variant(sync_do_unique)  # type: ignore
 474async def do_unique(
 475    environment: "Environment",
 476    value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
 477    case_sensitive: bool = False,
 478    attribute: t.Optional[t.Union[str, int]] = None,
 479) -> "t.Iterator[V]":
 480    return sync_do_unique(
 481        environment, await auto_to_list(value), case_sensitive, attribute
 482    )
 483
 484
 485def _min_or_max(
 486    environment: "Environment",
 487    value: "t.Iterable[V]",
 488    func: "t.Callable[..., V]",
 489    case_sensitive: bool,
 490    attribute: t.Optional[t.Union[str, int]],
 491) -> "t.Union[V, Undefined]":
 492    it = iter(value)
 493
 494    try:
 495        first = next(it)
 496    except StopIteration:
 497        return environment.undefined("No aggregated item, sequence was empty.")
 498
 499    key_func = make_attrgetter(
 500        environment, attribute, postprocess=ignore_case if not case_sensitive else None
 501    )
 502    return func(chain([first], it), key=key_func)
 503
 504
 505@pass_environment
 506def do_min(
 507    environment: "Environment",
 508    value: "t.Iterable[V]",
 509    case_sensitive: bool = False,
 510    attribute: t.Optional[t.Union[str, int]] = None,
 511) -> "t.Union[V, Undefined]":
 512    """Return the smallest item from the sequence.
 513
 514    .. sourcecode:: jinja
 515
 516        {{ [1, 2, 3]|min }}
 517            -> 1
 518
 519    :param case_sensitive: Treat upper and lower case strings as distinct.
 520    :param attribute: Get the object with the min value of this attribute.
 521    """
 522    return _min_or_max(environment, value, min, case_sensitive, attribute)
 523
 524
 525@pass_environment
 526def do_max(
 527    environment: "Environment",
 528    value: "t.Iterable[V]",
 529    case_sensitive: bool = False,
 530    attribute: t.Optional[t.Union[str, int]] = None,
 531) -> "t.Union[V, Undefined]":
 532    """Return the largest item from the sequence.
 533
 534    .. sourcecode:: jinja
 535
 536        {{ [1, 2, 3]|max }}
 537            -> 3
 538
 539    :param case_sensitive: Treat upper and lower case strings as distinct.
 540    :param attribute: Get the object with the max value of this attribute.
 541    """
 542    return _min_or_max(environment, value, max, case_sensitive, attribute)
 543
 544
 545def do_default(
 546    value: V,
 547    default_value: V = "",  # type: ignore
 548    boolean: bool = False,
 549) -> V:
 550    """If the value is undefined it will return the passed default value,
 551    otherwise the value of the variable:
 552
 553    .. sourcecode:: jinja
 554
 555        {{ my_variable|default('my_variable is not defined') }}
 556
 557    This will output the value of ``my_variable`` if the variable was
 558    defined, otherwise ``'my_variable is not defined'``. If you want
 559    to use default with variables that evaluate to false you have to
 560    set the second parameter to `true`:
 561
 562    .. sourcecode:: jinja
 563
 564        {{ ''|default('the string was empty', true) }}
 565
 566    .. versionchanged:: 2.11
 567       It's now possible to configure the :class:`~jinja2.Environment` with
 568       :class:`~jinja2.ChainableUndefined` to make the `default` filter work
 569       on nested elements and attributes that may contain undefined values
 570       in the chain without getting an :exc:`~jinja2.UndefinedError`.
 571    """
 572    if isinstance(value, Undefined) or (boolean and not value):
 573        return default_value
 574
 575    return value
 576
 577
 578@pass_eval_context
 579def sync_do_join(
 580    eval_ctx: "EvalContext",
 581    value: t.Iterable[t.Any],
 582    d: str = "",
 583    attribute: t.Optional[t.Union[str, int]] = None,
 584) -> str:
 585    """Return a string which is the concatenation of the strings in the
 586    sequence. The separator between elements is an empty string per
 587    default, you can define it with the optional parameter:
 588
 589    .. sourcecode:: jinja
 590
 591        {{ [1, 2, 3]|join('|') }}
 592            -> 1|2|3
 593
 594        {{ [1, 2, 3]|join }}
 595            -> 123
 596
 597    It is also possible to join certain attributes of an object:
 598
 599    .. sourcecode:: jinja
 600
 601        {{ users|join(', ', attribute='username') }}
 602
 603    .. versionadded:: 2.6
 604       The `attribute` parameter was added.
 605    """
 606    if attribute is not None:
 607        value = map(make_attrgetter(eval_ctx.environment, attribute), value)
 608
 609    # no automatic escaping?  joining is a lot easier then
 610    if not eval_ctx.autoescape:
 611        return str(d).join(map(str, value))
 612
 613    # if the delimiter doesn't have an html representation we check
 614    # if any of the items has.  If yes we do a coercion to Markup
 615    if not hasattr(d, "__html__"):
 616        value = list(value)
 617        do_escape = False
 618
 619        for idx, item in enumerate(value):
 620            if hasattr(item, "__html__"):
 621                do_escape = True
 622            else:
 623                value[idx] = str(item)
 624
 625        if do_escape:
 626            d = escape(d)
 627        else:
 628            d = str(d)
 629
 630        return d.join(value)
 631
 632    # no html involved, to normal joining
 633    return soft_str(d).join(map(soft_str, value))
 634
 635
 636@async_variant(sync_do_join)  # type: ignore
 637async def do_join(
 638    eval_ctx: "EvalContext",
 639    value: t.Union[t.AsyncIterable[t.Any], t.Iterable[t.Any]],
 640    d: str = "",
 641    attribute: t.Optional[t.Union[str, int]] = None,
 642) -> str:
 643    return sync_do_join(eval_ctx, await auto_to_list(value), d, attribute)
 644
 645
 646def do_center(value: str, width: int = 80) -> str:
 647    """Centers the value in a field of a given width."""
 648    return soft_str(value).center(width)
 649
 650
 651@pass_environment
 652def sync_do_first(
 653    environment: "Environment", seq: "t.Iterable[V]"
 654) -> "t.Union[V, Undefined]":
 655    """Return the first item of a sequence."""
 656    try:
 657        return next(iter(seq))
 658    except StopIteration:
 659        return environment.undefined("No first item, sequence was empty.")
 660
 661
 662@async_variant(sync_do_first)  # type: ignore
 663async def do_first(
 664    environment: "Environment", seq: "t.Union[t.AsyncIterable[V], t.Iterable[V]]"
 665) -> "t.Union[V, Undefined]":
 666    try:
 667        return await auto_aiter(seq).__anext__()
 668    except StopAsyncIteration:
 669        return environment.undefined("No first item, sequence was empty.")
 670
 671
 672@pass_environment
 673def do_last(
 674    environment: "Environment", seq: "t.Reversible[V]"
 675) -> "t.Union[V, Undefined]":
 676    """Return the last item of a sequence.
 677
 678    Note: Does not work with generators. You may want to explicitly
 679    convert it to a list:
 680
 681    .. sourcecode:: jinja
 682
 683        {{ data | selectattr('name', '==', 'Jinja') | list | last }}
 684    """
 685    try:
 686        return next(iter(reversed(seq)))
 687    except StopIteration:
 688        return environment.undefined("No last item, sequence was empty.")
 689
 690
 691# No async do_last, it may not be safe in async mode.
 692
 693
 694@pass_context
 695def do_random(context: "Context", seq: "t.Sequence[V]") -> "t.Union[V, Undefined]":
 696    """Return a random item from the sequence."""
 697    try:
 698        return random.choice(seq)
 699    except IndexError:
 700        return context.environment.undefined("No random item, sequence was empty.")
 701
 702
 703def do_filesizeformat(value: t.Union[str, float, int], binary: bool = False) -> str:
 704    """Format the value like a 'human-readable' file size (i.e. 13 kB,
 705    4.1 MB, 102 Bytes, etc).  Per default decimal prefixes are used (Mega,
 706    Giga, etc.), if the second parameter is set to `True` the binary
 707    prefixes are used (Mebi, Gibi).
 708    """
 709    bytes = float(value)
 710    base = 1024 if binary else 1000
 711    prefixes = [
 712        ("KiB" if binary else "kB"),
 713        ("MiB" if binary else "MB"),
 714        ("GiB" if binary else "GB"),
 715        ("TiB" if binary else "TB"),
 716        ("PiB" if binary else "PB"),
 717        ("EiB" if binary else "EB"),
 718        ("ZiB" if binary else "ZB"),
 719        ("YiB" if binary else "YB"),
 720    ]
 721
 722    if bytes == 1:
 723        return "1 Byte"
 724    elif bytes < base:
 725        return f"{int(bytes)} Bytes"
 726    else:
 727        for i, prefix in enumerate(prefixes):
 728            unit = base ** (i + 2)
 729
 730            if bytes < unit:
 731                return f"{base * bytes / unit:.1f} {prefix}"
 732
 733        return f"{base * bytes / unit:.1f} {prefix}"
 734
 735
 736def do_pprint(value: t.Any) -> str:
 737    """Pretty print a variable. Useful for debugging."""
 738    return pformat(value)
 739
 740
 741_uri_scheme_re = re.compile(r"^([\w.+-]{2,}:(/){0,2})$")
 742
 743
 744@pass_eval_context
 745def do_urlize(
 746    eval_ctx: "EvalContext",
 747    value: str,
 748    trim_url_limit: t.Optional[int] = None,
 749    nofollow: bool = False,
 750    target: t.Optional[str] = None,
 751    rel: t.Optional[str] = None,
 752    extra_schemes: t.Optional[t.Iterable[str]] = None,
 753) -> str:
 754    """Convert URLs in text into clickable links.
 755
 756    This may not recognize links in some situations. Usually, a more
 757    comprehensive formatter, such as a Markdown library, is a better
 758    choice.
 759
 760    Works on ``http://``, ``https://``, ``www.``, ``mailto:``, and email
 761    addresses. Links with trailing punctuation (periods, commas, closing
 762    parentheses) and leading punctuation (opening parentheses) are
 763    recognized excluding the punctuation. Email addresses that include
 764    header fields are not recognized (for example,
 765    ``mailto:address@example.com?cc=copy@example.com``).
 766
 767    :param value: Original text containing URLs to link.
 768    :param trim_url_limit: Shorten displayed URL values to this length.
 769    :param nofollow: Add the ``rel=nofollow`` attribute to links.
 770    :param target: Add the ``target`` attribute to links.
 771    :param rel: Add the ``rel`` attribute to links.
 772    :param extra_schemes: Recognize URLs that start with these schemes
 773        in addition to the default behavior. Defaults to
 774        ``env.policies["urlize.extra_schemes"]``, which defaults to no
 775        extra schemes.
 776
 777    .. versionchanged:: 3.0
 778        The ``extra_schemes`` parameter was added.
 779
 780    .. versionchanged:: 3.0
 781        Generate ``https://`` links for URLs without a scheme.
 782
 783    .. versionchanged:: 3.0
 784        The parsing rules were updated. Recognize email addresses with
 785        or without the ``mailto:`` scheme. Validate IP addresses. Ignore
 786        parentheses and brackets in more cases.
 787
 788    .. versionchanged:: 2.8
 789       The ``target`` parameter was added.
 790    """
 791    policies = eval_ctx.environment.policies
 792    rel_parts = set((rel or "").split())
 793
 794    if nofollow:
 795        rel_parts.add("nofollow")
 796
 797    rel_parts.update((policies["urlize.rel"] or "").split())
 798    rel = " ".join(sorted(rel_parts)) or None
 799
 800    if target is None:
 801        target = policies["urlize.target"]
 802
 803    if extra_schemes is None:
 804        extra_schemes = policies["urlize.extra_schemes"] or ()
 805
 806    for scheme in extra_schemes:
 807        if _uri_scheme_re.fullmatch(scheme) is None:
 808            raise FilterArgumentError(f"{scheme!r} is not a valid URI scheme prefix.")
 809
 810    rv = urlize(
 811        value,
 812        trim_url_limit=trim_url_limit,
 813        rel=rel,
 814        target=target,
 815        extra_schemes=extra_schemes,
 816    )
 817
 818    if eval_ctx.autoescape:
 819        rv = Markup(rv)
 820
 821    return rv
 822
 823
 824def do_indent(
 825    s: str, width: t.Union[int, str] = 4, first: bool = False, blank: bool = False
 826) -> str:
 827    """Return a copy of the string with each line indented by 4 spaces. The
 828    first line and blank lines are not indented by default.
 829
 830    :param width: Number of spaces, or a string, to indent by.
 831    :param first: Don't skip indenting the first line.
 832    :param blank: Don't skip indenting empty lines.
 833
 834    .. versionchanged:: 3.0
 835        ``width`` can be a string.
 836
 837    .. versionchanged:: 2.10
 838        Blank lines are not indented by default.
 839
 840        Rename the ``indentfirst`` argument to ``first``.
 841    """
 842    if isinstance(width, str):
 843        indention = width
 844    else:
 845        indention = " " * width
 846
 847    newline = "\n"
 848
 849    if isinstance(s, Markup):
 850        indention = Markup(indention)
 851        newline = Markup(newline)
 852
 853    s += newline  # this quirk is necessary for splitlines method
 854
 855    if blank:
 856        rv = (newline + indention).join(s.splitlines())
 857    else:
 858        lines = s.splitlines()
 859        rv = lines.pop(0)
 860
 861        if lines:
 862            rv += newline + newline.join(
 863                indention + line if line else line for line in lines
 864            )
 865
 866    if first:
 867        rv = indention + rv
 868
 869    return rv
 870
 871
 872@pass_environment
 873def do_truncate(
 874    env: "Environment",
 875    s: str,
 876    length: int = 255,
 877    killwords: bool = False,
 878    end: str = "...",
 879    leeway: t.Optional[int] = None,
 880) -> str:
 881    """Return a truncated copy of the string. The length is specified
 882    with the first parameter which defaults to ``255``. If the second
 883    parameter is ``true`` the filter will cut the text at length. Otherwise
 884    it will discard the last word. If the text was in fact
 885    truncated it will append an ellipsis sign (``"..."``). If you want a
 886    different ellipsis sign than ``"..."`` you can specify it using the
 887    third parameter. Strings that only exceed the length by the tolerance
 888    margin given in the fourth parameter will not be truncated.
 889
 890    .. sourcecode:: jinja
 891
 892        {{ "foo bar baz qux"|truncate(9) }}
 893            -> "foo..."
 894        {{ "foo bar baz qux"|truncate(9, True) }}
 895            -> "foo ba..."
 896        {{ "foo bar baz qux"|truncate(11) }}
 897            -> "foo bar baz qux"
 898        {{ "foo bar baz qux"|truncate(11, False, '...', 0) }}
 899            -> "foo bar..."
 900
 901    The default leeway on newer Jinja versions is 5 and was 0 before but
 902    can be reconfigured globally.
 903    """
 904    if leeway is None:
 905        leeway = env.policies["truncate.leeway"]
 906
 907    assert length >= len(end), f"expected length >= {len(end)}, got {length}"
 908    assert leeway >= 0, f"expected leeway >= 0, got {leeway}"
 909
 910    if len(s) <= length + leeway:
 911        return s
 912
 913    if killwords:
 914        return s[: length - len(end)] + end
 915
 916    result = s[: length - len(end)].rsplit(" ", 1)[0]
 917    return result + end
 918
 919
 920@pass_environment
 921def do_wordwrap(
 922    environment: "Environment",
 923    s: str,
 924    width: int = 79,
 925    break_long_words: bool = True,
 926    wrapstring: t.Optional[str] = None,
 927    break_on_hyphens: bool = True,
 928) -> str:
 929    """Wrap a string to the given width. Existing newlines are treated
 930    as paragraphs to be wrapped separately.
 931
 932    :param s: Original text to wrap.
 933    :param width: Maximum length of wrapped lines.
 934    :param break_long_words: If a word is longer than ``width``, break
 935        it across lines.
 936    :param break_on_hyphens: If a word contains hyphens, it may be split
 937        across lines.
 938    :param wrapstring: String to join each wrapped line. Defaults to
 939        :attr:`Environment.newline_sequence`.
 940
 941    .. versionchanged:: 2.11
 942        Existing newlines are treated as paragraphs wrapped separately.
 943
 944    .. versionchanged:: 2.11
 945        Added the ``break_on_hyphens`` parameter.
 946
 947    .. versionchanged:: 2.7
 948        Added the ``wrapstring`` parameter.
 949    """
 950    import textwrap
 951
 952    if wrapstring is None:
 953        wrapstring = environment.newline_sequence
 954
 955    # textwrap.wrap doesn't consider existing newlines when wrapping.
 956    # If the string has a newline before width, wrap will still insert
 957    # a newline at width, resulting in a short line. Instead, split and
 958    # wrap each paragraph individually.
 959    return wrapstring.join(
 960        [
 961            wrapstring.join(
 962                textwrap.wrap(
 963                    line,
 964                    width=width,
 965                    expand_tabs=False,
 966                    replace_whitespace=False,
 967                    break_long_words=break_long_words,
 968                    break_on_hyphens=break_on_hyphens,
 969                )
 970            )
 971            for line in s.splitlines()
 972        ]
 973    )
 974
 975
 976_word_re = re.compile(r"\w+")
 977
 978
 979def do_wordcount(s: str) -> int:
 980    """Count the words in that string."""
 981    return len(_word_re.findall(soft_str(s)))
 982
 983
 984def do_int(value: t.Any, default: int = 0, base: int = 10) -> int:
 985    """Convert the value into an integer. If the
 986    conversion doesn't work it will return ``0``. You can
 987    override this default using the first parameter. You
 988    can also override the default base (10) in the second
 989    parameter, which handles input with prefixes such as
 990    0b, 0o and 0x for bases 2, 8 and 16 respectively.
 991    The base is ignored for decimal numbers and non-string values.
 992    """
 993    try:
 994        if isinstance(value, str):
 995            return int(value, base)
 996
 997        return int(value)
 998    except (TypeError, ValueError):
 999        # this quirk is necessary so that "42.23"|int gives 42.
1000        try:
1001            return int(float(value))
1002        except (TypeError, ValueError, OverflowError):
1003            return default
1004
1005
1006def do_float(value: t.Any, default: float = 0.0) -> float:
1007    """Convert the value into a floating point number. If the
1008    conversion doesn't work it will return ``0.0``. You can
1009    override this default using the first parameter.
1010    """
1011    try:
1012        return float(value)
1013    except (TypeError, ValueError):
1014        return default
1015
1016
1017def do_format(value: str, *args: t.Any, **kwargs: t.Any) -> str:
1018    """Apply the given values to a `printf-style`_ format string, like
1019    ``string % values``.
1020
1021    .. sourcecode:: jinja
1022
1023        {{ "%s, %s!"|format(greeting, name) }}
1024        Hello, World!
1025
1026    In most cases it should be more convenient and efficient to use the
1027    ``%`` operator or :meth:`str.format`.
1028
1029    .. code-block:: text
1030
1031        {{ "%s, %s!" % (greeting, name) }}
1032        {{ "{}, {}!".format(greeting, name) }}
1033
1034    .. _printf-style: https://docs.python.org/library/stdtypes.html
1035        #printf-style-string-formatting
1036    """
1037    if args and kwargs:
1038        raise FilterArgumentError(
1039            "can't handle positional and keyword arguments at the same time"
1040        )
1041
1042    return soft_str(value) % (kwargs or args)
1043
1044
1045def do_trim(value: str, chars: t.Optional[str] = None) -> str:
1046    """Strip leading and trailing characters, by default whitespace."""
1047    return soft_str(value).strip(chars)
1048
1049
1050def do_striptags(value: "t.Union[str, HasHTML]") -> str:
1051    """Strip SGML/XML tags and replace adjacent whitespace by one space."""
1052    if hasattr(value, "__html__"):
1053        value = t.cast("HasHTML", value).__html__()
1054
1055    return Markup(str(value)).striptags()
1056
1057
1058def sync_do_slice(
1059    value: "t.Collection[V]", slices: int, fill_with: "t.Optional[V]" = None
1060) -> "t.Iterator[t.List[V]]":
1061    """Slice an iterator and return a list of lists containing
1062    those items. Useful if you want to create a div containing
1063    three ul tags that represent columns:
1064
1065    .. sourcecode:: html+jinja
1066
1067        <div class="columnwrapper">
1068          {%- for column in items|slice(3) %}
1069            <ul class="column-{{ loop.index }}">
1070            {%- for item in column %}
1071              <li>{{ item }}</li>
1072            {%- endfor %}
1073            </ul>
1074          {%- endfor %}
1075        </div>
1076
1077    If you pass it a second argument it's used to fill missing
1078    values on the last iteration.
1079    """
1080    seq = list(value)
1081    length = len(seq)
1082    items_per_slice = length // slices
1083    slices_with_extra = length % slices
1084    offset = 0
1085
1086    for slice_number in range(slices):
1087        start = offset + slice_number * items_per_slice
1088
1089        if slice_number < slices_with_extra:
1090            offset += 1
1091
1092        end = offset + (slice_number + 1) * items_per_slice
1093        tmp = seq[start:end]
1094
1095        if fill_with is not None and slice_number >= slices_with_extra:
1096            tmp.append(fill_with)
1097
1098        yield tmp
1099
1100
1101@async_variant(sync_do_slice)  # type: ignore
1102async def do_slice(
1103    value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
1104    slices: int,
1105    fill_with: t.Optional[t.Any] = None,
1106) -> "t.Iterator[t.List[V]]":
1107    return sync_do_slice(await auto_to_list(value), slices, fill_with)
1108
1109
1110def do_batch(
1111    value: "t.Iterable[V]", linecount: int, fill_with: "t.Optional[V]" = None
1112) -> "t.Iterator[t.List[V]]":
1113    """
1114    A filter that batches items. It works pretty much like `slice`
1115    just the other way round. It returns a list of lists with the
1116    given number of items. If you provide a second parameter this
1117    is used to fill up missing items. See this example:
1118
1119    .. sourcecode:: html+jinja
1120
1121        <table>
1122        {%- for row in items|batch(3, '&nbsp;') %}
1123          <tr>
1124          {%- for column in row %}
1125            <td>{{ column }}</td>
1126          {%- endfor %}
1127          </tr>
1128        {%- endfor %}
1129        </table>
1130    """
1131    tmp: t.List[V] = []
1132
1133    for item in value:
1134        if len(tmp) == linecount:
1135            yield tmp
1136            tmp = []
1137
1138        tmp.append(item)
1139
1140    if tmp:
1141        if fill_with is not None and len(tmp) < linecount:
1142            tmp += [fill_with] * (linecount - len(tmp))
1143
1144        yield tmp
1145
1146
1147def do_round(
1148    value: float,
1149    precision: int = 0,
1150    method: 'te.Literal["common", "ceil", "floor"]' = "common",
1151) -> float:
1152    """Round the number to a given precision. The first
1153    parameter specifies the precision (default is ``0``), the
1154    second the rounding method:
1155
1156    - ``'common'`` rounds either up or down
1157    - ``'ceil'`` always rounds up
1158    - ``'floor'`` always rounds down
1159
1160    If you don't specify a method ``'common'`` is used.
1161
1162    .. sourcecode:: jinja
1163
1164        {{ 42.55|round }}
1165            -> 43.0
1166        {{ 42.55|round(1, 'floor') }}
1167            -> 42.5
1168
1169    Note that even if rounded to 0 precision, a float is returned.  If
1170    you need a real integer, pipe it through `int`:
1171
1172    .. sourcecode:: jinja
1173
1174        {{ 42.55|round|int }}
1175            -> 43
1176    """
1177    if method not in {"common", "ceil", "floor"}:
1178        raise FilterArgumentError("method must be common, ceil or floor")
1179
1180    if method == "common":
1181        return round(value, precision)
1182
1183    func = getattr(math, method)
1184    return t.cast(float, func(value * (10**precision)) / (10**precision))
1185
1186
1187class _GroupTuple(t.NamedTuple):
1188    grouper: t.Any
1189    list: t.List[t.Any]
1190
1191    # Use the regular tuple repr to hide this subclass if users print
1192    # out the value during debugging.
1193    def __repr__(self) -> str:
1194        return tuple.__repr__(self)
1195
1196    def __str__(self) -> str:
1197        return tuple.__str__(self)
1198
1199
1200@pass_environment
1201def sync_do_groupby(
1202    environment: "Environment",
1203    value: "t.Iterable[V]",
1204    attribute: t.Union[str, int],
1205    default: t.Optional[t.Any] = None,
1206    case_sensitive: bool = False,
1207) -> "t.List[_GroupTuple]":
1208    """Group a sequence of objects by an attribute using Python's
1209    :func:`itertools.groupby`. The attribute can use dot notation for
1210    nested access, like ``"address.city"``. Unlike Python's ``groupby``,
1211    the values are sorted first so only one group is returned for each
1212    unique value.
1213
1214    For example, a list of ``User`` objects with a ``city`` attribute
1215    can be rendered in groups. In this example, ``grouper`` refers to
1216    the ``city`` value of the group.
1217
1218    .. sourcecode:: html+jinja
1219
1220        <ul>{% for city, items in users|groupby("city") %}
1221          <li>{{ city }}
1222            <ul>{% for user in items %}
1223              <li>{{ user.name }}
1224            {% endfor %}</ul>
1225          </li>
1226        {% endfor %}</ul>
1227
1228    ``groupby`` yields namedtuples of ``(grouper, list)``, which
1229    can be used instead of the tuple unpacking above. ``grouper`` is the
1230    value of the attribute, and ``list`` is the items with that value.
1231
1232    .. sourcecode:: html+jinja
1233
1234        <ul>{% for group in users|groupby("city") %}
1235          <li>{{ group.grouper }}: {{ group.list|join(", ") }}
1236        {% endfor %}</ul>
1237
1238    You can specify a ``default`` value to use if an object in the list
1239    does not have the given attribute.
1240
1241    .. sourcecode:: jinja
1242
1243        <ul>{% for city, items in users|groupby("city", default="NY") %}
1244          <li>{{ city }}: {{ items|map(attribute="name")|join(", ") }}</li>
1245        {% endfor %}</ul>
1246
1247    Like the :func:`~jinja-filters.sort` filter, sorting and grouping is
1248    case-insensitive by default. The ``key`` for each group will have
1249    the case of the first item in that group of values. For example, if
1250    a list of users has cities ``["CA", "NY", "ca"]``, the "CA" group
1251    will have two values. This can be disabled by passing
1252    ``case_sensitive=True``.
1253
1254    .. versionchanged:: 3.1
1255        Added the ``case_sensitive`` parameter. Sorting and grouping is
1256        case-insensitive by default, matching other filters that do
1257        comparisons.
1258
1259    .. versionchanged:: 3.0
1260        Added the ``default`` parameter.
1261
1262    .. versionchanged:: 2.6
1263        The attribute supports dot notation for nested access.
1264    """
1265    expr = make_attrgetter(
1266        environment,
1267        attribute,
1268        postprocess=ignore_case if not case_sensitive else None,
1269        default=default,
1270    )
1271    out = [
1272        _GroupTuple(key, list(values))
1273        for key, values in groupby(sorted(value, key=expr), expr)
1274    ]
1275
1276    if not case_sensitive:
1277        # Return the real key from the first value instead of the lowercase key.
1278        output_expr = make_attrgetter(environment, attribute, default=default)
1279        out = [_GroupTuple(output_expr(values[0]), values) for _, values in out]
1280
1281    return out
1282
1283
1284@async_variant(sync_do_groupby)  # type: ignore
1285async def do_groupby(
1286    environment: "Environment",
1287    value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
1288    attribute: t.Union[str, int],
1289    default: t.Optional[t.Any] = None,
1290    case_sensitive: bool = False,
1291) -> "t.List[_GroupTuple]":
1292    expr = make_attrgetter(
1293        environment,
1294        attribute,
1295        postprocess=ignore_case if not case_sensitive else None,
1296        default=default,
1297    )
1298    out = [
1299        _GroupTuple(key, await auto_to_list(values))
1300        for key, values in groupby(sorted(await auto_to_list(value), key=expr), expr)
1301    ]
1302
1303    if not case_sensitive:
1304        # Return the real key from the first value instead of the lowercase key.
1305        output_expr = make_attrgetter(environment, attribute, default=default)
1306        out = [_GroupTuple(output_expr(values[0]), values) for _, values in out]
1307
1308    return out
1309
1310
1311@pass_environment
1312def sync_do_sum(
1313    environment: "Environment",
1314    iterable: "t.Iterable[V]",
1315    attribute: t.Optional[t.Union[str, int]] = None,
1316    start: V = 0,  # type: ignore
1317) -> V:
1318    """Returns the sum of a sequence of numbers plus the value of parameter
1319    'start' (which defaults to 0).  When the sequence is empty it returns
1320    start.
1321
1322    It is also possible to sum up only certain attributes:
1323
1324    .. sourcecode:: jinja
1325
1326        Total: {{ items|sum(attribute='price') }}
1327
1328    .. versionchanged:: 2.6
1329       The ``attribute`` parameter was added to allow summing up over
1330       attributes.  Also the ``start`` parameter was moved on to the right.
1331    """
1332    if attribute is not None:
1333        iterable = map(make_attrgetter(environment, attribute), iterable)
1334
1335    return sum(iterable, start)  # type: ignore[no-any-return, call-overload]
1336
1337
1338@async_variant(sync_do_sum)  # type: ignore
1339async def do_sum(
1340    environment: "Environment",
1341    iterable: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
1342    attribute: t.Optional[t.Union[str, int]] = None,
1343    start: V = 0,  # type: ignore
1344) -> V:
1345    rv = start
1346
1347    if attribute is not None:
1348        func = make_attrgetter(environment, attribute)
1349    else:
1350
1351        def func(x: V) -> V:
1352            return x
1353
1354    async for item in auto_aiter(iterable):
1355        rv += func(item)
1356
1357    return rv
1358
1359
1360def sync_do_list(value: "t.Iterable[V]") -> "t.List[V]":
1361    """Convert the value into a list.  If it was a string the returned list
1362    will be a list of characters.
1363    """
1364    return list(value)
1365
1366
1367@async_variant(sync_do_list)  # type: ignore
1368async def do_list(value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]") -> "t.List[V]":
1369    return await auto_to_list(value)
1370
1371
1372def do_mark_safe(value: str) -> Markup:
1373    """Mark the value as safe which means that in an environment with automatic
1374    escaping enabled this variable will not be escaped.
1375    """
1376    return Markup(value)
1377
1378
1379def do_mark_unsafe(value: str) -> str:
1380    """Mark a value as unsafe.  This is the reverse operation for :func:`safe`."""
1381    return str(value)
1382
1383
1384@typing.overload
1385def do_reverse(value: str) -> str: ...
1386
1387
1388@typing.overload
1389def do_reverse(value: "t.Iterable[V]") -> "t.Iterable[V]": ...
1390
1391
1392def do_reverse(value: t.Union[str, t.Iterable[V]]) -> t.Union[str, t.Iterable[V]]:
1393    """Reverse the object or return an iterator that iterates over it the other
1394    way round.
1395    """
1396    if isinstance(value, str):
1397        return value[::-1]
1398
1399    try:
1400        return reversed(value)  # type: ignore
1401    except TypeError:
1402        try:
1403            rv = list(value)
1404            rv.reverse()
1405            return rv
1406        except TypeError as e:
1407            raise FilterArgumentError("argument must be iterable") from e
1408
1409
1410@pass_environment
1411def do_attr(
1412    environment: "Environment", obj: t.Any, name: str
1413) -> t.Union[Undefined, t.Any]:
1414    """Get an attribute of an object.  ``foo|attr("bar")`` works like
1415    ``foo.bar`` just that always an attribute is returned and items are not
1416    looked up.
1417
1418    See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details.
1419    """
1420    try:
1421        name = str(name)
1422    except UnicodeError:
1423        pass
1424    else:
1425        try:
1426            value = getattr(obj, name)
1427        except AttributeError:
1428            pass
1429        else:
1430            if environment.sandboxed:
1431                environment = t.cast("SandboxedEnvironment", environment)
1432
1433                if not environment.is_safe_attribute(obj, name, value):
1434                    return environment.unsafe_undefined(obj, name)
1435
1436            return value
1437
1438    return environment.undefined(obj=obj, name=name)
1439
1440
1441@typing.overload
1442def sync_do_map(
1443    context: "Context",
1444    value: t.Iterable[t.Any],
1445    name: str,
1446    *args: t.Any,
1447    **kwargs: t.Any,
1448) -> t.Iterable[t.Any]: ...
1449
1450
1451@typing.overload
1452def sync_do_map(
1453    context: "Context",
1454    value: t.Iterable[t.Any],
1455    *,
1456    attribute: str = ...,
1457    default: t.Optional[t.Any] = None,
1458) -> t.Iterable[t.Any]: ...
1459
1460
1461@pass_context
1462def sync_do_map(
1463    context: "Context", value: t.Iterable[t.Any], *args: t.Any, **kwargs: t.Any
1464) -> t.Iterable[t.Any]:
1465    """Applies a filter on a sequence of objects or looks up an attribute.
1466    This is useful when dealing with lists of objects but you are really
1467    only interested in a certain value of it.
1468
1469    The basic usage is mapping on an attribute.  Imagine you have a list
1470    of users but you are only interested in a list of usernames:
1471
1472    .. sourcecode:: jinja
1473
1474        Users on this page: {{ users|map(attribute='username')|join(', ') }}
1475
1476    You can specify a ``default`` value to use if an object in the list
1477    does not have the given attribute.
1478
1479    .. sourcecode:: jinja
1480
1481        {{ users|map(attribute="username", default="Anonymous")|join(", ") }}
1482
1483    Alternatively you can let it invoke a filter by passing the name of the
1484    filter and the arguments afterwards.  A good example would be applying a
1485    text conversion filter on a sequence:
1486
1487    .. sourcecode:: jinja
1488
1489        Users on this page: {{ titles|map('lower')|join(', ') }}
1490
1491    Similar to a generator comprehension such as:
1492
1493    .. code-block:: python
1494
1495        (u.username for u in users)
1496        (getattr(u, "username", "Anonymous") for u in users)
1497        (do_lower(x) for x in titles)
1498
1499    .. versionchanged:: 2.11.0
1500        Added the ``default`` parameter.
1501
1502    .. versionadded:: 2.7
1503    """
1504    if value:
1505        func = prepare_map(context, args, kwargs)
1506
1507        for item in value:
1508            yield func(item)
1509
1510
1511@typing.overload
1512def do_map(
1513    context: "Context",
1514    value: t.Union[t.AsyncIterable[t.Any], t.Iterable[t.Any]],
1515    name: str,
1516    *args: t.Any,
1517    **kwargs: t.Any,
1518) -> t.Iterable[t.Any]: ...
1519
1520
1521@typing.overload
1522def do_map(
1523    context: "Context",
1524    value: t.Union[t.AsyncIterable[t.Any], t.Iterable[t.Any]],
1525    *,
1526    attribute: str = ...,
1527    default: t.Optional[t.Any] = None,
1528) -> t.Iterable[t.Any]: ...
1529
1530
1531@async_variant(sync_do_map)  # type: ignore
1532async def do_map(
1533    context: "Context",
1534    value: t.Union[t.AsyncIterable[t.Any], t.Iterable[t.Any]],
1535    *args: t.Any,
1536    **kwargs: t.Any,
1537) -> t.AsyncIterable[t.Any]:
1538    if value:
1539        func = prepare_map(context, args, kwargs)
1540
1541        async for item in auto_aiter(value):
1542            yield await auto_await(func(item))
1543
1544
1545@pass_context
1546def sync_do_select(
1547    context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
1548) -> "t.Iterator[V]":
1549    """Filters a sequence of objects by applying a test to each object,
1550    and only selecting the objects with the test succeeding.
1551
1552    If no test is specified, each object will be evaluated as a boolean.
1553
1554    Example usage:
1555
1556    .. sourcecode:: jinja
1557
1558        {{ numbers|select("odd") }}
1559        {{ numbers|select("odd") }}
1560        {{ numbers|select("divisibleby", 3) }}
1561        {{ numbers|select("lessthan", 42) }}
1562        {{ strings|select("equalto", "mystring") }}
1563
1564    Similar to a generator comprehension such as:
1565
1566    .. code-block:: python
1567
1568        (n for n in numbers if test_odd(n))
1569        (n for n in numbers if test_divisibleby(n, 3))
1570
1571    .. versionadded:: 2.7
1572    """
1573    return select_or_reject(context, value, args, kwargs, lambda x: x, False)
1574
1575
1576@async_variant(sync_do_select)  # type: ignore
1577async def do_select(
1578    context: "Context",
1579    value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
1580    *args: t.Any,
1581    **kwargs: t.Any,
1582) -> "t.AsyncIterator[V]":
1583    return async_select_or_reject(context, value, args, kwargs, lambda x: x, False)
1584
1585
1586@pass_context
1587def sync_do_reject(
1588    context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
1589) -> "t.Iterator[V]":
1590    """Filters a sequence of objects by applying a test to each object,
1591    and rejecting the objects with the test succeeding.
1592
1593    If no test is specified, each object will be evaluated as a boolean.
1594
1595    Example usage:
1596
1597    .. sourcecode:: jinja
1598
1599        {{ numbers|reject("odd") }}
1600
1601    Similar to a generator comprehension such as:
1602
1603    .. code-block:: python
1604
1605        (n for n in numbers if not test_odd(n))
1606
1607    .. versionadded:: 2.7
1608    """
1609    return select_or_reject(context, value, args, kwargs, lambda x: not x, False)
1610
1611
1612@async_variant(sync_do_reject)  # type: ignore
1613async def do_reject(
1614    context: "Context",
1615    value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
1616    *args: t.Any,
1617    **kwargs: t.Any,
1618) -> "t.AsyncIterator[V]":
1619    return async_select_or_reject(context, value, args, kwargs, lambda x: not x, False)
1620
1621
1622@pass_context
1623def sync_do_selectattr(
1624    context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
1625) -> "t.Iterator[V]":
1626    """Filters a sequence of objects by applying a test to the specified
1627    attribute of each object, and only selecting the objects with the
1628    test succeeding.
1629
1630    If no test is specified, the attribute's value will be evaluated as
1631    a boolean.
1632
1633    Example usage:
1634
1635    .. sourcecode:: jinja
1636
1637        {{ users|selectattr("is_active") }}
1638        {{ users|selectattr("email", "none") }}
1639
1640    Similar to a generator comprehension such as:
1641
1642    .. code-block:: python
1643
1644        (user for user in users if user.is_active)
1645        (user for user in users if test_none(user.email))
1646
1647    .. versionadded:: 2.7
1648    """
1649    return select_or_reject(context, value, args, kwargs, lambda x: x, True)
1650
1651
1652@async_variant(sync_do_selectattr)  # type: ignore
1653async def do_selectattr(
1654    context: "Context",
1655    value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
1656    *args: t.Any,
1657    **kwargs: t.Any,
1658) -> "t.AsyncIterator[V]":
1659    return async_select_or_reject(context, value, args, kwargs, lambda x: x, True)
1660
1661
1662@pass_context
1663def sync_do_rejectattr(
1664    context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
1665) -> "t.Iterator[V]":
1666    """Filters a sequence of objects by applying a test to the specified
1667    attribute of each object, and rejecting the objects with the test
1668    succeeding.
1669
1670    If no test is specified, the attribute's value will be evaluated as
1671    a boolean.
1672
1673    .. sourcecode:: jinja
1674
1675        {{ users|rejectattr("is_active") }}
1676        {{ users|rejectattr("email", "none") }}
1677
1678    Similar to a generator comprehension such as:
1679
1680    .. code-block:: python
1681
1682        (user for user in users if not user.is_active)
1683        (user for user in users if not test_none(user.email))
1684
1685    .. versionadded:: 2.7
1686    """
1687    return select_or_reject(context, value, args, kwargs, lambda x: not x, True)
1688
1689
1690@async_variant(sync_do_rejectattr)  # type: ignore
1691async def do_rejectattr(
1692    context: "Context",
1693    value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
1694    *args: t.Any,
1695    **kwargs: t.Any,
1696) -> "t.AsyncIterator[V]":
1697    return async_select_or_reject(context, value, args, kwargs, lambda x: not x, True)
1698
1699
1700@pass_eval_context
1701def do_tojson(
1702    eval_ctx: "EvalContext", value: t.Any, indent: t.Optional[int] = None
1703) -> Markup:
1704    """Serialize an object to a string of JSON, and mark it safe to
1705    render in HTML. This filter is only for use in HTML documents.
1706
1707    The returned string is safe to render in HTML documents and
1708    ``<script>`` tags. The exception is in HTML attributes that are
1709    double quoted; either use single quotes or the ``|forceescape``
1710    filter.
1711
1712    :param value: The object to serialize to JSON.
1713    :param indent: The ``indent`` parameter passed to ``dumps``, for
1714        pretty-printing the value.
1715
1716    .. versionadded:: 2.9
1717    """
1718    policies = eval_ctx.environment.policies
1719    dumps = policies["json.dumps_function"]
1720    kwargs = policies["json.dumps_kwargs"]
1721
1722    if indent is not None:
1723        kwargs = kwargs.copy()
1724        kwargs["indent"] = indent
1725
1726    return htmlsafe_json_dumps(value, dumps=dumps, **kwargs)
1727
1728
1729def prepare_map(
1730    context: "Context", args: t.Tuple[t.Any, ...], kwargs: t.Dict[str, t.Any]
1731) -> t.Callable[[t.Any], t.Any]:
1732    if not args and "attribute" in kwargs:
1733        attribute = kwargs.pop("attribute")
1734        default = kwargs.pop("default", None)
1735
1736        if kwargs:
1737            raise FilterArgumentError(
1738                f"Unexpected keyword argument {next(iter(kwargs))!r}"
1739            )
1740
1741        func = make_attrgetter(context.environment, attribute, default=default)
1742    else:
1743        try:
1744            name = args[0]
1745            args = args[1:]
1746        except LookupError:
1747            raise FilterArgumentError("map requires a filter argument") from None
1748
1749        def func(item: t.Any) -> t.Any:
1750            return context.environment.call_filter(
1751                name, item, args, kwargs, context=context
1752            )
1753
1754    return func
1755
1756
1757def prepare_select_or_reject(
1758    context: "Context",
1759    args: t.Tuple[t.Any, ...],
1760    kwargs: t.Dict[str, t.Any],
1761    modfunc: t.Callable[[t.Any], t.Any],
1762    lookup_attr: bool,
1763) -> t.Callable[[t.Any], t.Any]:
1764    if lookup_attr:
1765        try:
1766            attr = args[0]
1767        except LookupError:
1768            raise FilterArgumentError("Missing parameter for attribute name") from None
1769
1770        transfunc = make_attrgetter(context.environment, attr)
1771        off = 1
1772    else:
1773        off = 0
1774
1775        def transfunc(x: V) -> V:
1776            return x
1777
1778    try:
1779        name = args[off]
1780        args = args[1 + off :]
1781
1782        def func(item: t.Any) -> t.Any:
1783            return context.environment.call_test(name, item, args, kwargs, context)
1784
1785    except LookupError:
1786        func = bool  # type: ignore
1787
1788    return lambda item: modfunc(func(transfunc(item)))
1789
1790
1791def select_or_reject(
1792    context: "Context",
1793    value: "t.Iterable[V]",
1794    args: t.Tuple[t.Any, ...],
1795    kwargs: t.Dict[str, t.Any],
1796    modfunc: t.Callable[[t.Any], t.Any],
1797    lookup_attr: bool,
1798) -> "t.Iterator[V]":
1799    if value:
1800        func = prepare_select_or_reject(context, args, kwargs, modfunc, lookup_attr)
1801
1802        for item in value:
1803            if func(item):
1804                yield item
1805
1806
1807async def async_select_or_reject(
1808    context: "Context",
1809    value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
1810    args: t.Tuple[t.Any, ...],
1811    kwargs: t.Dict[str, t.Any],
1812    modfunc: t.Callable[[t.Any], t.Any],
1813    lookup_attr: bool,
1814) -> "t.AsyncIterator[V]":
1815    if value:
1816        func = prepare_select_or_reject(context, args, kwargs, modfunc, lookup_attr)
1817
1818        async for item in auto_aiter(value):
1819            if func(item):
1820                yield item
1821
1822
1823FILTERS = {
1824    "abs": abs,
1825    "attr": do_attr,
1826    "batch": do_batch,
1827    "capitalize": do_capitalize,
1828    "center": do_center,
1829    "count": len,
1830    "d": do_default,
1831    "default": do_default,
1832    "dictsort": do_dictsort,
1833    "e": escape,
1834    "escape": escape,
1835    "filesizeformat": do_filesizeformat,
1836    "first": do_first,
1837    "float": do_float,
1838    "forceescape": do_forceescape,
1839    "format": do_format,
1840    "groupby": do_groupby,
1841    "indent": do_indent,
1842    "int": do_int,
1843    "join": do_join,
1844    "last": do_last,
1845    "length": len,
1846    "list": do_list,
1847    "lower": do_lower,
1848    "items": do_items,
1849    "map": do_map,
1850    "min": do_min,
1851    "max": do_max,
1852    "pprint": do_pprint,
1853    "random": do_random,
1854    "reject": do_reject,
1855    "rejectattr": do_rejectattr,
1856    "replace": do_replace,
1857    "reverse": do_reverse,
1858    "round": do_round,
1859    "safe": do_mark_safe,
1860    "select": do_select,
1861    "selectattr": do_selectattr,
1862    "slice": do_slice,
1863    "sort": do_sort,
1864    "string": soft_str,
1865    "striptags": do_striptags,
1866    "sum": do_sum,
1867    "title": do_title,
1868    "trim": do_trim,
1869    "truncate": do_truncate,
1870    "unique": do_unique,
1871    "upper": do_upper,
1872    "urlencode": do_urlencode,
1873    "urlize": do_urlize,
1874    "wordcount": do_wordcount,
1875    "wordwrap": do_wordwrap,
1876    "xmlattr": do_xmlattr,
1877    "tojson": do_tojson,
1878}
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 }}>
...
Results in something like this: .. sourcecode:: html
    ...
    </ul>
    

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

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

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

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

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

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]:
506@pass_environment
507def do_min(
508    environment: "Environment",
509    value: "t.Iterable[V]",
510    case_sensitive: bool = False,
511    attribute: t.Optional[t.Union[str, int]] = None,
512) -> "t.Union[V, Undefined]":
513    """Return the smallest item from the sequence.
514
515    .. sourcecode:: jinja
516
517        {{ [1, 2, 3]|min }}
518            -> 1
519
520    :param case_sensitive: Treat upper and lower case strings as distinct.
521    :param attribute: Get the object with the min value of this attribute.
522    """
523    return _min_or_max(environment, value, min, case_sensitive, attribute)

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]:
526@pass_environment
527def do_max(
528    environment: "Environment",
529    value: "t.Iterable[V]",
530    case_sensitive: bool = False,
531    attribute: t.Optional[t.Union[str, int]] = None,
532) -> "t.Union[V, Undefined]":
533    """Return the largest item from the sequence.
534
535    .. sourcecode:: jinja
536
537        {{ [1, 2, 3]|max }}
538            -> 3
539
540    :param case_sensitive: Treat upper and lower case strings as distinct.
541    :param attribute: Get the object with the max value of this attribute.
542    """
543    return _min_or_max(environment, value, max, case_sensitive, attribute)

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:
546def do_default(
547    value: V,
548    default_value: V = "",  # type: ignore
549    boolean: bool = False,
550) -> V:
551    """If the value is undefined it will return the passed default value,
552    otherwise the value of the variable:
553
554    .. sourcecode:: jinja
555
556        {{ my_variable|default('my_variable is not defined') }}
557
558    This will output the value of ``my_variable`` if the variable was
559    defined, otherwise ``'my_variable is not defined'``. If you want
560    to use default with variables that evaluate to false you have to
561    set the second parameter to `true`:
562
563    .. sourcecode:: jinja
564
565        {{ ''|default('the string was empty', true) }}
566
567    .. versionchanged:: 2.11
568       It's now possible to configure the :class:`~jinja2.Environment` with
569       :class:`~jinja2.ChainableUndefined` to make the `default` filter work
570       on nested elements and attributes that may contain undefined values
571       in the chain without getting an :exc:`~jinja2.UndefinedError`.
572    """
573    if isinstance(value, Undefined) or (boolean and not value):
574        return default_value
575
576    return value

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

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

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:
647def do_center(value: str, width: int = 80) -> str:
648    """Centers the value in a field of a given width."""
649    return soft_str(value).center(width)

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]:
652@pass_environment
653def sync_do_first(
654    environment: "Environment", seq: "t.Iterable[V]"
655) -> "t.Union[V, Undefined]":
656    """Return the first item of a sequence."""
657    try:
658        return next(iter(seq))
659    except StopIteration:
660        return environment.undefined("No first item, sequence was empty.")

Return the first item of a sequence.

@pass_environment
def do_first( environment: jinja2.environment.Environment, seq: Iterable[~V]) -> Union[~V, jinja2.runtime.Undefined]:
652@pass_environment
653def sync_do_first(
654    environment: "Environment", seq: "t.Iterable[V]"
655) -> "t.Union[V, Undefined]":
656    """Return the first item of a sequence."""
657    try:
658        return next(iter(seq))
659    except StopIteration:
660        return environment.undefined("No first item, sequence was empty.")

Return the first item of a sequence.

@pass_environment
def do_last( environment: jinja2.environment.Environment, seq: Reversible[~V]) -> Union[~V, jinja2.runtime.Undefined]:
673@pass_environment
674def do_last(
675    environment: "Environment", seq: "t.Reversible[V]"
676) -> "t.Union[V, Undefined]":
677    """Return the last item of a sequence.
678
679    Note: Does not work with generators. You may want to explicitly
680    convert it to a list:
681
682    .. sourcecode:: jinja
683
684        {{ data | selectattr('name', '==', 'Jinja') | list | last }}
685    """
686    try:
687        return next(iter(reversed(seq)))
688    except StopIteration:
689        return environment.undefined("No last item, sequence was empty.")

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]:
695@pass_context
696def do_random(context: "Context", seq: "t.Sequence[V]") -> "t.Union[V, Undefined]":
697    """Return a random item from the sequence."""
698    try:
699        return random.choice(seq)
700    except IndexError:
701        return context.environment.undefined("No random item, sequence was empty.")

Return a random item from the sequence.

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

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

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

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

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

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:
980def do_wordcount(s: str) -> int:
981    """Count the words in that string."""
982    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:
 985def do_int(value: t.Any, default: int = 0, base: int = 10) -> int:
 986    """Convert the value into an integer. If the
 987    conversion doesn't work it will return ``0``. You can
 988    override this default using the first parameter. You
 989    can also override the default base (10) in the second
 990    parameter, which handles input with prefixes such as
 991    0b, 0o and 0x for bases 2, 8 and 16 respectively.
 992    The base is ignored for decimal numbers and non-string values.
 993    """
 994    try:
 995        if isinstance(value, str):
 996            return int(value, base)
 997
 998        return int(value)
 999    except (TypeError, ValueError):
1000        # this quirk is necessary so that "42.23"|int gives 42.
1001        try:
1002            return int(float(value))
1003        except (TypeError, ValueError, OverflowError):
1004            return default

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:
1007def do_float(value: t.Any, default: float = 0.0) -> float:
1008    """Convert the value into a floating point number. If the
1009    conversion doesn't work it will return ``0.0``. You can
1010    override this default using the first parameter.
1011    """
1012    try:
1013        return float(value)
1014    except (TypeError, ValueError):
1015        return default

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:
1018def do_format(value: str, *args: t.Any, **kwargs: t.Any) -> str:
1019    """Apply the given values to a `printf-style`_ format string, like
1020    ``string % values``.
1021
1022    .. sourcecode:: jinja
1023
1024        {{ "%s, %s!"|format(greeting, name) }}
1025        Hello, World!
1026
1027    In most cases it should be more convenient and efficient to use the
1028    ``%`` operator or :meth:`str.format`.
1029
1030    .. code-block:: text
1031
1032        {{ "%s, %s!" % (greeting, name) }}
1033        {{ "{}, {}!".format(greeting, name) }}
1034
1035    .. _printf-style: https://docs.python.org/library/stdtypes.html
1036        #printf-style-string-formatting
1037    """
1038    if args and kwargs:
1039        raise FilterArgumentError(
1040            "can't handle positional and keyword arguments at the same time"
1041        )
1042
1043    return soft_str(value) % (kwargs or args)

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:
1046def do_trim(value: str, chars: t.Optional[str] = None) -> str:
1047    """Strip leading and trailing characters, by default whitespace."""
1048    return soft_str(value).strip(chars)

Strip leading and trailing characters, by default whitespace.

def do_striptags(value: Union[str, jinja2.filters.HasHTML]) -> str:
1051def do_striptags(value: "t.Union[str, HasHTML]") -> str:
1052    """Strip SGML/XML tags and replace adjacent whitespace by one space."""
1053    if hasattr(value, "__html__"):
1054        value = t.cast("HasHTML", value).__html__()
1055
1056    return Markup(str(value)).striptags()

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

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

.. sourcecode:: html+jinja

{%- for column in items|slice(3) %}
    {%- for item in column %}
  • {{ item }}
  • {%- endfor %}
{%- endfor %}

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

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

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

.. sourcecode:: html+jinja

{%- for column in items|slice(3) %}
    {%- for item in column %}
  • {{ item }}
  • {%- endfor %}
{%- endfor %}

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

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

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

.. sourcecode:: html+jinja


{%- for row in items|batch(3, ' ') %}
  
  {%- for column in row %}
    
  {%- endfor %}
  
{%- endfor %}
{{ column }}
def do_round( value: float, precision: int = 0, method: Literal['common', 'ceil', 'floor'] = 'common') -> float:
1148def do_round(
1149    value: float,
1150    precision: int = 0,
1151    method: 'te.Literal["common", "ceil", "floor"]' = "common",
1152) -> float:
1153    """Round the number to a given precision. The first
1154    parameter specifies the precision (default is ``0``), the
1155    second the rounding method:
1156
1157    - ``'common'`` rounds either up or down
1158    - ``'ceil'`` always rounds up
1159    - ``'floor'`` always rounds down
1160
1161    If you don't specify a method ``'common'`` is used.
1162
1163    .. sourcecode:: jinja
1164
1165        {{ 42.55|round }}
1166            -> 43.0
1167        {{ 42.55|round(1, 'floor') }}
1168            -> 42.5
1169
1170    Note that even if rounded to 0 precision, a float is returned.  If
1171    you need a real integer, pipe it through `int`:
1172
1173    .. sourcecode:: jinja
1174
1175        {{ 42.55|round|int }}
1176            -> 43
1177    """
1178    if method not in {"common", "ceil", "floor"}:
1179        raise FilterArgumentError("method must be common, ceil or floor")
1180
1181    if method == "common":
1182        return round(value, precision)
1183
1184    func = getattr(math, method)
1185    return t.cast(float, func(value * (10**precision)) / (10**precision))

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

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

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:
1312@pass_environment
1313def sync_do_sum(
1314    environment: "Environment",
1315    iterable: "t.Iterable[V]",
1316    attribute: t.Optional[t.Union[str, int]] = None,
1317    start: V = 0,  # type: ignore
1318) -> V:
1319    """Returns the sum of a sequence of numbers plus the value of parameter
1320    'start' (which defaults to 0).  When the sequence is empty it returns
1321    start.
1322
1323    It is also possible to sum up only certain attributes:
1324
1325    .. sourcecode:: jinja
1326
1327        Total: {{ items|sum(attribute='price') }}
1328
1329    .. versionchanged:: 2.6
1330       The ``attribute`` parameter was added to allow summing up over
1331       attributes.  Also the ``start`` parameter was moved on to the right.
1332    """
1333    if attribute is not None:
1334        iterable = map(make_attrgetter(environment, attribute), iterable)
1335
1336    return sum(iterable, start)  # type: ignore[no-any-return, call-overload]

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:
1312@pass_environment
1313def sync_do_sum(
1314    environment: "Environment",
1315    iterable: "t.Iterable[V]",
1316    attribute: t.Optional[t.Union[str, int]] = None,
1317    start: V = 0,  # type: ignore
1318) -> V:
1319    """Returns the sum of a sequence of numbers plus the value of parameter
1320    'start' (which defaults to 0).  When the sequence is empty it returns
1321    start.
1322
1323    It is also possible to sum up only certain attributes:
1324
1325    .. sourcecode:: jinja
1326
1327        Total: {{ items|sum(attribute='price') }}
1328
1329    .. versionchanged:: 2.6
1330       The ``attribute`` parameter was added to allow summing up over
1331       attributes.  Also the ``start`` parameter was moved on to the right.
1332    """
1333    if attribute is not None:
1334        iterable = map(make_attrgetter(environment, attribute), iterable)
1335
1336    return sum(iterable, start)  # type: ignore[no-any-return, call-overload]

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]:
1361def sync_do_list(value: "t.Iterable[V]") -> "t.List[V]":
1362    """Convert the value into a list.  If it was a string the returned list
1363    will be a list of characters.
1364    """
1365    return list(value)

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]:
1361def sync_do_list(value: "t.Iterable[V]") -> "t.List[V]":
1362    """Convert the value into a list.  If it was a string the returned list
1363    will be a list of characters.
1364    """
1365    return list(value)

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:
1373def do_mark_safe(value: str) -> Markup:
1374    """Mark the value as safe which means that in an environment with automatic
1375    escaping enabled this variable will not be escaped.
1376    """
1377    return Markup(value)

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:
1380def do_mark_unsafe(value: str) -> str:
1381    """Mark a value as unsafe.  This is the reverse operation for :func:`safe`."""
1382    return str(value)

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

def do_reverse(value: Union[str, Iterable[~V]]) -> Union[str, Iterable[~V]]:
1393def do_reverse(value: t.Union[str, t.Iterable[V]]) -> t.Union[str, t.Iterable[V]]:
1394    """Reverse the object or return an iterator that iterates over it the other
1395    way round.
1396    """
1397    if isinstance(value, str):
1398        return value[::-1]
1399
1400    try:
1401        return reversed(value)  # type: ignore
1402    except TypeError:
1403        try:
1404            rv = list(value)
1405            rv.reverse()
1406            return rv
1407        except TypeError as e:
1408            raise FilterArgumentError("argument must be iterable") from e

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]:
1411@pass_environment
1412def do_attr(
1413    environment: "Environment", obj: t.Any, name: str
1414) -> t.Union[Undefined, t.Any]:
1415    """Get an attribute of an object.  ``foo|attr("bar")`` works like
1416    ``foo.bar`` just that always an attribute is returned and items are not
1417    looked up.
1418
1419    See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details.
1420    """
1421    try:
1422        name = str(name)
1423    except UnicodeError:
1424        pass
1425    else:
1426        try:
1427            value = getattr(obj, name)
1428        except AttributeError:
1429            pass
1430        else:
1431            if environment.sandboxed:
1432                environment = t.cast("SandboxedEnvironment", environment)
1433
1434                if not environment.is_safe_attribute(obj, name, value):
1435                    return environment.unsafe_undefined(obj, name)
1436
1437            return value
1438
1439    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]:
1462@pass_context
1463def sync_do_map(
1464    context: "Context", value: t.Iterable[t.Any], *args: t.Any, **kwargs: t.Any
1465) -> t.Iterable[t.Any]:
1466    """Applies a filter on a sequence of objects or looks up an attribute.
1467    This is useful when dealing with lists of objects but you are really
1468    only interested in a certain value of it.
1469
1470    The basic usage is mapping on an attribute.  Imagine you have a list
1471    of users but you are only interested in a list of usernames:
1472
1473    .. sourcecode:: jinja
1474
1475        Users on this page: {{ users|map(attribute='username')|join(', ') }}
1476
1477    You can specify a ``default`` value to use if an object in the list
1478    does not have the given attribute.
1479
1480    .. sourcecode:: jinja
1481
1482        {{ users|map(attribute="username", default="Anonymous")|join(", ") }}
1483
1484    Alternatively you can let it invoke a filter by passing the name of the
1485    filter and the arguments afterwards.  A good example would be applying a
1486    text conversion filter on a sequence:
1487
1488    .. sourcecode:: jinja
1489
1490        Users on this page: {{ titles|map('lower')|join(', ') }}
1491
1492    Similar to a generator comprehension such as:
1493
1494    .. code-block:: python
1495
1496        (u.username for u in users)
1497        (getattr(u, "username", "Anonymous") for u in users)
1498        (do_lower(x) for x in titles)
1499
1500    .. versionchanged:: 2.11.0
1501        Added the ``default`` parameter.
1502
1503    .. versionadded:: 2.7
1504    """
1505    if value:
1506        func = prepare_map(context, args, kwargs)
1507
1508        for item in value:
1509            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]:
1462@pass_context
1463def sync_do_map(
1464    context: "Context", value: t.Iterable[t.Any], *args: t.Any, **kwargs: t.Any
1465) -> t.Iterable[t.Any]:
1466    """Applies a filter on a sequence of objects or looks up an attribute.
1467    This is useful when dealing with lists of objects but you are really
1468    only interested in a certain value of it.
1469
1470    The basic usage is mapping on an attribute.  Imagine you have a list
1471    of users but you are only interested in a list of usernames:
1472
1473    .. sourcecode:: jinja
1474
1475        Users on this page: {{ users|map(attribute='username')|join(', ') }}
1476
1477    You can specify a ``default`` value to use if an object in the list
1478    does not have the given attribute.
1479
1480    .. sourcecode:: jinja
1481
1482        {{ users|map(attribute="username", default="Anonymous")|join(", ") }}
1483
1484    Alternatively you can let it invoke a filter by passing the name of the
1485    filter and the arguments afterwards.  A good example would be applying a
1486    text conversion filter on a sequence:
1487
1488    .. sourcecode:: jinja
1489
1490        Users on this page: {{ titles|map('lower')|join(', ') }}
1491
1492    Similar to a generator comprehension such as:
1493
1494    .. code-block:: python
1495
1496        (u.username for u in users)
1497        (getattr(u, "username", "Anonymous") for u in users)
1498        (do_lower(x) for x in titles)
1499
1500    .. versionchanged:: 2.11.0
1501        Added the ``default`` parameter.
1502
1503    .. versionadded:: 2.7
1504    """
1505    if value:
1506        func = prepare_map(context, args, kwargs)
1507
1508        for item in value:
1509            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]:
1546@pass_context
1547def sync_do_select(
1548    context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
1549) -> "t.Iterator[V]":
1550    """Filters a sequence of objects by applying a test to each object,
1551    and only selecting the objects with the test succeeding.
1552
1553    If no test is specified, each object will be evaluated as a boolean.
1554
1555    Example usage:
1556
1557    .. sourcecode:: jinja
1558
1559        {{ numbers|select("odd") }}
1560        {{ numbers|select("odd") }}
1561        {{ numbers|select("divisibleby", 3) }}
1562        {{ numbers|select("lessthan", 42) }}
1563        {{ strings|select("equalto", "mystring") }}
1564
1565    Similar to a generator comprehension such as:
1566
1567    .. code-block:: python
1568
1569        (n for n in numbers if test_odd(n))
1570        (n for n in numbers if test_divisibleby(n, 3))
1571
1572    .. versionadded:: 2.7
1573    """
1574    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]:
1546@pass_context
1547def sync_do_select(
1548    context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
1549) -> "t.Iterator[V]":
1550    """Filters a sequence of objects by applying a test to each object,
1551    and only selecting the objects with the test succeeding.
1552
1553    If no test is specified, each object will be evaluated as a boolean.
1554
1555    Example usage:
1556
1557    .. sourcecode:: jinja
1558
1559        {{ numbers|select("odd") }}
1560        {{ numbers|select("odd") }}
1561        {{ numbers|select("divisibleby", 3) }}
1562        {{ numbers|select("lessthan", 42) }}
1563        {{ strings|select("equalto", "mystring") }}
1564
1565    Similar to a generator comprehension such as:
1566
1567    .. code-block:: python
1568
1569        (n for n in numbers if test_odd(n))
1570        (n for n in numbers if test_divisibleby(n, 3))
1571
1572    .. versionadded:: 2.7
1573    """
1574    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]:
1587@pass_context
1588def sync_do_reject(
1589    context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
1590) -> "t.Iterator[V]":
1591    """Filters a sequence of objects by applying a test to each object,
1592    and rejecting the objects with the test succeeding.
1593
1594    If no test is specified, each object will be evaluated as a boolean.
1595
1596    Example usage:
1597
1598    .. sourcecode:: jinja
1599
1600        {{ numbers|reject("odd") }}
1601
1602    Similar to a generator comprehension such as:
1603
1604    .. code-block:: python
1605
1606        (n for n in numbers if not test_odd(n))
1607
1608    .. versionadded:: 2.7
1609    """
1610    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]:
1587@pass_context
1588def sync_do_reject(
1589    context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
1590) -> "t.Iterator[V]":
1591    """Filters a sequence of objects by applying a test to each object,
1592    and rejecting the objects with the test succeeding.
1593
1594    If no test is specified, each object will be evaluated as a boolean.
1595
1596    Example usage:
1597
1598    .. sourcecode:: jinja
1599
1600        {{ numbers|reject("odd") }}
1601
1602    Similar to a generator comprehension such as:
1603
1604    .. code-block:: python
1605
1606        (n for n in numbers if not test_odd(n))
1607
1608    .. versionadded:: 2.7
1609    """
1610    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]:
1623@pass_context
1624def sync_do_selectattr(
1625    context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
1626) -> "t.Iterator[V]":
1627    """Filters a sequence of objects by applying a test to the specified
1628    attribute of each object, and only selecting the objects with the
1629    test succeeding.
1630
1631    If no test is specified, the attribute's value will be evaluated as
1632    a boolean.
1633
1634    Example usage:
1635
1636    .. sourcecode:: jinja
1637
1638        {{ users|selectattr("is_active") }}
1639        {{ users|selectattr("email", "none") }}
1640
1641    Similar to a generator comprehension such as:
1642
1643    .. code-block:: python
1644
1645        (user for user in users if user.is_active)
1646        (user for user in users if test_none(user.email))
1647
1648    .. versionadded:: 2.7
1649    """
1650    return select_or_reject(context, value, args, kwargs, lambda x: x, True)

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

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

Example usage:

.. sourcecode:: jinja

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

Similar to a generator comprehension such as:

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

New in version 2.7.

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

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

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

Example usage:

.. sourcecode:: jinja

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

Similar to a generator comprehension such as:

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

New in version 2.7.

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

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

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

.. sourcecode:: jinja

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

Similar to a generator comprehension such as:

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

New in version 2.7.

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

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

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

.. sourcecode:: jinja

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

Similar to a generator comprehension such as:

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

New in version 2.7.

@pass_eval_context
def do_tojson( eval_ctx: jinja2.nodes.EvalContext, value: Any, indent: Optional[int] = None) -> markupsafe.Markup:
1701@pass_eval_context
1702def do_tojson(
1703    eval_ctx: "EvalContext", value: t.Any, indent: t.Optional[int] = None
1704) -> Markup:
1705    """Serialize an object to a string of JSON, and mark it safe to
1706    render in HTML. This filter is only for use in HTML documents.
1707
1708    The returned string is safe to render in HTML documents and
1709    ``<script>`` tags. The exception is in HTML attributes that are
1710    double quoted; either use single quotes or the ``|forceescape``
1711    filter.
1712
1713    :param value: The object to serialize to JSON.
1714    :param indent: The ``indent`` parameter passed to ``dumps``, for
1715        pretty-printing the value.
1716
1717    .. versionadded:: 2.9
1718    """
1719    policies = eval_ctx.environment.policies
1720    dumps = policies["json.dumps_function"]
1721    kwargs = policies["json.dumps_kwargs"]
1722
1723    if indent is not None:
1724        kwargs = kwargs.copy()
1725        kwargs["indent"] = indent
1726
1727    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]:
1730def prepare_map(
1731    context: "Context", args: t.Tuple[t.Any, ...], kwargs: t.Dict[str, t.Any]
1732) -> t.Callable[[t.Any], t.Any]:
1733    if not args and "attribute" in kwargs:
1734        attribute = kwargs.pop("attribute")
1735        default = kwargs.pop("default", None)
1736
1737        if kwargs:
1738            raise FilterArgumentError(
1739                f"Unexpected keyword argument {next(iter(kwargs))!r}"
1740            )
1741
1742        func = make_attrgetter(context.environment, attribute, default=default)
1743    else:
1744        try:
1745            name = args[0]
1746            args = args[1:]
1747        except LookupError:
1748            raise FilterArgumentError("map requires a filter argument") from None
1749
1750        def func(item: t.Any) -> t.Any:
1751            return context.environment.call_filter(
1752                name, item, args, kwargs, context=context
1753            )
1754
1755    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]:
1758def prepare_select_or_reject(
1759    context: "Context",
1760    args: t.Tuple[t.Any, ...],
1761    kwargs: t.Dict[str, t.Any],
1762    modfunc: t.Callable[[t.Any], t.Any],
1763    lookup_attr: bool,
1764) -> t.Callable[[t.Any], t.Any]:
1765    if lookup_attr:
1766        try:
1767            attr = args[0]
1768        except LookupError:
1769            raise FilterArgumentError("Missing parameter for attribute name") from None
1770
1771        transfunc = make_attrgetter(context.environment, attr)
1772        off = 1
1773    else:
1774        off = 0
1775
1776        def transfunc(x: V) -> V:
1777            return x
1778
1779    try:
1780        name = args[off]
1781        args = args[1 + off :]
1782
1783        def func(item: t.Any) -> t.Any:
1784            return context.environment.call_test(name, item, args, kwargs, context)
1785
1786    except LookupError:
1787        func = bool  # type: ignore
1788
1789    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]:
1792def select_or_reject(
1793    context: "Context",
1794    value: "t.Iterable[V]",
1795    args: t.Tuple[t.Any, ...],
1796    kwargs: t.Dict[str, t.Any],
1797    modfunc: t.Callable[[t.Any], t.Any],
1798    lookup_attr: bool,
1799) -> "t.Iterator[V]":
1800    if value:
1801        func = prepare_select_or_reject(context, args, kwargs, modfunc, lookup_attr)
1802
1803        for item in value:
1804            if func(item):
1805                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]:
1808async def async_select_or_reject(
1809    context: "Context",
1810    value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
1811    args: t.Tuple[t.Any, ...],
1812    kwargs: t.Dict[str, t.Any],
1813    modfunc: t.Callable[[t.Any], t.Any],
1814    lookup_attr: bool,
1815) -> "t.AsyncIterator[V]":
1816    if value:
1817        func = prepare_select_or_reject(context, args, kwargs, modfunc, lookup_attr)
1818
1819        async for item in auto_aiter(value):
1820            if func(item):
1821                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>}