1 """Built-in template filters used with the ``|`` operator."""
7 from collections
import abc
8 from itertools
import chain
9 from itertools
import groupby
11 from markupsafe
import escape
12 from markupsafe
import Markup
13 from markupsafe
import soft_str
15 from .async_utils
import async_variant
16 from .async_utils
import auto_aiter
17 from .async_utils
import auto_await
18 from .async_utils
import auto_to_list
19 from .exceptions
import FilterArgumentError
20 from .runtime
import Undefined
21 from .utils
import htmlsafe_json_dumps
22 from .utils
import pass_context
23 from .utils
import pass_environment
24 from .utils
import pass_eval_context
25 from .utils
import pformat
26 from .utils
import url_quote
27 from .utils
import urlize
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
36 class HasHTML(te
.Protocol
):
37 def __html__(self
) -> str:
41 F
= t
.TypeVar("F", bound
=t
.Callable
[..., t
.Any
])
46 def 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())
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.
66 parts
= _prepare_attribute_parts(attribute
)
68 def attrgetter(item
: t
.Any
) -> t
.Any
:
70 item
= environment
.getitem(item
, part
)
72 if default
is not None and isinstance(item
, Undefined
):
75 if postprocess
is not None:
76 item
= postprocess(item
)
83 def 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.
93 The value returned by the returned callable is a list of extracted
96 Examples of attribute: "attr1,attr2", "attr1.inner1.0,attr2.inner2.0", etc.
98 if isinstance(attribute
, str):
99 split
: t
.Sequence
[t
.Union
[str, int, None]] = attribute
.split(",")
103 parts
= [_prepare_attribute_parts(item
) for item
in split
]
105 def attrgetter(item
: t
.Any
) -> t
.List
[t
.Any
]:
106 items
= [None] * len(parts
)
108 for i
, attribute_part
in enumerate(parts
):
111 for part
in attribute_part
:
112 item_i
= environment
.getitem(item_i
, part
)
114 if postprocess
is not None:
115 item_i
= postprocess(item_i
)
124 def _prepare_attribute_parts(
125 attr
: t
.Optional
[t
.Union
[str, int]]
126 ) -> t
.List
[t
.Union
[str, int]]:
130 if isinstance(attr
, str):
131 return [int(x
) if x
.isdigit() else x
for x
in attr
.split(".")]
136 def 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
__()
141 return escape(str(value
))
145 value
: t
.Union
[str, t
.Mapping
[str, t
.Any
], t
.Iterable
[t
.Tuple
[str, t
.Any
]]]
147 """Quote data for use in a URL path or query using UTF-8.
149 Basic wrapper around :func:`urllib.parse.quote` when given a
150 string, or :func:`urllib.parse.urlencode` for a dict or iterable.
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
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.
160 .. versionadded:: 2.7
162 if isinstance(value
, str) or not isinstance(value
, abc
.Iterable
):
163 return url_quote(value
)
165 if isinstance(value
, dict):
166 items
: t
.Iterable
[t
.Tuple
[str, t
.Any
]] = value
.items()
168 items
= value
# type: ignore
171 f
"{url_quote(k, for_qs=True)}={url_quote(v, for_qs=True)}" for k
, v
in items
177 eval_ctx
: "EvalContext", s
: str, old
: str, new
: str, count
: t
.Optional
[int] = None
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:
185 .. sourcecode:: jinja
187 {{ "Hello World"|replace("Hello", "Goodbye") }}
190 {{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
191 -> d'oh, d'oh, aaargh
196 if not eval_ctx
.autoescape
:
197 return str(s
).replace(str(old
), str(new
), count
)
200 hasattr(old
, "__html__")
201 or hasattr(new
, "__html__")
202 and not hasattr(s
, "__html__")
208 return s
.replace(soft_str(old
), soft_str(new
), count
)
211 def do_upper(s
: str) -> str:
212 """Convert a value to uppercase."""
213 return soft_str(s
).upper()
216 def do_lower(s
: str) -> str:
217 """Convert a value to lowercase."""
218 return soft_str(s
).lower()
221 def 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.
224 ``x|items`` is the same as ``x.items()``, except if ``x`` is
225 undefined an empty iterator is returned.
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.
231 .. code-block:: html+jinja
234 {% for key, value in my_dict|items %}
240 .. versionadded:: 3.1
242 if isinstance(value
, Undefined
):
245 if not isinstance(value
, abc
.Mapping
):
246 raise TypeError("Can only get item pairs from a mapping.")
248 yield from value
.items()
253 eval_ctx
: "EvalContext", d
: t
.Mapping
[str, t
.Any
], autospace
: bool = True
255 """Create an SGML/XML attribute string based on the items in a dict.
256 All values that are neither `none` nor `undefined` are automatically
259 .. sourcecode:: html+jinja
261 <ul{{ {'class': 'my_list', 'missing': none,
262 'id': 'list-%d'|format(variable)}|xmlattr }}>
266 Results in something like this:
270 <ul class="my_list" id="list-42">
274 As you can see it automatically prepends a space in front of the item
275 if the filter returned something unless the second parameter is false.
278 f
'{escape(key)}="{escape(value)}"'
279 for key
, value
in d
.items()
280 if value
is not None and not isinstance(value
, Undefined
)
286 if eval_ctx
.autoescape
:
292 def do_capitalize(s
: str) -> str:
293 """Capitalize a value. The first character will be uppercase, all others
296 return soft_str(s
).capitalize()
299 _word_beginning_split_re
= re
.compile(r
"([-\s({\[<]+)")
302 def do_title(s
: str) -> str:
303 """Return a titlecased version of the value. I.e. words will start with
304 uppercase letters, all remaining characters are lowercase.
308 item
[0].upper() + item
[1:].lower()
309 for item
in _word_beginning_split_re
.split(soft_str(s
))
316 value
: t
.Mapping
[K
, V
],
317 case_sensitive
: bool = False,
318 by
: 'te.Literal["key", "value"]' = "key",
319 reverse
: bool = False,
320 ) -> t
.List
[t
.Tuple
[K
, V
]]:
321 """Sort a dict and yield (key, value) pairs. Python dicts may not
322 be in the order you want to display them in, so sort them first.
324 .. sourcecode:: jinja
326 {% for key, value in mydict|dictsort %}
327 sort the dict by key, case insensitive
329 {% for key, value in mydict|dictsort(reverse=true) %}
330 sort the dict by key, case insensitive, reverse order
332 {% for key, value in mydict|dictsort(true) %}
333 sort the dict by key, case sensitive
335 {% for key, value in mydict|dictsort(false, 'value') %}
336 sort the dict by value, case insensitive
343 raise FilterArgumentError('You can only sort by either "key" or "value"')
345 def sort_func(item
: t
.Tuple
[t
.Any
, t
.Any
]) -> t
.Any
:
348 if not case_sensitive
:
349 value
= ignore_case(value
)
353 return sorted(value
.items(), key
=sort_func
, reverse
=reverse
)
358 environment
: "Environment",
359 value
: "t.Iterable[V]",
360 reverse
: bool = False,
361 case_sensitive
: bool = False,
362 attribute
: t
.Optional
[t
.Union
[str, int]] = None,
364 """Sort an iterable using Python's :func:`sorted`.
366 .. sourcecode:: jinja
368 {% for city in cities|sort %}
372 :param reverse: Sort descending instead of ascending.
373 :param case_sensitive: When sorting strings, sort upper and lower
375 :param attribute: When sorting objects or dicts, an attribute or
376 key to sort by. Can use dot notation like ``"address.city"``.
377 Can be a list of attributes like ``"age,name"``.
379 The sort is stable, it does not change the relative order of
380 elements that compare equal. This makes it is possible to chain
381 sorts on different attributes and ordering.
383 .. sourcecode:: jinja
385 {% for user in users|sort(attribute="name")
386 |sort(reverse=true, attribute="age") %}
390 As a shortcut to chaining when the direction is the same for all
391 attributes, pass a comma separate list of attributes.
393 .. sourcecode:: jinja
395 {% for user in users|sort(attribute="age,name") %}
399 .. versionchanged:: 2.11.0
400 The ``attribute`` parameter can be a comma separated list of
401 attributes, e.g. ``"age,name"``.
403 .. versionchanged:: 2.6
404 The ``attribute`` parameter was added.
406 key_func
= make_multi_attrgetter(
407 environment
, attribute
, postprocess
=ignore_case
if not case_sensitive
else None
409 return sorted(value
, key
=key_func
, reverse
=reverse
)
414 environment
: "Environment",
415 value
: "t.Iterable[V]",
416 case_sensitive
: bool = False,
417 attribute
: t
.Optional
[t
.Union
[str, int]] = None,
418 ) -> "t.Iterator[V]":
419 """Returns a list of unique items from the given iterable.
421 .. sourcecode:: jinja
423 {{ ['foo', 'bar', 'foobar', 'FooBar']|unique|list }}
424 -> ['foo', 'bar', 'foobar']
426 The unique items are yielded in the same order as their first occurrence in
427 the iterable passed to the filter.
429 :param case_sensitive: Treat upper and lower case strings as distinct.
430 :param attribute: Filter objects with unique values for this attribute.
432 getter
= make_attrgetter(
433 environment
, attribute
, postprocess
=ignore_case
if not case_sensitive
else None
446 environment
: "Environment",
447 value
: "t.Iterable[V]",
448 func
: "t.Callable[..., V]",
449 case_sensitive
: bool,
450 attribute
: t
.Optional
[t
.Union
[str, int]],
451 ) -> "t.Union[V, Undefined]":
456 except StopIteration:
457 return environment
.undefined("No aggregated item, sequence was empty.")
459 key_func
= make_attrgetter(
460 environment
, attribute
, postprocess
=ignore_case
if not case_sensitive
else None
462 return func(chain([first
], it
), key
=key_func
)
467 environment
: "Environment",
468 value
: "t.Iterable[V]",
469 case_sensitive
: bool = False,
470 attribute
: t
.Optional
[t
.Union
[str, int]] = None,
471 ) -> "t.Union[V, Undefined]":
472 """Return the smallest item from the sequence.
474 .. sourcecode:: jinja
479 :param case_sensitive: Treat upper and lower case strings as distinct.
480 :param attribute: Get the object with the min value of this attribute.
482 return _min_or_max(environment
, value
, min, case_sensitive
, attribute
)
487 environment
: "Environment",
488 value
: "t.Iterable[V]",
489 case_sensitive
: bool = False,
490 attribute
: t
.Optional
[t
.Union
[str, int]] = None,
491 ) -> "t.Union[V, Undefined]":
492 """Return the largest item from the sequence.
494 .. sourcecode:: jinja
499 :param case_sensitive: Treat upper and lower case strings as distinct.
500 :param attribute: Get the object with the max value of this attribute.
502 return _min_or_max(environment
, value
, max, case_sensitive
, attribute
)
507 default_value
: V
= "", # type: ignore
508 boolean
: bool = False,
510 """If the value is undefined it will return the passed default value,
511 otherwise the value of the variable:
513 .. sourcecode:: jinja
515 {{ my_variable|default('my_variable is not defined') }}
517 This will output the value of ``my_variable`` if the variable was
518 defined, otherwise ``'my_variable is not defined'``. If you want
519 to use default with variables that evaluate to false you have to
520 set the second parameter to `true`:
522 .. sourcecode:: jinja
524 {{ ''|default('the string was empty', true) }}
526 .. versionchanged:: 2.11
527 It's now possible to configure the :class:`~jinja2.Environment` with
528 :class:`~jinja2.ChainableUndefined` to make the `default` filter work
529 on nested elements and attributes that may contain undefined values
530 in the chain without getting an :exc:`~jinja2.UndefinedError`.
532 if isinstance(value
, Undefined
) or (boolean
and not value
):
540 eval_ctx
: "EvalContext",
543 attribute
: t
.Optional
[t
.Union
[str, int]] = None,
545 """Return a string which is the concatenation of the strings in the
546 sequence. The separator between elements is an empty string per
547 default, you can define it with the optional parameter:
549 .. sourcecode:: jinja
551 {{ [1, 2, 3]|join('|') }}
557 It is also possible to join certain attributes of an object:
559 .. sourcecode:: jinja
561 {{ users|join(', ', attribute='username') }}
563 .. versionadded:: 2.6
564 The `attribute` parameter was added.
566 if attribute
is not None:
567 value
= map(make_attrgetter(eval_ctx
.environment
, attribute
), value
)
569 # no automatic escaping? joining is a lot easier then
570 if not eval_ctx
.autoescape
:
571 return str(d
).join(map(str, value
))
573 # if the delimiter doesn't have an html representation we check
574 # if any of the items has. If yes we do a coercion to Markup
575 if not hasattr(d
, "__html__"):
579 for idx
, item
in enumerate(value
):
580 if hasattr(item
, "__html__"):
583 value
[idx
] = str(item
)
592 # no html involved, to normal joining
593 return soft_str(d
).join(map(soft_str
, value
))
596 @async_variant(sync_do_join
) # type: ignore
598 eval_ctx
: "EvalContext",
599 value
: t
.Union
[t
.AsyncIterable
, t
.Iterable
],
601 attribute
: t
.Optional
[t
.Union
[str, int]] = None,
603 return sync_do_join(eval_ctx
, await auto_to_list(value
), d
, attribute
)
606 def do_center(value
: str, width
: int = 80) -> str:
607 """Centers the value in a field of a given width."""
608 return soft_str(value
).center(width
)
613 environment
: "Environment", seq
: "t.Iterable[V]"
614 ) -> "t.Union[V, Undefined]":
615 """Return the first item of a sequence."""
617 return next(iter(seq
))
618 except StopIteration:
619 return environment
.undefined("No first item, sequence was empty.")
622 @async_variant(sync_do_first
) # type: ignore
624 environment
: "Environment", seq
: "t.Union[t.AsyncIterable[V], t.Iterable[V]]"
625 ) -> "t.Union[V, Undefined]":
627 return await auto_aiter(seq
).__anext
__()
628 except StopAsyncIteration
:
629 return environment
.undefined("No first item, sequence was empty.")
634 environment
: "Environment", seq
: "t.Reversible[V]"
635 ) -> "t.Union[V, Undefined]":
636 """Return the last item of a sequence.
638 Note: Does not work with generators. You may want to explicitly
639 convert it to a list:
641 .. sourcecode:: jinja
643 {{ data | selectattr('name', '==', 'Jinja') | list | last }}
646 return next(iter(reversed(seq
)))
647 except StopIteration:
648 return environment
.undefined("No last item, sequence was empty.")
651 # No async do_last, it may not be safe in async mode.
655 def do_random(context
: "Context", seq
: "t.Sequence[V]") -> "t.Union[V, Undefined]":
656 """Return a random item from the sequence."""
658 return random
.choice(seq
)
660 return context
.environment
.undefined("No random item, sequence was empty.")
663 def do_filesizeformat(value
: t
.Union
[str, float, int], binary
: bool = False) -> str:
664 """Format the value like a 'human-readable' file size (i.e. 13 kB,
665 4.1 MB, 102 Bytes, etc). Per default decimal prefixes are used (Mega,
666 Giga, etc.), if the second parameter is set to `True` the binary
667 prefixes are used (Mebi, Gibi).
670 base
= 1024 if binary
else 1000
672 ("KiB" if binary
else "kB"),
673 ("MiB" if binary
else "MB"),
674 ("GiB" if binary
else "GB"),
675 ("TiB" if binary
else "TB"),
676 ("PiB" if binary
else "PB"),
677 ("EiB" if binary
else "EB"),
678 ("ZiB" if binary
else "ZB"),
679 ("YiB" if binary
else "YB"),
685 return f
"{int(bytes)} Bytes"
687 for i
, prefix
in enumerate(prefixes
):
688 unit
= base
** (i
+ 2)
691 return f
"{base * bytes / unit:.1f} {prefix}"
693 return f
"{base * bytes / unit:.1f} {prefix}"
696 def do_pprint(value
: t
.Any
) -> str:
697 """Pretty print a variable. Useful for debugging."""
698 return pformat(value
)
701 _uri_scheme_re
= re
.compile(r
"^([\w.+-]{2,}:(/){0,2})$")
706 eval_ctx
: "EvalContext",
708 trim_url_limit
: t
.Optional
[int] = None,
709 nofollow
: bool = False,
710 target
: t
.Optional
[str] = None,
711 rel
: t
.Optional
[str] = None,
712 extra_schemes
: t
.Optional
[t
.Iterable
[str]] = None,
714 """Convert URLs in text into clickable links.
716 This may not recognize links in some situations. Usually, a more
717 comprehensive formatter, such as a Markdown library, is a better
720 Works on ``http://``, ``https://``, ``www.``, ``mailto:``, and email
721 addresses. Links with trailing punctuation (periods, commas, closing
722 parentheses) and leading punctuation (opening parentheses) are
723 recognized excluding the punctuation. Email addresses that include
724 header fields are not recognized (for example,
725 ``mailto:address@example.com?cc=copy@example.com``).
727 :param value: Original text containing URLs to link.
728 :param trim_url_limit: Shorten displayed URL values to this length.
729 :param nofollow: Add the ``rel=nofollow`` attribute to links.
730 :param target: Add the ``target`` attribute to links.
731 :param rel: Add the ``rel`` attribute to links.
732 :param extra_schemes: Recognize URLs that start with these schemes
733 in addition to the default behavior. Defaults to
734 ``env.policies["urlize.extra_schemes"]``, which defaults to no
737 .. versionchanged:: 3.0
738 The ``extra_schemes`` parameter was added.
740 .. versionchanged:: 3.0
741 Generate ``https://`` links for URLs without a scheme.
743 .. versionchanged:: 3.0
744 The parsing rules were updated. Recognize email addresses with
745 or without the ``mailto:`` scheme. Validate IP addresses. Ignore
746 parentheses and brackets in more cases.
748 .. versionchanged:: 2.8
749 The ``target`` parameter was added.
751 policies
= eval_ctx
.environment
.policies
752 rel_parts
= set((rel
or "").split())
755 rel_parts
.add("nofollow")
757 rel_parts
.update((policies
["urlize.rel"] or "").split())
758 rel
= " ".join(sorted(rel_parts
)) or None
761 target
= policies
["urlize.target"]
763 if extra_schemes
is None:
764 extra_schemes
= policies
["urlize.extra_schemes"] or ()
766 for scheme
in extra_schemes
:
767 if _uri_scheme_re
.fullmatch(scheme
) is None:
768 raise FilterArgumentError(f
"{scheme!r} is not a valid URI scheme prefix.")
772 trim_url_limit
=trim_url_limit
,
775 extra_schemes
=extra_schemes
,
778 if eval_ctx
.autoescape
:
785 s
: str, width
: t
.Union
[int, str] = 4, first
: bool = False, blank
: bool = False
787 """Return a copy of the string with each line indented by 4 spaces. The
788 first line and blank lines are not indented by default.
790 :param width: Number of spaces, or a string, to indent by.
791 :param first: Don't skip indenting the first line.
792 :param blank: Don't skip indenting empty lines.
794 .. versionchanged:: 3.0
795 ``width`` can be a string.
797 .. versionchanged:: 2.10
798 Blank lines are not indented by default.
800 Rename the ``indentfirst`` argument to ``first``.
802 if isinstance(width
, str):
805 indention
= " " * width
809 if isinstance(s
, Markup
):
810 indention
= Markup(indention
)
811 newline
= Markup(newline
)
813 s
+= newline
# this quirk is necessary for splitlines method
816 rv
= (newline
+ indention
).join(s
.splitlines())
818 lines
= s
.splitlines()
822 rv
+= newline
+ newline
.join(
823 indention
+ line
if line
else line
for line
in lines
837 killwords
: bool = False,
839 leeway
: t
.Optional
[int] = None,
841 """Return a truncated copy of the string. The length is specified
842 with the first parameter which defaults to ``255``. If the second
843 parameter is ``true`` the filter will cut the text at length. Otherwise
844 it will discard the last word. If the text was in fact
845 truncated it will append an ellipsis sign (``"..."``). If you want a
846 different ellipsis sign than ``"..."`` you can specify it using the
847 third parameter. Strings that only exceed the length by the tolerance
848 margin given in the fourth parameter will not be truncated.
850 .. sourcecode:: jinja
852 {{ "foo bar baz qux"|truncate(9) }}
854 {{ "foo bar baz qux"|truncate(9, True) }}
856 {{ "foo bar baz qux"|truncate(11) }}
858 {{ "foo bar baz qux"|truncate(11, False, '...', 0) }}
861 The default leeway on newer Jinja versions is 5 and was 0 before but
862 can be reconfigured globally.
865 leeway
= env
.policies
["truncate.leeway"]
867 assert length
>= len(end
), f
"expected length >= {len(end)}, got {length}"
868 assert leeway
>= 0, f
"expected leeway >= 0, got {leeway}"
870 if len(s
) <= length
+ leeway
:
874 return s
[: length
- len(end
)] + end
876 result
= s
[: length
- len(end
)].rsplit(" ", 1)[0]
882 environment
: "Environment",
885 break_long_words
: bool = True,
886 wrapstring
: t
.Optional
[str] = None,
887 break_on_hyphens
: bool = True,
889 """Wrap a string to the given width. Existing newlines are treated
890 as paragraphs to be wrapped separately.
892 :param s: Original text to wrap.
893 :param width: Maximum length of wrapped lines.
894 :param break_long_words: If a word is longer than ``width``, break
896 :param break_on_hyphens: If a word contains hyphens, it may be split
898 :param wrapstring: String to join each wrapped line. Defaults to
899 :attr:`Environment.newline_sequence`.
901 .. versionchanged:: 2.11
902 Existing newlines are treated as paragraphs wrapped separately.
904 .. versionchanged:: 2.11
905 Added the ``break_on_hyphens`` parameter.
907 .. versionchanged:: 2.7
908 Added the ``wrapstring`` parameter.
912 if wrapstring
is None:
913 wrapstring
= environment
.newline_sequence
915 # textwrap.wrap doesn't consider existing newlines when wrapping.
916 # If the string has a newline before width, wrap will still insert
917 # a newline at width, resulting in a short line. Instead, split and
918 # wrap each paragraph individually.
919 return wrapstring
.join(
926 replace_whitespace
=False,
927 break_long_words
=break_long_words
,
928 break_on_hyphens
=break_on_hyphens
,
931 for line
in s
.splitlines()
936 _word_re
= re
.compile(r
"\w+")
939 def do_wordcount(s
: str) -> int:
940 """Count the words in that string."""
941 return len(_word_re
.findall(soft_str(s
)))
944 def do_int(value
: t
.Any
, default
: int = 0, base
: int = 10) -> int:
945 """Convert the value into an integer. If the
946 conversion doesn't work it will return ``0``. You can
947 override this default using the first parameter. You
948 can also override the default base (10) in the second
949 parameter, which handles input with prefixes such as
950 0b, 0o and 0x for bases 2, 8 and 16 respectively.
951 The base is ignored for decimal numbers and non-string values.
954 if isinstance(value
, str):
955 return int(value
, base
)
958 except (TypeError, ValueError):
959 # this quirk is necessary so that "42.23"|int gives 42.
961 return int(float(value
))
962 except (TypeError, ValueError):
966 def do_float(value
: t
.Any
, default
: float = 0.0) -> float:
967 """Convert the value into a floating point number. If the
968 conversion doesn't work it will return ``0.0``. You can
969 override this default using the first parameter.
973 except (TypeError, ValueError):
977 def do_format(value
: str, *args
: t
.Any
, **kwargs
: t
.Any
) -> str:
978 """Apply the given values to a `printf-style`_ format string, like
981 .. sourcecode:: jinja
983 {{ "%s, %s!"|format(greeting, name) }}
986 In most cases it should be more convenient and efficient to use the
987 ``%`` operator or :meth:`str.format`.
991 {{ "%s, %s!" % (greeting, name) }}
992 {{ "{}, {}!".format(greeting, name) }}
994 .. _printf-style: https://docs.python.org/library/stdtypes.html
995 #printf-style-string-formatting
998 raise FilterArgumentError(
999 "can't handle positional and keyword arguments at the same time"
1002 return soft_str(value
) % (kwargs
or args
)
1005 def do_trim(value
: str, chars
: t
.Optional
[str] = None) -> str:
1006 """Strip leading and trailing characters, by default whitespace."""
1007 return soft_str(value
).strip(chars
)
1010 def do_striptags(value
: "t.Union[str, HasHTML]") -> str:
1011 """Strip SGML/XML tags and replace adjacent whitespace by one space."""
1012 if hasattr(value
, "__html__"):
1013 value
= t
.cast("HasHTML", value
).__html
__()
1015 return Markup(str(value
)).striptags()
1019 value
: "t.Collection[V]", slices
: int, fill_with
: "t.Optional[V]" = None
1020 ) -> "t.Iterator[t.List[V]]":
1021 """Slice an iterator and return a list of lists containing
1022 those items. Useful if you want to create a div containing
1023 three ul tags that represent columns:
1025 .. sourcecode:: html+jinja
1027 <div class="columnwrapper">
1028 {%- for column in items|slice(3) %}
1029 <ul class="column-{{ loop.index }}">
1030 {%- for item in column %}
1037 If you pass it a second argument it's used to fill missing
1038 values on the last iteration.
1042 items_per_slice
= length
// slices
1043 slices_with_extra
= length
% slices
1046 for slice_number
in range(slices
):
1047 start
= offset
+ slice_number
* items_per_slice
1049 if slice_number
< slices_with_extra
:
1052 end
= offset
+ (slice_number
+ 1) * items_per_slice
1053 tmp
= seq
[start
:end
]
1055 if fill_with
is not None and slice_number
>= slices_with_extra
:
1056 tmp
.append(fill_with
)
1061 @async_variant(sync_do_slice
) # type: ignore
1063 value
: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
1065 fill_with
: t
.Optional
[t
.Any
] = None,
1066 ) -> "t.Iterator[t.List[V]]":
1067 return sync_do_slice(await auto_to_list(value
), slices
, fill_with
)
1071 value
: "t.Iterable[V]", linecount
: int, fill_with
: "t.Optional[V]" = None
1072 ) -> "t.Iterator[t.List[V]]":
1074 A filter that batches items. It works pretty much like `slice`
1075 just the other way round. It returns a list of lists with the
1076 given number of items. If you provide a second parameter this
1077 is used to fill up missing items. See this example:
1079 .. sourcecode:: html+jinja
1082 {%- for row in items|batch(3, ' ') %}
1084 {%- for column in row %}
1085 <td>{{ column }}</td>
1091 tmp
: "t.List[V]" = []
1094 if len(tmp
) == linecount
:
1101 if fill_with
is not None and len(tmp
) < linecount
:
1102 tmp
+= [fill_with
] * (linecount
- len(tmp
))
1110 method
: 'te.Literal["common", "ceil", "floor"]' = "common",
1112 """Round the number to a given precision. The first
1113 parameter specifies the precision (default is ``0``), the
1114 second the rounding method:
1116 - ``'common'`` rounds either up or down
1117 - ``'ceil'`` always rounds up
1118 - ``'floor'`` always rounds down
1120 If you don't specify a method ``'common'`` is used.
1122 .. sourcecode:: jinja
1126 {{ 42.55|round(1, 'floor') }}
1129 Note that even if rounded to 0 precision, a float is returned. If
1130 you need a real integer, pipe it through `int`:
1132 .. sourcecode:: jinja
1134 {{ 42.55|round|int }}
1137 if method
not in {"common", "ceil", "floor"}
:
1138 raise FilterArgumentError("method must be common, ceil or floor")
1140 if method
== "common":
1141 return round(value
, precision
)
1143 func
= getattr(math
, method
)
1144 return t
.cast(float, func(value
* (10**precision
)) / (10**precision
))
1147 class _GroupTuple(t
.NamedTuple
):
1151 # Use the regular tuple repr to hide this subclass if users print
1152 # out the value during debugging.
1153 def __repr__(self
) -> str:
1154 return tuple.__repr
__(self
)
1156 def __str__(self
) -> str:
1157 return tuple.__str
__(self
)
1161 def sync_do_groupby(
1162 environment
: "Environment",
1163 value
: "t.Iterable[V]",
1164 attribute
: t
.Union
[str, int],
1165 default
: t
.Optional
[t
.Any
] = None,
1166 case_sensitive
: bool = False,
1167 ) -> "t.List[_GroupTuple]":
1168 """Group a sequence of objects by an attribute using Python's
1169 :func:`itertools.groupby`. The attribute can use dot notation for
1170 nested access, like ``"address.city"``. Unlike Python's ``groupby``,
1171 the values are sorted first so only one group is returned for each
1174 For example, a list of ``User`` objects with a ``city`` attribute
1175 can be rendered in groups. In this example, ``grouper`` refers to
1176 the ``city`` value of the group.
1178 .. sourcecode:: html+jinja
1180 <ul>{% for city, items in users|groupby("city") %}
1182 <ul>{% for user in items %}
1188 ``groupby`` yields namedtuples of ``(grouper, list)``, which
1189 can be used instead of the tuple unpacking above. ``grouper`` is the
1190 value of the attribute, and ``list`` is the items with that value.
1192 .. sourcecode:: html+jinja
1194 <ul>{% for group in users|groupby("city") %}
1195 <li>{{ group.grouper }}: {{ group.list|join(", ") }}
1198 You can specify a ``default`` value to use if an object in the list
1199 does not have the given attribute.
1201 .. sourcecode:: jinja
1203 <ul>{% for city, items in users|groupby("city", default="NY") %}
1204 <li>{{ city }}: {{ items|map(attribute="name")|join(", ") }}</li>
1207 Like the :func:`~jinja-filters.sort` filter, sorting and grouping is
1208 case-insensitive by default. The ``key`` for each group will have
1209 the case of the first item in that group of values. For example, if
1210 a list of users has cities ``["CA", "NY", "ca"]``, the "CA" group
1211 will have two values. This can be disabled by passing
1212 ``case_sensitive=True``.
1214 .. versionchanged:: 3.1
1215 Added the ``case_sensitive`` parameter. Sorting and grouping is
1216 case-insensitive by default, matching other filters that do
1219 .. versionchanged:: 3.0
1220 Added the ``default`` parameter.
1222 .. versionchanged:: 2.6
1223 The attribute supports dot notation for nested access.
1225 expr
= make_attrgetter(
1228 postprocess
=ignore_case
if not case_sensitive
else None,
1232 _GroupTuple(key
, list(values
))
1233 for key
, values
in groupby(sorted(value
, key
=expr
), expr
)
1236 if not case_sensitive
:
1237 # Return the real key from the first value instead of the lowercase key.
1238 output_expr
= make_attrgetter(environment
, attribute
, default
=default
)
1239 out
= [_GroupTuple(output_expr(values
[0]), values
) for _
, values
in out
]
1244 @async_variant(sync_do_groupby
) # type: ignore
1245 async def do_groupby(
1246 environment
: "Environment",
1247 value
: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
1248 attribute
: t
.Union
[str, int],
1249 default
: t
.Optional
[t
.Any
] = None,
1250 case_sensitive
: bool = False,
1251 ) -> "t.List[_GroupTuple]":
1252 expr
= make_attrgetter(
1255 postprocess
=ignore_case
if not case_sensitive
else None,
1259 _GroupTuple(key
, await auto_to_list(values
))
1260 for key
, values
in groupby(sorted(await auto_to_list(value
), key
=expr
), expr
)
1263 if not case_sensitive
:
1264 # Return the real key from the first value instead of the lowercase key.
1265 output_expr
= make_attrgetter(environment
, attribute
, default
=default
)
1266 out
= [_GroupTuple(output_expr(values
[0]), values
) for _
, values
in out
]
1273 environment
: "Environment",
1274 iterable
: "t.Iterable[V]",
1275 attribute
: t
.Optional
[t
.Union
[str, int]] = None,
1276 start
: V
= 0, # type: ignore
1278 """Returns the sum of a sequence of numbers plus the value of parameter
1279 'start' (which defaults to 0). When the sequence is empty it returns
1282 It is also possible to sum up only certain attributes:
1284 .. sourcecode:: jinja
1286 Total: {{ items|sum(attribute='price') }}
1288 .. versionchanged:: 2.6
1289 The ``attribute`` parameter was added to allow summing up over
1290 attributes. Also the ``start`` parameter was moved on to the right.
1292 if attribute
is not None:
1293 iterable
= map(make_attrgetter(environment
, attribute
), iterable
)
1295 return sum(iterable
, start
) # type: ignore[no-any-return, call-overload]
1298 @async_variant(sync_do_sum
) # type: ignore
1300 environment
: "Environment",
1301 iterable
: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
1302 attribute
: t
.Optional
[t
.Union
[str, int]] = None,
1303 start
: V
= 0, # type: ignore
1307 if attribute
is not None:
1308 func
= make_attrgetter(environment
, attribute
)
1311 def func(x
: V
) -> V
:
1314 async for item
in auto_aiter(iterable
):
1320 def sync_do_list(value
: "t.Iterable[V]") -> "t.List[V]":
1321 """Convert the value into a list. If it was a string the returned list
1322 will be a list of characters.
1327 @async_variant(sync_do_list
) # type: ignore
1328 async def do_list(value
: "t.Union[t.AsyncIterable[V], t.Iterable[V]]") -> "t.List[V]":
1329 return await auto_to_list(value
)
1332 def do_mark_safe(value
: str) -> Markup
:
1333 """Mark the value as safe which means that in an environment with automatic
1334 escaping enabled this variable will not be escaped.
1336 return Markup(value
)
1339 def do_mark_unsafe(value
: str) -> str:
1340 """Mark a value as unsafe. This is the reverse operation for :func:`safe`."""
1345 def do_reverse(value
: str) -> str:
1350 def do_reverse(value
: "t.Iterable[V]") -> "t.Iterable[V]":
1354 def do_reverse(value
: t
.Union
[str, t
.Iterable
[V
]]) -> t
.Union
[str, t
.Iterable
[V
]]:
1355 """Reverse the object or return an iterator that iterates over it the other
1358 if isinstance(value
, str):
1362 return reversed(value
) # type: ignore
1368 except TypeError as e
:
1369 raise FilterArgumentError("argument must be iterable") from e
1374 environment
: "Environment", obj
: t
.Any
, name
: str
1375 ) -> t
.Union
[Undefined
, t
.Any
]:
1376 """Get an attribute of an object. ``foo|attr("bar")`` works like
1377 ``foo.bar`` just that always an attribute is returned and items are not
1380 See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details.
1384 except UnicodeError:
1388 value
= getattr(obj
, name
)
1389 except AttributeError:
1392 if environment
.sandboxed
:
1393 environment
= t
.cast("SandboxedEnvironment", environment
)
1395 if not environment
.is_safe_attribute(obj
, name
, value
):
1396 return environment
.unsafe_undefined(obj
, name
)
1400 return environment
.undefined(obj
=obj
, name
=name
)
1405 context
: "Context", value
: t
.Iterable
, name
: str, *args
: t
.Any
, **kwargs
: t
.Any
1415 attribute
: str = ...,
1416 default
: t
.Optional
[t
.Any
] = None,
1423 context
: "Context", value
: t
.Iterable
, *args
: t
.Any
, **kwargs
: t
.Any
1425 """Applies a filter on a sequence of objects or looks up an attribute.
1426 This is useful when dealing with lists of objects but you are really
1427 only interested in a certain value of it.
1429 The basic usage is mapping on an attribute. Imagine you have a list
1430 of users but you are only interested in a list of usernames:
1432 .. sourcecode:: jinja
1434 Users on this page: {{ users|map(attribute='username')|join(', ') }}
1436 You can specify a ``default`` value to use if an object in the list
1437 does not have the given attribute.
1439 .. sourcecode:: jinja
1441 {{ users|map(attribute="username", default="Anonymous")|join(", ") }}
1443 Alternatively you can let it invoke a filter by passing the name of the
1444 filter and the arguments afterwards. A good example would be applying a
1445 text conversion filter on a sequence:
1447 .. sourcecode:: jinja
1449 Users on this page: {{ titles|map('lower')|join(', ') }}
1451 Similar to a generator comprehension such as:
1453 .. code-block:: python
1455 (u.username for u in users)
1456 (getattr(u, "username", "Anonymous") for u in users)
1457 (do_lower(x) for x in titles)
1459 .. versionchanged:: 2.11.0
1460 Added the ``default`` parameter.
1462 .. versionadded:: 2.7
1465 func
= prepare_map(context
, args
, kwargs
)
1474 value
: t
.Union
[t
.AsyncIterable
, t
.Iterable
],
1485 value
: t
.Union
[t
.AsyncIterable
, t
.Iterable
],
1487 attribute
: str = ...,
1488 default
: t
.Optional
[t
.Any
] = None,
1493 @async_variant(sync_do_map
) # type: ignore
1496 value
: t
.Union
[t
.AsyncIterable
, t
.Iterable
],
1499 ) -> t
.AsyncIterable
:
1501 func
= prepare_map(context
, args
, kwargs
)
1503 async for item
in auto_aiter(value
):
1504 yield await auto_await(func(item
))
1509 context
: "Context", value
: "t.Iterable[V]", *args
: t
.Any
, **kwargs
: t
.Any
1510 ) -> "t.Iterator[V]":
1511 """Filters a sequence of objects by applying a test to each object,
1512 and only selecting the objects with the test succeeding.
1514 If no test is specified, each object will be evaluated as a boolean.
1518 .. sourcecode:: jinja
1520 {{ numbers|select("odd") }}
1521 {{ numbers|select("odd") }}
1522 {{ numbers|select("divisibleby", 3) }}
1523 {{ numbers|select("lessthan", 42) }}
1524 {{ strings|select("equalto", "mystring") }}
1526 Similar to a generator comprehension such as:
1528 .. code-block:: python
1530 (n for n in numbers if test_odd(n))
1531 (n for n in numbers if test_divisibleby(n, 3))
1533 .. versionadded:: 2.7
1535 return select_or_reject(context
, value
, args
, kwargs
, lambda x
: x
, False)
1538 @async_variant(sync_do_select
) # type: ignore
1539 async def do_select(
1541 value
: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
1544 ) -> "t.AsyncIterator[V]":
1545 return async_select_or_reject(context
, value
, args
, kwargs
, lambda x
: x
, False)
1550 context
: "Context", value
: "t.Iterable[V]", *args
: t
.Any
, **kwargs
: t
.Any
1551 ) -> "t.Iterator[V]":
1552 """Filters a sequence of objects by applying a test to each object,
1553 and rejecting the objects with the test succeeding.
1555 If no test is specified, each object will be evaluated as a boolean.
1559 .. sourcecode:: jinja
1561 {{ numbers|reject("odd") }}
1563 Similar to a generator comprehension such as:
1565 .. code-block:: python
1567 (n for n in numbers if not test_odd(n))
1569 .. versionadded:: 2.7
1571 return select_or_reject(context
, value
, args
, kwargs
, lambda x
: not x
, False)
1574 @async_variant(sync_do_reject
) # type: ignore
1575 async def do_reject(
1577 value
: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
1580 ) -> "t.AsyncIterator[V]":
1581 return async_select_or_reject(context
, value
, args
, kwargs
, lambda x
: not x
, False)
1585 def sync_do_selectattr(
1586 context
: "Context", value
: "t.Iterable[V]", *args
: t
.Any
, **kwargs
: t
.Any
1587 ) -> "t.Iterator[V]":
1588 """Filters a sequence of objects by applying a test to the specified
1589 attribute of each object, and only selecting the objects with the
1592 If no test is specified, the attribute's value will be evaluated as
1597 .. sourcecode:: jinja
1599 {{ users|selectattr("is_active") }}
1600 {{ users|selectattr("email", "none") }}
1602 Similar to a generator comprehension such as:
1604 .. code-block:: python
1606 (u for user in users if user.is_active)
1607 (u for user in users if test_none(user.email))
1609 .. versionadded:: 2.7
1611 return select_or_reject(context
, value
, args
, kwargs
, lambda x
: x
, True)
1614 @async_variant(sync_do_selectattr
) # type: ignore
1615 async def do_selectattr(
1617 value
: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
1620 ) -> "t.AsyncIterator[V]":
1621 return async_select_or_reject(context
, value
, args
, kwargs
, lambda x
: x
, True)
1625 def sync_do_rejectattr(
1626 context
: "Context", value
: "t.Iterable[V]", *args
: t
.Any
, **kwargs
: t
.Any
1627 ) -> "t.Iterator[V]":
1628 """Filters a sequence of objects by applying a test to the specified
1629 attribute of each object, and rejecting the objects with the test
1632 If no test is specified, the attribute's value will be evaluated as
1635 .. sourcecode:: jinja
1637 {{ users|rejectattr("is_active") }}
1638 {{ users|rejectattr("email", "none") }}
1640 Similar to a generator comprehension such as:
1642 .. code-block:: python
1644 (u for user in users if not user.is_active)
1645 (u for user in users if not test_none(user.email))
1647 .. versionadded:: 2.7
1649 return select_or_reject(context
, value
, args
, kwargs
, lambda x
: not x
, True)
1652 @async_variant(sync_do_rejectattr
) # type: ignore
1653 async def do_rejectattr(
1655 value
: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
1658 ) -> "t.AsyncIterator[V]":
1659 return async_select_or_reject(context
, value
, args
, kwargs
, lambda x
: not x
, True)
1664 eval_ctx
: "EvalContext", value
: t
.Any
, indent
: t
.Optional
[int] = None
1666 """Serialize an object to a string of JSON, and mark it safe to
1667 render in HTML. This filter is only for use in HTML documents.
1669 The returned string is safe to render in HTML documents and
1670 ``<script>`` tags. The exception is in HTML attributes that are
1671 double quoted; either use single quotes or the ``|forceescape``
1674 :param value: The object to serialize to JSON.
1675 :param indent: The ``indent`` parameter passed to ``dumps``, for
1676 pretty-printing the value.
1678 .. versionadded:: 2.9
1680 policies
= eval_ctx
.environment
.policies
1681 dumps
= policies
["json.dumps_function"]
1682 kwargs
= policies
["json.dumps_kwargs"]
1684 if indent
is not None:
1685 kwargs
= kwargs
.copy()
1686 kwargs
["indent"] = indent
1688 return htmlsafe_json_dumps(value
, dumps
=dumps
, **kwargs
)
1692 context
: "Context", args
: t
.Tuple
, kwargs
: t
.Dict
[str, t
.Any
]
1693 ) -> t
.Callable
[[t
.Any
], t
.Any
]:
1694 if not args
and "attribute" in kwargs
:
1695 attribute
= kwargs
.pop("attribute")
1696 default
= kwargs
.pop("default", None)
1699 raise FilterArgumentError(
1700 f
"Unexpected keyword argument {next(iter(kwargs))!r}"
1703 func
= make_attrgetter(context
.environment
, attribute
, default
=default
)
1709 raise FilterArgumentError("map requires a filter argument") from None
1711 def func(item
: t
.Any
) -> t
.Any
:
1712 return context
.environment
.call_filter(
1713 name
, item
, args
, kwargs
, context
=context
1719 def prepare_select_or_reject(
1722 kwargs
: t
.Dict
[str, t
.Any
],
1723 modfunc
: t
.Callable
[[t
.Any
], t
.Any
],
1725 ) -> t
.Callable
[[t
.Any
], t
.Any
]:
1730 raise FilterArgumentError("Missing parameter for attribute name") from None
1732 transfunc
= make_attrgetter(context
.environment
, attr
)
1737 def transfunc(x
: V
) -> V
:
1742 args
= args
[1 + off
:]
1744 def func(item
: t
.Any
) -> t
.Any
:
1745 return context
.environment
.call_test(name
, item
, args
, kwargs
)
1748 func
= bool # type: ignore
1750 return lambda item
: modfunc(func(transfunc(item
)))
1753 def select_or_reject(
1755 value
: "t.Iterable[V]",
1757 kwargs
: t
.Dict
[str, t
.Any
],
1758 modfunc
: t
.Callable
[[t
.Any
], t
.Any
],
1760 ) -> "t.Iterator[V]":
1762 func
= prepare_select_or_reject(context
, args
, kwargs
, modfunc
, lookup_attr
)
1769 async def async_select_or_reject(
1771 value
: "t.Union[t.AsyncIterable[V], t.Iterable[V]]",
1773 kwargs
: t
.Dict
[str, t
.Any
],
1774 modfunc
: t
.Callable
[[t
.Any
], t
.Any
],
1776 ) -> "t.AsyncIterator[V]":
1778 func
= prepare_select_or_reject(context
, args
, kwargs
, modfunc
, lookup_attr
)
1780 async for item
in auto_aiter(value
):
1789 "capitalize": do_capitalize
,
1790 "center": do_center
,
1793 "default": do_default
,
1794 "dictsort": do_dictsort
,
1797 "filesizeformat": do_filesizeformat
,
1800 "forceescape": do_forceescape
,
1801 "format": do_format
,
1802 "groupby": do_groupby
,
1803 "indent": do_indent
,
1814 "pprint": do_pprint
,
1815 "random": do_random
,
1816 "reject": do_reject
,
1817 "rejectattr": do_rejectattr
,
1818 "replace": do_replace
,
1819 "reverse": do_reverse
,
1821 "safe": do_mark_safe
,
1822 "select": do_select
,
1823 "selectattr": do_selectattr
,
1827 "striptags": do_striptags
,
1831 "truncate": do_truncate
,
1832 "unique": do_unique
,
1834 "urlencode": do_urlencode
,
1835 "urlize": do_urlize
,
1836 "wordcount": do_wordcount
,
1837 "wordwrap": do_wordwrap
,
1838 "xmlattr": do_xmlattr
,
1839 "tojson": do_tojson
,