mypy does not honour open()
overrides from typeshed. · Issue #11193 · python/mypy (original) (raw)
Bug Report
It seems like mypy is not honoring the typeshed Path.open overrides exactly, as from these I would expect mypy to think the values returned by open was:
io.TextIOWrapper
for.open("w")
io.BufferedWriter
for.open("wb")
io.FileIO
for.open("wb", buffering=0)
But instead, mypy thinks the values returned are:typing.TextIO
for.open("w")
typing.BinaryIO
for.open("wb")
typing.BinaryIO
for.open("wb", buffering=0)
The same is the case for the open()
builtin.
I'm reporting this as a mypy issue, because the typing in typeshed looks right to me for the most part, and I can't even tell from typeshed where mypy would be getting typing.TextIO
from. I will however report a seperate issue against typeshed for mixing the io.
and typing.IO
heirarchies in return types, as this is maybe where typing.BinaryIO
comes from, but even so the other overrides should take precedence as far as I can tell.
To Reproduce
The problem can be seen when running mypy on the following code which contain unit tests which run with no errors:
import io import pathlib import tempfile import typing import unittest
class TestOpen(unittest.TestCase): def setUp(self) -> None: self._tmp_path = tempfile.TemporaryDirectory() self.tmp_path = pathlib.Path(self._tmp_path.name) self.tmp_file = self.tmp_path / "file"
def tearDown(self) -> None:
self._tmp_path.cleanup()
def test_open_text_stream(self) -> None:
with self.tmp_file.open("w") as text_stream:
text_io: typing.TextIO = text_stream # noqa: F841
text_io_base: io.TextIOBase = text_stream # noqa: F841
assert isinstance(text_stream, io.TextIOBase)
def test_open_buffered_stream(self) -> None:
with self.tmp_file.open("wb") as buffered_stream:
binary_io: typing.BinaryIO = buffered_stream # noqa: F841
buffered_io_base: io.BufferedIOBase = buffered_stream # noqa: F841
assert isinstance(buffered_stream, io.BufferedIOBase)
def test_open_raw_stream(self) -> None:
with self.tmp_file.open("wb", buffering=0) as raw_stream:
binary_io: typing.BinaryIO = raw_stream # noqa: F841
raw_io_base: io.RawIOBase = raw_stream # noqa: F841
assert isinstance(binary_io, io.RawIOBase)
if name == "main": unittest.main()
Expected Behavior
I expect mypy to not find any errors in the shared code.
Actual Behavior
Mypy reports the following type errors:
$ poetry run mypy --show-error-codes --show-error-context test_open_ut.py
test_open_ut.py: note: In member "test_open_text_stream" of class "TestOpen":
test_open_ut.py:20: error: Incompatible types in assignment (expression has type "TextIO", variable has type "TextIOBase") [assignment]
test_open_ut.py:21: error: Subclass of "TextIO" and "TextIOBase" cannot exist: would have incompatible method signatures [unreachable]
test_open_ut.py: note: In member "test_open_buffered_stream" of class "TestOpen":
test_open_ut.py:26: error: Incompatible types in assignment (expression has type "BinaryIO", variable has type "BufferedIOBase") [assignment]
test_open_ut.py:27: error: Subclass of "BinaryIO" and "BufferedIOBase" cannot exist: would have incompatible method signatures [unreachable]
test_open_ut.py: note: In member "test_open_raw_stream" of class "TestOpen":
test_open_ut.py:32: error: Incompatible types in assignment (expression has type "BinaryIO", variable has type "RawIOBase") [assignment]
test_open_ut.py:33: error: Subclass of "BinaryIO" and "RawIOBase" cannot exist: would have incompatible method signatures [unreachable]
Your Environment
- Mypy version used: 0.910
- Mypy command-line flags:
--show-error-codes --show-error-context
- Mypy configuration options from
mypy.ini
(and other config files):
[mypy]
# Kept as seperate config file as some plugins don't support pyproject.toml
# (e.g pydantic.mypy)
# https://mypy.readthedocs.io/en/stable/config_file.html
python_version = 3.7
strict = True
warn_unreachable = True
warn_unused_configs = True
- Python version used: 3.7
- Operating system and version: Fedora 34
The code for this can be found here