jinja2.filters

Built-in template filters used with the | operator.

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

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

Convert a value to uppercase.

def do_lower(s: str) -> str:
217def do_lower(s: str) -> str:
218    """Convert a value to lowercase."""
219    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]]:
222def do_items(value: t.Union[t.Mapping[K, V], Undefined]) -> t.Iterator[t.Tuple[K, V]]:
223    """Return an iterator over the ``(key, value)`` items of a mapping.
224
225    ``x|items`` is the same as ``x.items()``, except if ``x`` is
226    undefined an empty iterator is returned.
227
228    This filter is useful if you expect the template to be rendered with
229    an implementation of Jinja in another programming language that does
230    not have a ``.items()`` method on its mapping type.
231
232    .. code-block:: html+jinja
233
234        <dl>
235        {% for key, value in my_dict|items %}
236            <dt>{{ key }}
237            <dd>{{ value }}
238        {% endfor %}
239        </dl>
240
241    .. versionadded:: 3.1
242    """
243    if isinstance(value, Undefined):
244        return
245
246    if not isinstance(value, abc.Mapping):
247        raise TypeError("Can only get item pairs from a mapping.")
248
249    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:
255@pass_eval_context
256def do_xmlattr(
257    eval_ctx: "EvalContext", d: t.Mapping[str, t.Any], autospace: bool = True
258) -> str:
259    """Create an SGML/XML attribute string based on the items in a dict.
260
261    If any key contains a space, this fails with a ``ValueError``. Values that
262    are neither ``none`` nor ``undefined`` are automatically escaped.
263
264    .. sourcecode:: html+jinja
265
266        <ul{{ {'class': 'my_list', 'missing': none,
267                'id': 'list-%d'|format(variable)}|xmlattr }}>
268        ...
269        </ul>
270
271    Results in something like this:
272
273    .. sourcecode:: html
274
275        <ul class="my_list" id="list-42">
276        ...
277        </ul>
278
279    As you can see it automatically prepends a space in front of the item
280    if the filter returned something unless the second parameter is false.
281
282    .. versionchanged:: 3.1.3
283        Keys with spaces are not allowed.
284    """
285    items = []
286
287    for key, value in d.items():
288        if value is None or isinstance(value, Undefined):
289            continue
290
291        if _space_re.search(key) is not None:
292            raise ValueError(f"Spaces are not allowed in attributes: '{key}'")
293
294        items.append(f'{escape(key)}="{escape(value)}"')
295
296    rv = " ".join(items)
297
298    if autospace and rv:
299        rv = " " + rv
300
301    if eval_ctx.autoescape:
302        rv = Markup(rv)
303
304    return rv

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

If any key contains a space, this fails with a ValueError. Values that are neither none nor undefined are automatically escaped.

.. sourcecode:: html+jinja

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

Results in something like this:

.. sourcecode:: html

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

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

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

def do_capitalize(s: str) -> str:
307def do_capitalize(s: str) -> str:
308    """Capitalize a value. The first character will be uppercase, all others
309    lowercase.
310    """
311    return soft_str(s).capitalize()

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

def do_title(s: str) -> str:
317def do_title(s: str) -> str:
318    """Return a titlecased version of the value. I.e. words will start with
319    uppercase letters, all remaining characters are lowercase.
320    """
321    return "".join(
322        [
323            item[0].upper() + item[1:].lower()
324            for item in _word_beginning_split_re.split(soft_str(s))
325            if item
326        ]
327    )

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]]:
330def do_dictsort(
331    value: t.Mapping[K, V],
332    case_sensitive: bool = False,
333    by: 'te.Literal["key", "value"]' = "key",
334    reverse: bool = False,
335) -> t.List[t.Tuple[K, V]]:
336    """Sort a dict and yield (key, value) pairs. Python dicts may not
337    be in the order you want to display them in, so sort them first.
338
339    .. sourcecode:: jinja
340
341        {% for key, value in mydict|dictsort %}
342            sort the dict by key, case insensitive
343
344        {% for key, value in mydict|dictsort(reverse=true) %}
345            sort the dict by key, case insensitive, reverse order
346
347        {% for key, value in mydict|dictsort(true) %}
348            sort the dict by key, case sensitive
349
350        {% for key, value in mydict|dictsort(false, 'value') %}
351            sort the dict by value, case insensitive
352    """
353    if by == "key":
354        pos = 0
355    elif by == "value":
356        pos = 1
357    else:
358        raise FilterArgumentError('You can only sort by either "key" or "value"')
359
360    def sort_func(item: t.Tuple[t.Any, t.Any]) -> t.Any:
361        value = item[pos]
362
363        if not case_sensitive:
364            value = ignore_case(value)
365
366        return value
367
368    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]:
371@pass_environment
372def do_sort(
373    environment: "Environment",
374    value: "t.Iterable[V]",
375    reverse: bool = False,
376    case_sensitive: bool = False,
377    attribute: t.Optional[t.Union[str, int]] = None,
378) -> "t.List[V]":
379    """Sort an iterable using Python's :func:`sorted`.
380
381    .. sourcecode:: jinja
382
383        {% for city in cities|sort %}
384            ...
385        {% endfor %}
386
387    :param reverse: Sort descending instead of ascending.
388    :param case_sensitive: When sorting strings, sort upper and lower
389        case separately.
390    :param attribute: When sorting objects or dicts, an attribute or
391        key to sort by. Can use dot notation like ``"address.city"``.
392        Can be a list of attributes like ``"age,name"``.
393
394    The sort is stable, it does not change the relative order of
395    elements that compare equal. This makes it is possible to chain
396    sorts on different attributes and ordering.
397
398    .. sourcecode:: jinja
399
400        {% for user in users|sort(attribute="name")
401            |sort(reverse=true, attribute="age") %}
402            ...
403        {% endfor %}
404
405    As a shortcut to chaining when the direction is the same for all
406    attributes, pass a comma separate list of attributes.
407
408    .. sourcecode:: jinja
409
410        {% for user in users|sort(attribute="age,name") %}
411            ...
412        {% endfor %}
413
414    .. versionchanged:: 2.11.0
415        The ``attribute`` parameter can be a comma separated list of
416        attributes, e.g. ``"age,name"``.
417
418    .. versionchanged:: 2.6
419       The ``attribute`` parameter was added.
420    """
421    key_func = make_multi_attrgetter(
422        environment, attribute, postprocess=ignore_case if not case_sensitive else None
423    )
424    return sorted(value, key=key_func, reverse=reverse)

Sort an iterable using Python's sorted().

.. sourcecode:: jinja

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

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

.. sourcecode:: jinja

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

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

.. sourcecode:: jinja

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

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

Changed in version 2.6: The attribute parameter was added.

@pass_environment
def do_unique( environment: jinja2.environment.Environment, value: Iterable[~V], case_sensitive: bool = False, attribute: Union[str, int, NoneType] = None) -> Iterator[~V]:
427@pass_environment
428def do_unique(
429    environment: "Environment",
430    value: "t.Iterable[V]",
431    case_sensitive: bool = False,
432    attribute: t.Optional[t.Union[str, int]] = None,
433) -> "t.Iterator[V]":
434    """Returns a list of unique items from the given iterable.
435
436    .. sourcecode:: jinja
437
438        {{ ['foo', 'bar', 'foobar', 'FooBar']|unique|list }}
439            -> ['foo', 'bar', 'foobar']
440
441    The unique items are yielded in the same order as their first occurrence in
442    the iterable passed to the filter.
443
444    :param case_sensitive: Treat upper and lower case strings as distinct.
445    :param attribute: Filter objects with unique values for this attribute.
446    """
447    getter = make_attrgetter(
448        environment, attribute, postprocess=ignore_case if not case_sensitive else None
449    )
450    seen = set()
451
452    for item in value:
453        key = getter(item)
454
455        if key not in seen:
456            seen.add(key)
457            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]:
480@pass_environment
481def do_min(
482    environment: "Environment",
483    value: "t.Iterable[V]",
484    case_sensitive: bool = False,
485    attribute: t.Optional[t.Union[str, int]] = None,
486) -> "t.Union[V, Undefined]":
487    """Return the smallest item from the sequence.
488
489    .. sourcecode:: jinja
490
491        {{ [1, 2, 3]|min }}
492            -> 1
493
494    :param case_sensitive: Treat upper and lower case strings as distinct.
495    :param attribute: Get the object with the min value of this attribute.
496    """
497    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]:
500@pass_environment
501def do_max(
502    environment: "Environment",
503    value: "t.Iterable[V]",
504    case_sensitive: bool = False,
505    attribute: t.Optional[t.Union[str, int]] = None,
506) -> "t.Union[V, Undefined]":
507    """Return the largest item from the sequence.
508
509    .. sourcecode:: jinja
510
511        {{ [1, 2, 3]|max }}
512            -> 3
513
514    :param case_sensitive: Treat upper and lower case strings as distinct.
515    :param attribute: Get the object with the max value of this attribute.
516    """
517    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:
520def do_default(
521    value: V,
522    default_value: V = "",  # type: ignore
523    boolean: bool = False,
524) -> V:
525    """If the value is undefined it will return the passed default value,
526    otherwise the value of the variable:
527
528    .. sourcecode:: jinja
529
530        {{ my_variable|default('my_variable is not defined') }}
531
532    This will output the value of ``my_variable`` if the variable was
533    defined, otherwise ``'my_variable is not defined'``. If you want
534    to use default with variables that evaluate to false you have to
535    set the second parameter to `true`:
536
537    .. sourcecode:: jinja
538
539        {{ ''|default('the string was empty', true) }}
540
541    .. versionchanged:: 2.11
542       It's now possible to configure the :class:`~jinja2.Environment` with
543       :class:`~jinja2.ChainableUndefined` to make the `default` filter work
544       on nested elements and attributes that may contain undefined values
545       in the chain without getting an :exc:`~jinja2.UndefinedError`.
546    """
547    if isinstance(value, Undefined) or (boolean and not value):
548        return default_value
549
550    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, d: str = '', attribute: Union[str, int, NoneType] = None) -> str:
553@pass_eval_context
554def sync_do_join(
555    eval_ctx: "EvalContext",
556    value: t.Iterable,
557    d: str = "",
558    attribute: t.Optional[t.Union[str, int]] = None,
559) -> str:
560    """Return a string which is the concatenation of the strings in the
561    sequence. The separator between elements is an empty string per
562    default, you can define it with the optional parameter:
563
564    .. sourcecode:: jinja
565
566        {{ [1, 2, 3]|join('|') }}
567            -> 1|2|3
568
569        {{ [1, 2, 3]|join }}
570            -> 123
571
572    It is also possible to join certain attributes of an object:
573
574    .. sourcecode:: jinja
575
576        {{ users|join(', ', attribute='username') }}
577
578    .. versionadded:: 2.6
579       The `attribute` parameter was added.
580    """
581    if attribute is not None:
582        value = map(make_attrgetter(eval_ctx.environment, attribute), value)
583
584    # no automatic escaping?  joining is a lot easier then
585    if not eval_ctx.autoescape:
586        return str(d).join(map(str, value))
587
588    # if the delimiter doesn't have an html representation we check
589    # if any of the items has.  If yes we do a coercion to Markup
590    if not hasattr(d, "__html__"):
591        value = list(value)
592        do_escape = False
593
594        for idx, item in enumerate(value):
595            if hasattr(item, "__html__"):
596                do_escape = True
597            else:
598                value[idx] = str(item)
599
600        if do_escape:
601            d = escape(d)
602        else:
603            d = str(d)
604
605        return d.join(value)
606
607    # no html involved, to normal joining
608    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, d: str = '', attribute: Union[str, int, NoneType] = None) -> str:
553@pass_eval_context
554def sync_do_join(
555    eval_ctx: "EvalContext",
556    value: t.Iterable,
557    d: str = "",
558    attribute: t.Optional[t.Union[str, int]] = None,
559) -> str:
560    """Return a string which is the concatenation of the strings in the
561    sequence. The separator between elements is an empty string per
562    default, you can define it with the optional parameter:
563
564    .. sourcecode:: jinja
565
566        {{ [1, 2, 3]|join('|') }}
567            -> 1|2|3
568
569        {{ [1, 2, 3]|join }}
570            -> 123
571
572    It is also possible to join certain attributes of an object:
573
574    .. sourcecode:: jinja
575
576        {{ users|join(', ', attribute='username') }}
577
578    .. versionadded:: 2.6
579       The `attribute` parameter was added.
580    """
581    if attribute is not None:
582        value = map(make_attrgetter(eval_ctx.environment, attribute), value)
583
584    # no automatic escaping?  joining is a lot easier then
585    if not eval_ctx.autoescape:
586        return str(d).join(map(str, value))
587
588    # if the delimiter doesn't have an html representation we check
589    # if any of the items has.  If yes we do a coercion to Markup
590    if not hasattr(d, "__html__"):
591        value = list(value)
592        do_escape = False
593
594        for idx, item in enumerate(value):
595            if hasattr(item, "__html__"):
596                do_escape = True
597            else:
598                value[idx] = str(item)
599
600        if do_escape:
601            d = escape(d)
602        else:
603            d = str(d)
604
605        return d.join(value)
606
607    # no html involved, to normal joining
608    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:
621def do_center(value: str, width: int = 80) -> str:
622    """Centers the value in a field of a given width."""
623    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]:
626@pass_environment
627def sync_do_first(
628    environment: "Environment", seq: "t.Iterable[V]"
629) -> "t.Union[V, Undefined]":
630    """Return the first item of a sequence."""
631    try:
632        return next(iter(seq))
633    except StopIteration:
634        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]:
626@pass_environment
627def sync_do_first(
628    environment: "Environment", seq: "t.Iterable[V]"
629) -> "t.Union[V, Undefined]":
630    """Return the first item of a sequence."""
631    try:
632        return next(iter(seq))
633    except StopIteration:
634        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]:
647@pass_environment
648def do_last(
649    environment: "Environment", seq: "t.Reversible[V]"
650) -> "t.Union[V, Undefined]":
651    """Return the last item of a sequence.
652
653    Note: Does not work with generators. You may want to explicitly
654    convert it to a list:
655
656    .. sourcecode:: jinja
657
658        {{ data | selectattr('name', '==', 'Jinja') | list | last }}
659    """
660    try:
661        return next(iter(reversed(seq)))
662    except StopIteration:
663        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]:
669@pass_context
670def do_random(context: "Context", seq: "t.Sequence[V]") -> "t.Union[V, Undefined]":
671    """Return a random item from the sequence."""
672    try:
673        return random.choice(seq)
674    except IndexError:
675        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:
678def do_filesizeformat(value: t.Union[str, float, int], binary: bool = False) -> str:
679    """Format the value like a 'human-readable' file size (i.e. 13 kB,
680    4.1 MB, 102 Bytes, etc).  Per default decimal prefixes are used (Mega,
681    Giga, etc.), if the second parameter is set to `True` the binary
682    prefixes are used (Mebi, Gibi).
683    """
684    bytes = float(value)
685    base = 1024 if binary else 1000
686    prefixes = [
687        ("KiB" if binary else "kB"),
688        ("MiB" if binary else "MB"),
689        ("GiB" if binary else "GB"),
690        ("TiB" if binary else "TB"),
691        ("PiB" if binary else "PB"),
692        ("EiB" if binary else "EB"),
693        ("ZiB" if binary else "ZB"),
694        ("YiB" if binary else "YB"),
695    ]
696
697    if bytes == 1:
698        return "1 Byte"
699    elif bytes < base:
700        return f"{int(bytes)} Bytes"
701    else:
702        for i, prefix in enumerate(prefixes):
703            unit = base ** (i + 2)
704
705            if bytes < unit:
706                return f"{base * bytes / unit:.1f} {prefix}"
707
708        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:
711def do_pprint(value: t.Any) -> str:
712    """Pretty print a variable. Useful for debugging."""
713    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:
719@pass_eval_context
720def do_urlize(
721    eval_ctx: "EvalContext",
722    value: str,
723    trim_url_limit: t.Optional[int] = None,
724    nofollow: bool = False,
725    target: t.Optional[str] = None,
726    rel: t.Optional[str] = None,
727    extra_schemes: t.Optional[t.Iterable[str]] = None,
728) -> str:
729    """Convert URLs in text into clickable links.
730
731    This may not recognize links in some situations. Usually, a more
732    comprehensive formatter, such as a Markdown library, is a better
733    choice.
734
735    Works on ``http://``, ``https://``, ``www.``, ``mailto:``, and email
736    addresses. Links with trailing punctuation (periods, commas, closing
737    parentheses) and leading punctuation (opening parentheses) are
738    recognized excluding the punctuation. Email addresses that include
739    header fields are not recognized (for example,
740    ``mailto:address@example.com?cc=copy@example.com``).
741
742    :param value: Original text containing URLs to link.
743    :param trim_url_limit: Shorten displayed URL values to this length.
744    :param nofollow: Add the ``rel=nofollow`` attribute to links.
745    :param target: Add the ``target`` attribute to links.
746    :param rel: Add the ``rel`` attribute to links.
747    :param extra_schemes: Recognize URLs that start with these schemes
748        in addition to the default behavior. Defaults to
749        ``env.policies["urlize.extra_schemes"]``, which defaults to no
750        extra schemes.
751
752    .. versionchanged:: 3.0
753        The ``extra_schemes`` parameter was added.
754
755    .. versionchanged:: 3.0
756        Generate ``https://`` links for URLs without a scheme.
757
758    .. versionchanged:: 3.0
759        The parsing rules were updated. Recognize email addresses with
760        or without the ``mailto:`` scheme. Validate IP addresses. Ignore
761        parentheses and brackets in more cases.
762
763    .. versionchanged:: 2.8
764       The ``target`` parameter was added.
765    """
766    policies = eval_ctx.environment.policies
767    rel_parts = set((rel or "").split())
768
769    if nofollow:
770        rel_parts.add("nofollow")
771
772    rel_parts.update((policies["urlize.rel"] or "").split())
773    rel = " ".join(sorted(rel_parts)) or None
774
775    if target is None:
776        target = policies["urlize.target"]
777
778    if extra_schemes is None:
779        extra_schemes = policies["urlize.extra_schemes"] or ()
780
781    for scheme in extra_schemes:
782        if _uri_scheme_re.fullmatch(scheme) is None:
783            raise FilterArgumentError(f"{scheme!r} is not a valid URI scheme prefix.")
784
785    rv = urlize(
786        value,
787        trim_url_limit=trim_url_limit,
788        rel=rel,
789        target=target,
790        extra_schemes=extra_schemes,
791    )
792
793    if eval_ctx.autoescape:
794        rv = Markup(rv)
795
796    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:
799def do_indent(
800    s: str, width: t.Union[int, str] = 4, first: bool = False, blank: bool = False
801) -> str:
802    """Return a copy of the string with each line indented by 4 spaces. The
803    first line and blank lines are not indented by default.
804
805    :param width: Number of spaces, or a string, to indent by.
806    :param first: Don't skip indenting the first line.
807    :param blank: Don't skip indenting empty lines.
808
809    .. versionchanged:: 3.0
810        ``width`` can be a string.
811
812    .. versionchanged:: 2.10
813        Blank lines are not indented by default.
814
815        Rename the ``indentfirst`` argument to ``first``.
816    """
817    if isinstance(width, str):
818        indention = width
819    else:
820        indention = " " * width
821
822    newline = "\n"
823
824    if isinstance(s, Markup):
825        indention = Markup(indention)
826        newline = Markup(newline)
827
828    s += newline  # this quirk is necessary for splitlines method
829
830    if blank:
831        rv = (newline + indention).join(s.splitlines())
832    else:
833        lines = s.splitlines()
834        rv = lines.pop(0)
835
836        if lines:
837            rv += newline + newline.join(
838                indention + line if line else line for line in lines
839            )
840
841    if first:
842        rv = indention + rv
843
844    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:
847@pass_environment
848def do_truncate(
849    env: "Environment",
850    s: str,
851    length: int = 255,
852    killwords: bool = False,
853    end: str = "...",
854    leeway: t.Optional[int] = None,
855) -> str:
856    """Return a truncated copy of the string. The length is specified
857    with the first parameter which defaults to ``255``. If the second
858    parameter is ``true`` the filter will cut the text at length. Otherwise
859    it will discard the last word. If the text was in fact
860    truncated it will append an ellipsis sign (``"..."``). If you want a
861    different ellipsis sign than ``"..."`` you can specify it using the
862    third parameter. Strings that only exceed the length by the tolerance
863    margin given in the fourth parameter will not be truncated.
864
865    .. sourcecode:: jinja
866
867        {{ "foo bar baz qux"|truncate(9) }}
868            -> "foo..."
869        {{ "foo bar baz qux"|truncate(9, True) }}
870            -> "foo ba..."
871        {{ "foo bar baz qux"|truncate(11) }}
872            -> "foo bar baz qux"
873        {{ "foo bar baz qux"|truncate(11, False, '...', 0) }}
874            -> "foo bar..."
875
876    The default leeway on newer Jinja versions is 5 and was 0 before but
877    can be reconfigured globally.
878    """
879    if leeway is None:
880        leeway = env.policies["truncate.leeway"]
881
882    assert length >= len(end), f"expected length >= {len(end)}, got {length}"
883    assert leeway >= 0, f"expected leeway >= 0, got {leeway}"
884
885    if len(s) <= length + leeway:
886        return s
887
888    if killwords:
889        return s[: length - len(end)] + end
890
891    result = s[: length - len(end)].rsplit(" ", 1)[0]
892    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:
895@pass_environment
896def do_wordwrap(
897    environment: "Environment",
898    s: str,
899    width: int = 79,
900    break_long_words: bool = True,
901    wrapstring: t.Optional[str] = None,
902    break_on_hyphens: bool = True,
903) -> str:
904    """Wrap a string to the given width. Existing newlines are treated
905    as paragraphs to be wrapped separately.
906
907    :param s: Original text to wrap.
908    :param width: Maximum length of wrapped lines.
909    :param break_long_words: If a word is longer than ``width``, break
910        it across lines.
911    :param break_on_hyphens: If a word contains hyphens, it may be split
912        across lines.
913    :param wrapstring: String to join each wrapped line. Defaults to
914        :attr:`Environment.newline_sequence`.
915
916    .. versionchanged:: 2.11
917        Existing newlines are treated as paragraphs wrapped separately.
918
919    .. versionchanged:: 2.11
920        Added the ``break_on_hyphens`` parameter.
921
922    .. versionchanged:: 2.7
923        Added the ``wrapstring`` parameter.
924    """
925    import textwrap
926
927    if wrapstring is None:
928        wrapstring = environment.newline_sequence
929
930    # textwrap.wrap doesn't consider existing newlines when wrapping.
931    # If the string has a newline before width, wrap will still insert
932    # a newline at width, resulting in a short line. Instead, split and
933    # wrap each paragraph individually.
934    return wrapstring.join(
935        [
936            wrapstring.join(
937                textwrap.wrap(
938                    line,
939                    width=width,
940                    expand_tabs=False,
941                    replace_whitespace=False,
942                    break_long_words=break_long_words,
943                    break_on_hyphens=break_on_hyphens,
944                )
945            )
946            for line in s.splitlines()
947        ]
948    )

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:
954def do_wordcount(s: str) -> int:
955    """Count the words in that string."""
956    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:
959def do_int(value: t.Any, default: int = 0, base: int = 10) -> int:
960    """Convert the value into an integer. If the
961    conversion doesn't work it will return ``0``. You can
962    override this default using the first parameter. You
963    can also override the default base (10) in the second
964    parameter, which handles input with prefixes such as
965    0b, 0o and 0x for bases 2, 8 and 16 respectively.
966    The base is ignored for decimal numbers and non-string values.
967    """
968    try:
969        if isinstance(value, str):
970            return int(value, base)
971
972        return int(value)
973    except (TypeError, ValueError):
974        # this quirk is necessary so that "42.23"|int gives 42.
975        try:
976            return int(float(value))
977        except (TypeError, ValueError):
978            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:
981def do_float(value: t.Any, default: float = 0.0) -> float:
982    """Convert the value into a floating point number. If the
983    conversion doesn't work it will return ``0.0``. You can
984    override this default using the first parameter.
985    """
986    try:
987        return float(value)
988    except (TypeError, ValueError):
989        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:
 992def do_format(value: str, *args: t.Any, **kwargs: t.Any) -> str:
 993    """Apply the given values to a `printf-style`_ format string, like
 994    ``string % values``.
 995
 996    .. sourcecode:: jinja
 997
 998        {{ "%s, %s!"|format(greeting, name) }}
 999        Hello, World!
1000
1001    In most cases it should be more convenient and efficient to use the
1002    ``%`` operator or :meth:`str.format`.
1003
1004    .. code-block:: text
1005
1006        {{ "%s, %s!" % (greeting, name) }}
1007        {{ "{}, {}!".format(greeting, name) }}
1008
1009    .. _printf-style: https://docs.python.org/library/stdtypes.html
1010        #printf-style-string-formatting
1011    """
1012    if args and kwargs:
1013        raise FilterArgumentError(
1014            "can't handle positional and keyword arguments at the same time"
1015        )
1016
1017    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:
1020def do_trim(value: str, chars: t.Optional[str] = None) -> str:
1021    """Strip leading and trailing characters, by default whitespace."""
1022    return soft_str(value).strip(chars)

Strip leading and trailing characters, by default whitespace.

def do_striptags(value: Union[str, jinja2.filters.HasHTML]) -> str:
1025def do_striptags(value: "t.Union[str, HasHTML]") -> str:
1026    """Strip SGML/XML tags and replace adjacent whitespace by one space."""
1027    if hasattr(value, "__html__"):
1028        value = t.cast("HasHTML", value).__html__()
1029
1030    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]]:
1033def sync_do_slice(
1034    value: "t.Collection[V]", slices: int, fill_with: "t.Optional[V]" = None
1035) -> "t.Iterator[t.List[V]]":
1036    """Slice an iterator and return a list of lists containing
1037    those items. Useful if you want to create a div containing
1038    three ul tags that represent columns:
1039
1040    .. sourcecode:: html+jinja
1041
1042        <div class="columnwrapper">
1043          {%- for column in items|slice(3) %}
1044            <ul class="column-{{ loop.index }}">
1045            {%- for item in column %}
1046              <li>{{ item }}</li>
1047            {%- endfor %}
1048            </ul>
1049          {%- endfor %}
1050        </div>
1051
1052    If you pass it a second argument it's used to fill missing
1053    values on the last iteration.
1054    """
1055    seq = list(value)
1056    length = len(seq)
1057    items_per_slice = length // slices
1058    slices_with_extra = length % slices
1059    offset = 0
1060
1061    for slice_number in range(slices):
1062        start = offset + slice_number * items_per_slice
1063
1064        if slice_number < slices_with_extra:
1065            offset += 1
1066
1067        end = offset + (slice_number + 1) * items_per_slice
1068        tmp = seq[start:end]
1069
1070        if fill_with is not None and slice_number >= slices_with_extra:
1071            tmp.append(fill_with)
1072
1073        yield tmp

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

.. sourcecode:: html+jinja

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

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

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

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

.. sourcecode:: html+jinja

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

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

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

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

.. sourcecode:: html+jinja

<table>
{%- for row in items|batch(3, '&nbsp;') %}
  <tr>
  {%- for column in row %}
    <td>{{ column }}</td>
  {%- endfor %}
  </tr>
{%- endfor %}
</table>
def do_round( value: float, precision: int = 0, method: Literal['common', 'ceil', 'floor'] = 'common') -> float:
1122def do_round(
1123    value: float,
1124    precision: int = 0,
1125    method: 'te.Literal["common", "ceil", "floor"]' = "common",
1126) -> float:
1127    """Round the number to a given precision. The first
1128    parameter specifies the precision (default is ``0``), the
1129    second the rounding method:
1130
1131    - ``'common'`` rounds either up or down
1132    - ``'ceil'`` always rounds up
1133    - ``'floor'`` always rounds down
1134
1135    If you don't specify a method ``'common'`` is used.
1136
1137    .. sourcecode:: jinja
1138
1139        {{ 42.55|round }}
1140            -> 43.0
1141        {{ 42.55|round(1, 'floor') }}
1142            -> 42.5
1143
1144    Note that even if rounded to 0 precision, a float is returned.  If
1145    you need a real integer, pipe it through `int`:
1146
1147    .. sourcecode:: jinja
1148
1149        {{ 42.55|round|int }}
1150            -> 43
1151    """
1152    if method not in {"common", "ceil", "floor"}:
1153        raise FilterArgumentError("method must be common, ceil or floor")
1154
1155    if method == "common":
1156        return round(value, precision)
1157
1158    func = getattr(math, method)
1159    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]:
1175@pass_environment
1176def sync_do_groupby(
1177    environment: "Environment",
1178    value: "t.Iterable[V]",
1179    attribute: t.Union[str, int],
1180    default: t.Optional[t.Any] = None,
1181    case_sensitive: bool = False,
1182) -> "t.List[_GroupTuple]":
1183    """Group a sequence of objects by an attribute using Python's
1184    :func:`itertools.groupby`. The attribute can use dot notation for
1185    nested access, like ``"address.city"``. Unlike Python's ``groupby``,
1186    the values are sorted first so only one group is returned for each
1187    unique value.
1188
1189    For example, a list of ``User`` objects with a ``city`` attribute
1190    can be rendered in groups. In this example, ``grouper`` refers to
1191    the ``city`` value of the group.
1192
1193    .. sourcecode:: html+jinja
1194
1195        <ul>{% for city, items in users|groupby("city") %}
1196          <li>{{ city }}
1197            <ul>{% for user in items %}
1198              <li>{{ user.name }}
1199            {% endfor %}</ul>
1200          </li>
1201        {% endfor %}</ul>
1202
1203    ``groupby`` yields namedtuples of ``(grouper, list)``, which
1204    can be used instead of the tuple unpacking above. ``grouper`` is the
1205    value of the attribute, and ``list`` is the items with that value.
1206
1207    .. sourcecode:: html+jinja
1208
1209        <ul>{% for group in users|groupby("city") %}
1210          <li>{{ group.grouper }}: {{ group.list|join(", ") }}
1211        {% endfor %}</ul>
1212
1213    You can specify a ``default`` value to use if an object in the list
1214    does not have the given attribute.
1215
1216    .. sourcecode:: jinja
1217
1218        <ul>{% for city, items in users|groupby("city", default="NY") %}
1219          <li>{{ city }}: {{ items|map(attribute="name")|join(", ") }}</li>
1220        {% endfor %}</ul>
1221
1222    Like the :func:`~jinja-filters.sort` filter, sorting and grouping is
1223    case-insensitive by default. The ``key`` for each group will have
1224    the case of the first item in that group of values. For example, if
1225    a list of users has cities ``["CA", "NY", "ca"]``, the "CA" group
1226    will have two values. This can be disabled by passing
1227    ``case_sensitive=True``.
1228
1229    .. versionchanged:: 3.1
1230        Added the ``case_sensitive`` parameter. Sorting and grouping is
1231        case-insensitive by default, matching other filters that do
1232        comparisons.
1233
1234    .. versionchanged:: 3.0
1235        Added the ``default`` parameter.
1236
1237    .. versionchanged:: 2.6
1238        The attribute supports dot notation for nested access.
1239    """
1240    expr = make_attrgetter(
1241        environment,
1242        attribute,
1243        postprocess=ignore_case if not case_sensitive else None,
1244        default=default,
1245    )
1246    out = [
1247        _GroupTuple(key, list(values))
1248        for key, values in groupby(sorted(value, key=expr), expr)
1249    ]
1250
1251    if not case_sensitive:
1252        # Return the real key from the first value instead of the lowercase key.
1253        output_expr = make_attrgetter(environment, attribute, default=default)
1254        out = [_GroupTuple(output_expr(values[0]), values) for _, values in out]
1255
1256    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]:
1175@pass_environment
1176def sync_do_groupby(
1177    environment: "Environment",
1178    value: "t.Iterable[V]",
1179    attribute: t.Union[str, int],
1180    default: t.Optional[t.Any] = None,
1181    case_sensitive: bool = False,
1182) -> "t.List[_GroupTuple]":
1183    """Group a sequence of objects by an attribute using Python's
1184    :func:`itertools.groupby`. The attribute can use dot notation for
1185    nested access, like ``"address.city"``. Unlike Python's ``groupby``,
1186    the values are sorted first so only one group is returned for each
1187    unique value.
1188
1189    For example, a list of ``User`` objects with a ``city`` attribute
1190    can be rendered in groups. In this example, ``grouper`` refers to
1191    the ``city`` value of the group.
1192
1193    .. sourcecode:: html+jinja
1194
1195        <ul>{% for city, items in users|groupby("city") %}
1196          <li>{{ city }}
1197            <ul>{% for user in items %}
1198              <li>{{ user.name }}
1199            {% endfor %}</ul>
1200          </li>
1201        {% endfor %}</ul>
1202
1203    ``groupby`` yields namedtuples of ``(grouper, list)``, which
1204    can be used instead of the tuple unpacking above. ``grouper`` is the
1205    value of the attribute, and ``list`` is the items with that value.
1206
1207    .. sourcecode:: html+jinja
1208
1209        <ul>{% for group in users|groupby("city") %}
1210          <li>{{ group.grouper }}: {{ group.list|join(", ") }}
1211        {% endfor %}</ul>
1212
1213    You can specify a ``default`` value to use if an object in the list
1214    does not have the given attribute.
1215
1216    .. sourcecode:: jinja
1217
1218        <ul>{% for city, items in users|groupby("city", default="NY") %}
1219          <li>{{ city }}: {{ items|map(attribute="name")|join(", ") }}</li>
1220        {% endfor %}</ul>
1221
1222    Like the :func:`~jinja-filters.sort` filter, sorting and grouping is
1223    case-insensitive by default. The ``key`` for each group will have
1224    the case of the first item in that group of values. For example, if
1225    a list of users has cities ``["CA", "NY", "ca"]``, the "CA" group
1226    will have two values. This can be disabled by passing
1227    ``case_sensitive=True``.
1228
1229    .. versionchanged:: 3.1
1230        Added the ``case_sensitive`` parameter. Sorting and grouping is
1231        case-insensitive by default, matching other filters that do
1232        comparisons.
1233
1234    .. versionchanged:: 3.0
1235        Added the ``default`` parameter.
1236
1237    .. versionchanged:: 2.6
1238        The attribute supports dot notation for nested access.
1239    """
1240    expr = make_attrgetter(
1241        environment,
1242        attribute,
1243        postprocess=ignore_case if not case_sensitive else None,
1244        default=default,
1245    )
1246    out = [
1247        _GroupTuple(key, list(values))
1248        for key, values in groupby(sorted(value, key=expr), expr)
1249    ]
1250
1251    if not case_sensitive:
1252        # Return the real key from the first value instead of the lowercase key.
1253        output_expr = make_attrgetter(environment, attribute, default=default)
1254        out = [_GroupTuple(output_expr(values[0]), values) for _, values in out]
1255
1256    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:
1286@pass_environment
1287def sync_do_sum(
1288    environment: "Environment",
1289    iterable: "t.Iterable[V]",
1290    attribute: t.Optional[t.Union[str, int]] = None,
1291    start: V = 0,  # type: ignore
1292) -> V:
1293    """Returns the sum of a sequence of numbers plus the value of parameter
1294    'start' (which defaults to 0).  When the sequence is empty it returns
1295    start.
1296
1297    It is also possible to sum up only certain attributes:
1298
1299    .. sourcecode:: jinja
1300
1301        Total: {{ items|sum(attribute='price') }}
1302
1303    .. versionchanged:: 2.6
1304       The ``attribute`` parameter was added to allow summing up over
1305       attributes.  Also the ``start`` parameter was moved on to the right.
1306    """
1307    if attribute is not None:
1308        iterable = map(make_attrgetter(environment, attribute), iterable)
1309
1310    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:
1286@pass_environment
1287def sync_do_sum(
1288    environment: "Environment",
1289    iterable: "t.Iterable[V]",
1290    attribute: t.Optional[t.Union[str, int]] = None,
1291    start: V = 0,  # type: ignore
1292) -> V:
1293    """Returns the sum of a sequence of numbers plus the value of parameter
1294    'start' (which defaults to 0).  When the sequence is empty it returns
1295    start.
1296
1297    It is also possible to sum up only certain attributes:
1298
1299    .. sourcecode:: jinja
1300
1301        Total: {{ items|sum(attribute='price') }}
1302
1303    .. versionchanged:: 2.6
1304       The ``attribute`` parameter was added to allow summing up over
1305       attributes.  Also the ``start`` parameter was moved on to the right.
1306    """
1307    if attribute is not None:
1308        iterable = map(make_attrgetter(environment, attribute), iterable)
1309
1310    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]:
1335def sync_do_list(value: "t.Iterable[V]") -> "t.List[V]":
1336    """Convert the value into a list.  If it was a string the returned list
1337    will be a list of characters.
1338    """
1339    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]:
1335def sync_do_list(value: "t.Iterable[V]") -> "t.List[V]":
1336    """Convert the value into a list.  If it was a string the returned list
1337    will be a list of characters.
1338    """
1339    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:
1347def do_mark_safe(value: str) -> Markup:
1348    """Mark the value as safe which means that in an environment with automatic
1349    escaping enabled this variable will not be escaped.
1350    """
1351    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:
1354def do_mark_unsafe(value: str) -> str:
1355    """Mark a value as unsafe.  This is the reverse operation for :func:`safe`."""
1356    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]]:
1369def do_reverse(value: t.Union[str, t.Iterable[V]]) -> t.Union[str, t.Iterable[V]]:
1370    """Reverse the object or return an iterator that iterates over it the other
1371    way round.
1372    """
1373    if isinstance(value, str):
1374        return value[::-1]
1375
1376    try:
1377        return reversed(value)  # type: ignore
1378    except TypeError:
1379        try:
1380            rv = list(value)
1381            rv.reverse()
1382            return rv
1383        except TypeError as e:
1384            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]:
1387@pass_environment
1388def do_attr(
1389    environment: "Environment", obj: t.Any, name: str
1390) -> t.Union[Undefined, t.Any]:
1391    """Get an attribute of an object.  ``foo|attr("bar")`` works like
1392    ``foo.bar`` just that always an attribute is returned and items are not
1393    looked up.
1394
1395    See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details.
1396    """
1397    try:
1398        name = str(name)
1399    except UnicodeError:
1400        pass
1401    else:
1402        try:
1403            value = getattr(obj, name)
1404        except AttributeError:
1405            pass
1406        else:
1407            if environment.sandboxed:
1408                environment = t.cast("SandboxedEnvironment", environment)
1409
1410                if not environment.is_safe_attribute(obj, name, value):
1411                    return environment.unsafe_undefined(obj, name)
1412
1413            return value
1414
1415    return environment.undefined(obj=obj, name=name)

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

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

@pass_context
def sync_do_map( context: jinja2.runtime.Context, value: Iterable, *args: Any, **kwargs: Any) -> Iterable:
1436@pass_context
1437def sync_do_map(
1438    context: "Context", value: t.Iterable, *args: t.Any, **kwargs: t.Any
1439) -> t.Iterable:
1440    """Applies a filter on a sequence of objects or looks up an attribute.
1441    This is useful when dealing with lists of objects but you are really
1442    only interested in a certain value of it.
1443
1444    The basic usage is mapping on an attribute.  Imagine you have a list
1445    of users but you are only interested in a list of usernames:
1446
1447    .. sourcecode:: jinja
1448
1449        Users on this page: {{ users|map(attribute='username')|join(', ') }}
1450
1451    You can specify a ``default`` value to use if an object in the list
1452    does not have the given attribute.
1453
1454    .. sourcecode:: jinja
1455
1456        {{ users|map(attribute="username", default="Anonymous")|join(", ") }}
1457
1458    Alternatively you can let it invoke a filter by passing the name of the
1459    filter and the arguments afterwards.  A good example would be applying a
1460    text conversion filter on a sequence:
1461
1462    .. sourcecode:: jinja
1463
1464        Users on this page: {{ titles|map('lower')|join(', ') }}
1465
1466    Similar to a generator comprehension such as:
1467
1468    .. code-block:: python
1469
1470        (u.username for u in users)
1471        (getattr(u, "username", "Anonymous") for u in users)
1472        (do_lower(x) for x in titles)
1473
1474    .. versionchanged:: 2.11.0
1475        Added the ``default`` parameter.
1476
1477    .. versionadded:: 2.7
1478    """
1479    if value:
1480        func = prepare_map(context, args, kwargs)
1481
1482        for item in value:
1483            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, *args: Any, **kwargs: Any) -> Iterable:
1436@pass_context
1437def sync_do_map(
1438    context: "Context", value: t.Iterable, *args: t.Any, **kwargs: t.Any
1439) -> t.Iterable:
1440    """Applies a filter on a sequence of objects or looks up an attribute.
1441    This is useful when dealing with lists of objects but you are really
1442    only interested in a certain value of it.
1443
1444    The basic usage is mapping on an attribute.  Imagine you have a list
1445    of users but you are only interested in a list of usernames:
1446
1447    .. sourcecode:: jinja
1448
1449        Users on this page: {{ users|map(attribute='username')|join(', ') }}
1450
1451    You can specify a ``default`` value to use if an object in the list
1452    does not have the given attribute.
1453
1454    .. sourcecode:: jinja
1455
1456        {{ users|map(attribute="username", default="Anonymous")|join(", ") }}
1457
1458    Alternatively you can let it invoke a filter by passing the name of the
1459    filter and the arguments afterwards.  A good example would be applying a
1460    text conversion filter on a sequence:
1461
1462    .. sourcecode:: jinja
1463
1464        Users on this page: {{ titles|map('lower')|join(', ') }}
1465
1466    Similar to a generator comprehension such as:
1467
1468    .. code-block:: python
1469
1470        (u.username for u in users)
1471        (getattr(u, "username", "Anonymous") for u in users)
1472        (do_lower(x) for x in titles)
1473
1474    .. versionchanged:: 2.11.0
1475        Added the ``default`` parameter.
1476
1477    .. versionadded:: 2.7
1478    """
1479    if value:
1480        func = prepare_map(context, args, kwargs)
1481
1482        for item in value:
1483            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]:
1522@pass_context
1523def sync_do_select(
1524    context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
1525) -> "t.Iterator[V]":
1526    """Filters a sequence of objects by applying a test to each object,
1527    and only selecting the objects with the test succeeding.
1528
1529    If no test is specified, each object will be evaluated as a boolean.
1530
1531    Example usage:
1532
1533    .. sourcecode:: jinja
1534
1535        {{ numbers|select("odd") }}
1536        {{ numbers|select("odd") }}
1537        {{ numbers|select("divisibleby", 3) }}
1538        {{ numbers|select("lessthan", 42) }}
1539        {{ strings|select("equalto", "mystring") }}
1540
1541    Similar to a generator comprehension such as:
1542
1543    .. code-block:: python
1544
1545        (n for n in numbers if test_odd(n))
1546        (n for n in numbers if test_divisibleby(n, 3))
1547
1548    .. versionadded:: 2.7
1549    """
1550    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]:
1522@pass_context
1523def sync_do_select(
1524    context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
1525) -> "t.Iterator[V]":
1526    """Filters a sequence of objects by applying a test to each object,
1527    and only selecting the objects with the test succeeding.
1528
1529    If no test is specified, each object will be evaluated as a boolean.
1530
1531    Example usage:
1532
1533    .. sourcecode:: jinja
1534
1535        {{ numbers|select("odd") }}
1536        {{ numbers|select("odd") }}
1537        {{ numbers|select("divisibleby", 3) }}
1538        {{ numbers|select("lessthan", 42) }}
1539        {{ strings|select("equalto", "mystring") }}
1540
1541    Similar to a generator comprehension such as:
1542
1543    .. code-block:: python
1544
1545        (n for n in numbers if test_odd(n))
1546        (n for n in numbers if test_divisibleby(n, 3))
1547
1548    .. versionadded:: 2.7
1549    """
1550    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]:
1563@pass_context
1564def sync_do_reject(
1565    context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
1566) -> "t.Iterator[V]":
1567    """Filters a sequence of objects by applying a test to each object,
1568    and rejecting the objects with the test succeeding.
1569
1570    If no test is specified, each object will be evaluated as a boolean.
1571
1572    Example usage:
1573
1574    .. sourcecode:: jinja
1575
1576        {{ numbers|reject("odd") }}
1577
1578    Similar to a generator comprehension such as:
1579
1580    .. code-block:: python
1581
1582        (n for n in numbers if not test_odd(n))
1583
1584    .. versionadded:: 2.7
1585    """
1586    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]:
1563@pass_context
1564def sync_do_reject(
1565    context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
1566) -> "t.Iterator[V]":
1567    """Filters a sequence of objects by applying a test to each object,
1568    and rejecting the objects with the test succeeding.
1569
1570    If no test is specified, each object will be evaluated as a boolean.
1571
1572    Example usage:
1573
1574    .. sourcecode:: jinja
1575
1576        {{ numbers|reject("odd") }}
1577
1578    Similar to a generator comprehension such as:
1579
1580    .. code-block:: python
1581
1582        (n for n in numbers if not test_odd(n))
1583
1584    .. versionadded:: 2.7
1585    """
1586    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]:
1599@pass_context
1600def sync_do_selectattr(
1601    context: "Context", value: "t.Iterable[V]", *args: t.Any, **kwargs: t.Any
1602) -> "t.Iterator[V]":
1603    """Filters a sequence of objects by applying a test to the specified
1604    attribute of each object, and only selecting the objects with the
1605    test succeeding.
1606
1607    If no test is specified, the attribute's value will be evaluated as
1608    a boolean.
1609
1610    Example usage:
1611
1612    .. sourcecode:: jinja
1613
1614        {{ users|selectattr("is_active") }}
1615        {{ users|selectattr("email", "none") }}
1616
1617    Similar to a generator comprehension such as:
1618
1619    .. code-block:: python
1620
1621        (u for user in users if user.is_active)
1622        (u for user in users if test_none(user.email))
1623
1624    .. versionadded:: 2.7
1625    """
1626    return select_or_reject(context, value, args, kwargs, lambda x: x, True)

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

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

Example usage:

.. sourcecode:: jinja

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

Similar to a generator comprehension such as:

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

New in version 2.7.

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

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

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

Example usage:

.. sourcecode:: jinja

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

Similar to a generator comprehension such as:

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

New in version 2.7.

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

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

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

.. sourcecode:: jinja

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

Similar to a generator comprehension such as:

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

New in version 2.7.

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

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

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

.. sourcecode:: jinja

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

Similar to a generator comprehension such as:

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

New in version 2.7.

@pass_eval_context
def do_tojson( eval_ctx: jinja2.nodes.EvalContext, value: Any, indent: Optional[int] = None) -> markupsafe.Markup:
1677@pass_eval_context
1678def do_tojson(
1679    eval_ctx: "EvalContext", value: t.Any, indent: t.Optional[int] = None
1680) -> Markup:
1681    """Serialize an object to a string of JSON, and mark it safe to
1682    render in HTML. This filter is only for use in HTML documents.
1683
1684    The returned string is safe to render in HTML documents and
1685    ``<script>`` tags. The exception is in HTML attributes that are
1686    double quoted; either use single quotes or the ``|forceescape``
1687    filter.
1688
1689    :param value: The object to serialize to JSON.
1690    :param indent: The ``indent`` parameter passed to ``dumps``, for
1691        pretty-printing the value.
1692
1693    .. versionadded:: 2.9
1694    """
1695    policies = eval_ctx.environment.policies
1696    dumps = policies["json.dumps_function"]
1697    kwargs = policies["json.dumps_kwargs"]
1698
1699    if indent is not None:
1700        kwargs = kwargs.copy()
1701        kwargs["indent"] = indent
1702
1703    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, kwargs: Dict[str, Any]) -> Callable[[Any], Any]:
1706def prepare_map(
1707    context: "Context", args: t.Tuple, kwargs: t.Dict[str, t.Any]
1708) -> t.Callable[[t.Any], t.Any]:
1709    if not args and "attribute" in kwargs:
1710        attribute = kwargs.pop("attribute")
1711        default = kwargs.pop("default", None)
1712
1713        if kwargs:
1714            raise FilterArgumentError(
1715                f"Unexpected keyword argument {next(iter(kwargs))!r}"
1716            )
1717
1718        func = make_attrgetter(context.environment, attribute, default=default)
1719    else:
1720        try:
1721            name = args[0]
1722            args = args[1:]
1723        except LookupError:
1724            raise FilterArgumentError("map requires a filter argument") from None
1725
1726        def func(item: t.Any) -> t.Any:
1727            return context.environment.call_filter(
1728                name, item, args, kwargs, context=context
1729            )
1730
1731    return func
def prepare_select_or_reject( context: jinja2.runtime.Context, args: Tuple, kwargs: Dict[str, Any], modfunc: Callable[[Any], Any], lookup_attr: bool) -> Callable[[Any], Any]:
1734def prepare_select_or_reject(
1735    context: "Context",
1736    args: t.Tuple,
1737    kwargs: t.Dict[str, t.Any],
1738    modfunc: t.Callable[[t.Any], t.Any],
1739    lookup_attr: bool,
1740) -> t.Callable[[t.Any], t.Any]:
1741    if lookup_attr:
1742        try:
1743            attr = args[0]
1744        except LookupError:
1745            raise FilterArgumentError("Missing parameter for attribute name") from None
1746
1747        transfunc = make_attrgetter(context.environment, attr)
1748        off = 1
1749    else:
1750        off = 0
1751
1752        def transfunc(x: V) -> V:
1753            return x
1754
1755    try:
1756        name = args[off]
1757        args = args[1 + off :]
1758
1759        def func(item: t.Any) -> t.Any:
1760            return context.environment.call_test(name, item, args, kwargs)
1761
1762    except LookupError:
1763        func = bool  # type: ignore
1764
1765    return lambda item: modfunc(func(transfunc(item)))
def select_or_reject( context: jinja2.runtime.Context, value: Iterable[~V], args: Tuple, kwargs: Dict[str, Any], modfunc: Callable[[Any], Any], lookup_attr: bool) -> Iterator[~V]:
1768def select_or_reject(
1769    context: "Context",
1770    value: "t.Iterable[V]",
1771    args: t.Tuple,
1772    kwargs: t.Dict[str, t.Any],
1773    modfunc: t.Callable[[t.Any], t.Any],
1774    lookup_attr: bool,
1775) -> "t.Iterator[V]":
1776    if value:
1777        func = prepare_select_or_reject(context, args, kwargs, modfunc, lookup_attr)
1778
1779        for item in value:
1780            if func(item):
1781                yield item
async def async_select_or_reject( context: jinja2.runtime.Context, value: Union[AsyncIterable[~V], Iterable[~V]], args: Tuple, kwargs: Dict[str, Any], modfunc: Callable[[Any], Any], lookup_attr: bool) -> AsyncIterator[~V]:
1784async def async_select_or_reject(
1785    context: "Context",
1786    value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
1787    args: t.Tuple,
1788    kwargs: t.Dict[str, t.Any],
1789    modfunc: t.Callable[[t.Any], t.Any],
1790    lookup_attr: bool,
1791) -> "t.AsyncIterator[V]":
1792    if value:
1793        func = prepare_select_or_reject(context, args, kwargs, modfunc, lookup_attr)
1794
1795        async for item in auto_aiter(value):
1796            if func(item):
1797                yield item
FILTERS = {'abs': <built-in function abs>, 'attr': <function do_attr>, 'batch': <function do_batch>, 'capitalize': <function do_capitalize>, 'center': <function do_center>, 'count': <built-in function len>, 'd': <function do_default>, 'default': <function do_default>, 'dictsort': <function do_dictsort>, 'e': <built-in function escape>, 'escape': <built-in function escape>, 'filesizeformat': <function do_filesizeformat>, 'first': <function do_first>, 'float': <function do_float>, 'forceescape': <function do_forceescape>, 'format': <function do_format>, 'groupby': <function do_groupby>, 'indent': <function do_indent>, 'int': <function do_int>, 'join': <function do_join>, 'last': <function do_last>, 'length': <built-in function len>, 'list': <function do_list>, 'lower': <function do_lower>, 'items': <function do_items>, 'map': <function do_map>, 'min': <function do_min>, 'max': <function do_max>, 'pprint': <function do_pprint>, 'random': <function do_random>, 'reject': <function do_reject>, 'rejectattr': <function do_rejectattr>, 'replace': <function do_replace>, 'reverse': <function do_reverse>, 'round': <function do_round>, 'safe': <function do_mark_safe>, 'select': <function do_select>, 'selectattr': <function do_selectattr>, 'slice': <function do_slice>, 'sort': <function do_sort>, 'string': <built-in function soft_str>, 'striptags': <function do_striptags>, 'sum': <function do_sum>, 'title': <function do_title>, 'trim': <function do_trim>, 'truncate': <function do_truncate>, 'unique': <function do_unique>, 'upper': <function do_upper>, 'urlencode': <function do_urlencode>, 'urlize': <function do_urlize>, 'wordcount': <function do_wordcount>, 'wordwrap': <function do_wordwrap>, 'xmlattr': <function do_xmlattr>, 'tojson': <function do_tojson>}