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}
1855