return soft_str(s).lower()
+def do_items(value: t.Union[t.Mapping[K, V], Undefined]) -> t.Iterator[t.Tuple[K, V]]:
+ """Return an iterator over the ``(key, value)`` items of a mapping.
+
+ ``x|items`` is the same as ``x.items()``, except if ``x`` is
+ undefined an empty iterator is returned.
+
+ This filter is useful if you expect the template to be rendered with
+ an implementation of Jinja in another programming language that does
+ not have a ``.items()`` method on its mapping type.
+
+ .. code-block:: html+jinja
+
+ <dl>
+ {% for key, value in my_dict|items %}
+ <dt>{{ key }}
+ <dd>{{ value }}
+ {% endfor %}
+ </dl>
+
+ .. versionadded:: 3.1
+ """
+ if isinstance(value, Undefined):
+ return
+
+ if not isinstance(value, abc.Mapping):
+ raise TypeError("Can only get item pairs from a mapping.")
+
+ yield from value.items()
+
+
@pass_eval_context
def do_xmlattr(
eval_ctx: "EvalContext", d: t.Mapping[str, t.Any], autospace: bool = True
"length": len,
"list": do_list,
"lower": do_lower,
+ "items": do_items,
"map": do_map,
"min": do_min,
"max": do_max,
out = tmpl.render()
assert out == "foo"
+ def test_items(self, env):
+ d = {i: c for i, c in enumerate("abc")}
+ tmpl = env.from_string("""{{ d|items|list }}""")
+ out = tmpl.render(d=d)
+ assert out == "[(0, 'a'), (1, 'b'), (2, 'c')]"
+
+ def test_items_undefined(self, env):
+ tmpl = env.from_string("""{{ d|items|list }}""")
+ out = tmpl.render()
+ assert out == "[]"
+
def test_pprint(self, env):
from pprint import pformat