pallets / jinja

A very fast and expressive template engine.
https://jinja.palletsprojects.com
BSD 3-Clause "New" or "Revised" License
10.23k stars 1.6k forks source link

Indent filter fails confusing if input is not string #1927

Closed alex-harvey-z3q closed 7 months ago

alex-harvey-z3q commented 7 months ago

Description

When calling the indent filter when the input is not a string (e.g. dict input), the filter fails with a confusing error message:

unsupported operand type(s) for +=: 'dict' and 'str'"

To reproduce

See the test I wrote:

    def test_indent_dict(self, env):
        self._test_indent_multiline_template(env)
        t = env.from_string('{{ mydict|indent }}')
        with pytest.raises(FilterArgumentError):
            t.render(mydict={"foo":"bar"})

Expected behaviour

An error message that advises that the filter has been called with unexpected inputs is expected.

Environment:

davidism commented 7 months ago

In general, Python does not do type checking just to show special error messages. If you pass in wrong data to something it might fail in weird ways at a weird spot. This filter isn't special in this regard.

alex-harvey-z3q commented 7 months ago

@davidism If you look through the code, you have yourself already added a number of FilterArgumentExceptions—correctly, according to good design—to ensure that failures are graceful. Also, the idea that Python programmers normally don't bother to handle their exceptions and just let things blow up confusingly is .... not true.

davidism commented 7 months ago

Here's the standard library's own indent function, failing on invalid input without talking about str. Most other functions result in similar behavior. Convince the cpython maintainers that they should add runtime type checks for the arguments of each function they maintain, and I'll consider adding them all over the place in Jinja too.

>>> import textwrap
>>> textwrap.indent({}, "  ")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.10/textwrap.py", line 488, in indent
    return ''.join(prefixed_lines())
  File "/usr/local/lib/python3.10/textwrap.py", line 486, in prefixed_lines
    for line in text.splitlines(True):
AttributeError: 'dict' object has no attribute 'splitlines'