pallets / jinja

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

Type annotation wrong on TemplateStream.dump? #1983

Open alicederyn opened 2 months ago

alicederyn commented 2 months ago

This PR changed the hint for dump from IO to IO[bytes]: https://github.com/pallets/jinja/pull/1968

However, I believe if encoding is not provided (or explicitly None), this should be IO[str]? I certainly get a runtime error (TypeError: a bytes-like object is required, not 'str') if I try to change my code to pass in an IO[bytes] to satisfy mypy, while the code works fine at runtime if I just # type: ignore the new mypy errors.

I believe the type hint needs to change to an @overload:

@overload
def dump(
        self,
        fp: t.Union[str, t.IO[bytes]],
        encoding: str,
        errors: t.Optional[str] = "strict",
    ) -> None:
    ...

@overload
def dump(
        self,
        fp: t.Union[str, t.IO[str]],
        encoding: None = None,
        errors: t.Optional[str] = "strict",
    ) -> None:
    ...
stefmolin commented 2 months ago

Hi @alicederyn - Can you include a minimally reproducible example?

alicederyn commented 2 months ago

Sure! Take this for instance:

from jinja2 import Environment, FileSystemLoader

def simple_repro() -> None:
    environment = Environment(loader=FileSystemLoader("."))
    with open("foo.txt", "w") as output:
        environment.get_template("foo.txt.jinja").stream(person="Stefanie").dump(output)

with the following in foo.txt.jinja:

Hi {{person}}!

This runs fine, but mypy complains that:

repro.py:6: error: Argument 1 to "dump" of "TemplateStream" has incompatible type "TextIOWrapper"; expected "str | IO[bytes]"  [arg-type]

Changing the open call to open("foo.txt", "wb") makes mypy happy as output is now an IO[bytes], but at runtime the call to dump fails:

>               real_fp.writelines(iterable)
E               TypeError: a bytes-like object is required, not 'str'

opt/bb/lib/python3.11/site-packages/jinja2/environment.py:1626: TypeError

(It shouldn't matter, but this is python 3.11, jinja2 3.1.4, and mypy 1.10.0.)