Skip to content
Advertisement

mypy declares IO[bytes] incompatible with BinaryIO

Consider the following code:

from io      import TextIOWrapper
from typing  import List
from zipfile import ZipFile

def read_zip_lines(zippath: str, filename: str) -> List[str]:
    with ZipFile(zippath) as zf:
        with zf.open(filename) as bfp:
            with TextIOWrapper(bfp, 'utf-8') as fp:
                return fp.readlines()

Running mypy v0.782 on the above code under Python 3.6.9 fails with the following error:

zfopen.py:8: error: Argument 1 to "TextIOWrapper" has incompatible type "IO[bytes]"; expected "BinaryIO"

However, I feel that this code should not be regarded as an error, as ZipFile.open() returns a binary filehandle, which TextIOWrapper accepts. Moreover, IO[bytes] and BinaryIO are (as far as I understand) effectively the same thing; it’s just that BinaryIO is declared as a subclass of IO[bytes]. I would naïvely expect IO[bytes] to be accepted everywhere that BinaryIO is, except that’s not how subclasses work, and I’m not sure how to properly make use of this subclassing when typing.

Who is in error here, and how does the error get fixed?

  • Is typeshed in error for declaring the return type of ZipFile.open() as IO[bytes] instead of BinaryIO?
  • Is typeshed in error for declaring the type of the first argument to TextIOWrapper as BinaryIO instead of IO[bytes]?
  • Is the typing module in error for making BinaryIO a subclass of IO[bytes] instead of an alias?
  • Is my code in error for not performing some sort of cast on bfp?
  • Is my thinking in error for expecting bfp to be passable to TextIOWrapper unmodified?

Advertisement

Answer

This shorter test case with mypy 0.782 gets the same error:

    binary_file = io.open('foo.bin', 'rb')
    text_file = io.TextIOWrapper(binary_file, encoding='utf-8', newline='')

whether binary_file is explicitly declared as IO[bytes] or inferred.

Fix: Use mypy 0.770 or mypy 0.790.

It was a regression in mypy’s typeshed (Issue 4349) and the fix is in mypy 0.790, fixing both zipfile.open() and io.open().

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement