jinja2.filters

Built-in template filters used with the | operator.

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

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

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

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

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

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

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

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

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

Enforce HTML escaping. This will probably double escape variables.

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

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

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

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

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

New in version 2.7.

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

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

.. sourcecode:: jinja

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

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

Convert a value to uppercase.

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

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

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

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

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

New in version 3.1.

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

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

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

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

.. sourcecode:: html+jinja

<ul{{ {'class': 'my_list', 'missing': none,
        'id': 'list-%d'|format(variable)}|xmlattr }}>
...
Results in something like this: .. sourcecode:: html
    ...
    </ul>
    

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

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

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

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

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

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

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

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

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

.. sourcecode:: jinja

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

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

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

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

Sort an iterable using Python's sorted().

.. sourcecode:: jinja

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

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

.. sourcecode:: jinja

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

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

.. sourcecode:: jinja

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

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

Changed in version 2.6: The attribute parameter was added.

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

Returns a list of unique items from the given iterable.

.. sourcecode:: jinja

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

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

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

Returns a list of unique items from the given iterable.

.. sourcecode:: jinja

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

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

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

Return the smallest item from the sequence.

.. sourcecode:: jinja

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

Return the largest item from the sequence.

.. sourcecode:: jinja

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

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

.. sourcecode:: jinja

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

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

.. sourcecode:: jinja

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

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

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

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

.. sourcecode:: jinja

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

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

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

.. sourcecode:: jinja

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

New in version 2.6: The attribute parameter was added.

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

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

.. sourcecode:: jinja

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

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

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

.. sourcecode:: jinja

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

New in version 2.6: The attribute parameter was added.

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

Centers the value in a field of a given width.

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

Return the first item of a sequence.

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

Return the first item of a sequence.

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

Return the last item of a sequence.

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

.. sourcecode:: jinja

{{ data | selectattr('name', '==', 'Jinja') | list | last }}
@pass_context
def do_random( context: jinja2.runtime.Context, seq: Sequence[~V]) -> Union[~V, jinja2.runtime.Undefined]:
696@pass_context
697def do_random(context: "Context", seq: "t.Sequence[V]") -> "t.Union[V, Undefined]":
698    """Return a random item from the sequence."""
699    try:
700        return random.choice(seq)
701    except IndexError:
702        return context.environment.undefined("No random item, sequence was empty.")

Return a random item from the sequence.

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

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

def do_pprint(value: Any) -> str:
738def do_pprint(value: t.Any) -> str:
739    """Pretty print a variable. Useful for debugging."""
740    return pformat(value)

Pretty print a variable. Useful for debugging.

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

Convert URLs in text into clickable links.

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

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

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

Changed in version 3.0: The extra_schemes parameter was added.

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

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

Changed in version 2.8: The target parameter was added.

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

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

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

Changed in version 3.0: width can be a string.

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

Rename the indentfirst argument to first.

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

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

.. sourcecode:: jinja

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

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

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

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

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

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

Changed in version 2.11: Added the break_on_hyphens parameter.

Changed in version 2.7: Added the wrapstring parameter.

def do_wordcount(s: str) -> int:
981def do_wordcount(s: str) -> int:
982    """Count the words in that string."""
983    return len(_word_re.findall(soft_str(s)))

Count the words in that string.

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

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

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

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

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

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

.. sourcecode:: jinja

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

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

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

Strip leading and trailing characters, by default whitespace.

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

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

.. sourcecode:: html+jinja

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

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

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

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

.. sourcecode:: html+jinja

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

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

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

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

.. sourcecode:: html+jinja


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

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

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

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

.. sourcecode:: jinja

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

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

.. sourcecode:: jinja

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

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

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

.. sourcecode:: html+jinja

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

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

.. sourcecode:: html+jinja

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

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

.. sourcecode:: jinja

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

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

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

Changed in version 3.0: Added the default parameter.

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

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

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

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

.. sourcecode:: html+jinja

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

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

.. sourcecode:: html+jinja

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

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

.. sourcecode:: jinja

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

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

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

Changed in version 3.0: Added the default parameter.

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

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

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

It is also possible to sum up only certain attributes:

.. sourcecode:: jinja

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

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

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

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

It is also possible to sum up only certain attributes:

.. sourcecode:: jinja

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

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

def sync_do_list(value: Iterable[~V]) -> List[~V]:
1362def sync_do_list(value: "t.Iterable[V]") -> "t.List[V]":
1363    """Convert the value into a list.  If it was a string the returned list
1364    will be a list of characters.
1365    """
1366    return list(value)

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

def do_list(value: Iterable[~V]) -> List[~V]:
1362def sync_do_list(value: "t.Iterable[V]") -> "t.List[V]":
1363    """Convert the value into a list.  If it was a string the returned list
1364    will be a list of characters.
1365    """
1366    return list(value)

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

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

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

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

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

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

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

@pass_environment
def do_attr( environment: jinja2.environment.Environment, obj: Any, name: str) -> Union[jinja2.runtime.Undefined, Any]:
1412@pass_environment
1413def do_attr(
1414    environment: "Environment", obj: t.Any, name: str
1415) -> t.Union[Undefined, t.Any]:
1416    """Get an attribute of an object. ``foo|attr("bar")`` works like
1417    ``foo.bar``, but returns undefined instead of falling back to ``foo["bar"]``
1418    if the attribute doesn't exist.
1419
1420    See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details.
1421    """
1422    # Environment.getattr will fall back to obj[name] if obj.name doesn't exist.
1423    # But we want to call env.getattr to get behavior such as sandboxing.
1424    # Determine if the attr exists first, so we know the fallback won't trigger.
1425    try:
1426        # This avoids executing properties/descriptors, but misses __getattr__
1427        # and __getattribute__ dynamic attrs.
1428        getattr_static(obj, name)
1429    except AttributeError:
1430        # This finds dynamic attrs, and we know it's not a descriptor at this point.
1431        if not hasattr(obj, name):
1432            return environment.undefined(obj=obj, name=name)
1433
1434    return environment.getattr(obj, name)

Get an attribute of an object. foo|attr("bar") works like foo.bar, but returns undefined instead of falling back to foo["bar"] if the attribute doesn't exist.

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

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

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

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

.. sourcecode:: jinja

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

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

.. sourcecode:: jinja

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

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

.. sourcecode:: jinja

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

Similar to a generator comprehension such as:

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

Changed in version 2.11.0: Added the default parameter.

New in version 2.7.

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

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

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

.. sourcecode:: jinja

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

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

.. sourcecode:: jinja

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

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

.. sourcecode:: jinja

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

Similar to a generator comprehension such as:

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

Changed in version 2.11.0: Added the default parameter.

New in version 2.7.

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

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

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

Example usage:

.. sourcecode:: jinja

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

Similar to a generator comprehension such as:

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

New in version 2.7.

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

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

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

Example usage:

.. sourcecode:: jinja

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

Similar to a generator comprehension such as:

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

New in version 2.7.

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

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

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

Example usage:

.. sourcecode:: jinja

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

Similar to a generator comprehension such as:

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

New in version 2.7.

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

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

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

Example usage:

.. sourcecode:: jinja

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

Similar to a generator comprehension such as:

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

New in version 2.7.

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

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

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

Example usage:

.. sourcecode:: jinja

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

Similar to a generator comprehension such as:

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

New in version 2.7.

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

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

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

Example usage:

.. sourcecode:: jinja

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

Similar to a generator comprehension such as:

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

New in version 2.7.

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

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

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

.. sourcecode:: jinja

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

Similar to a generator comprehension such as:

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

New in version 2.7.

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

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

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

.. sourcecode:: jinja

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

Similar to a generator comprehension such as:

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

New in version 2.7.

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

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

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

Parameters
  • value: The object to serialize to JSON.
  • indent: The indent parameter passed 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]:
1725def prepare_map(
1726    context: "Context", args: t.Tuple[t.Any, ...], kwargs: t.Dict[str, t.Any]
1727) -> t.Callable[[t.Any], t.Any]:
1728    if not args and "attribute" in kwargs:
1729        attribute = kwargs.pop("attribute")
1730        default = kwargs.pop("default", None)
1731
1732        if kwargs:
1733            raise FilterArgumentError(
1734                f"Unexpected keyword argument {next(iter(kwargs))!r}"
1735            )
1736
1737        func = make_attrgetter(context.environment, attribute, default=default)
1738    else:
1739        try:
1740            name = args[0]
1741            args = args[1:]
1742        except LookupError:
1743            raise FilterArgumentError("map requires a filter argument") from None
1744
1745        def func(item: t.Any) -> t.Any:
1746            return context.environment.call_filter(
1747                name, item, args, kwargs, context=context
1748            )
1749
1750    return func
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]:
1753def prepare_select_or_reject(
1754    context: "Context",
1755    args: t.Tuple[t.Any, ...],
1756    kwargs: t.Dict[str, t.Any],
1757    modfunc: t.Callable[[t.Any], t.Any],
1758    lookup_attr: bool,
1759) -> t.Callable[[t.Any], t.Any]:
1760    if lookup_attr:
1761        try:
1762            attr = args[0]
1763        except LookupError:
1764            raise FilterArgumentError("Missing parameter for attribute name") from None
1765
1766        transfunc = make_attrgetter(context.environment, attr)
1767        off = 1
1768    else:
1769        off = 0
1770
1771        def transfunc(x: V) -> V:
1772            return x
1773
1774    try:
1775        name = args[off]
1776        args = args[1 + off :]
1777
1778        def func(item: t.Any) -> t.Any:
1779            return context.environment.call_test(name, item, args, kwargs, context)
1780
1781    except LookupError:
1782        func = bool  # type: ignore
1783
1784    return lambda item: modfunc(func(transfunc(item)))
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]:
1787def select_or_reject(
1788    context: "Context",
1789    value: "t.Iterable[V]",
1790    args: t.Tuple[t.Any, ...],
1791    kwargs: t.Dict[str, t.Any],
1792    modfunc: t.Callable[[t.Any], t.Any],
1793    lookup_attr: bool,
1794) -> "t.Iterator[V]":
1795    if value:
1796        func = prepare_select_or_reject(context, args, kwargs, modfunc, lookup_attr)
1797
1798        for item in value:
1799            if func(item):
1800                yield item
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]:
1803async def async_select_or_reject(
1804    context: "Context",
1805    value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
1806    args: t.Tuple[t.Any, ...],
1807    kwargs: t.Dict[str, t.Any],
1808    modfunc: t.Callable[[t.Any], t.Any],
1809    lookup_attr: bool,
1810) -> "t.AsyncIterator[V]":
1811    if value:
1812        func = prepare_select_or_reject(context, args, kwargs, modfunc, lookup_attr)
1813
1814        async for item in auto_aiter(value):
1815            if func(item):
1816                yield item
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': <function escape>, 'escape': <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': <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>}