pythonpython-typingduck-typing

Why io.BytesIO is not a subclass of typing.BinaryIO, and io.StringIO is neither a subclass of typing.TextIO?


When use match-case pattern, I found that case typing.BinaryIO(): can not match object with type io.BytesIO.

So I try this:

import io
import typing

assert issubclass(list, typing.Sequence)
assert issubclass(list, typing.List)
assert issubclass(dict, typing.Mapping)
assert issubclass(dict, typing.Dict)
# assert issubclass(io.StringIO, typing.TextIO) # failed!
# assert issubclass(io.BytesIO, typing.BinaryIO) # failed!

a = [1, 2, 3]
b = {"a": 1, "b": 2, "c": 3}
c = io.BytesIO(b"123123123")
d = io.StringIO("123123123")

assert isinstance(a, typing.List)
assert isinstance(a, typing.Sequence)
assert isinstance(b, typing.Dict)
assert isinstance(b, typing.Mapping)
# assert isinstance(c, typing.BinaryIO) # failed!
# assert isinstance(d, typing.TextIO) # failed!

It shows that io.BytesIO and io.StringIO are not subclass of typing.BinaryIO and typing.TextIO, which in my opinion is strange since official documents never hint me to be carefule about this behaviour (or at least I never found it).

What is more strange is a .pyi stub file i found, its path is /data/users/XXXXXX/.vscode-server/extensions/ms-python.vscode-pylance-2024.11.1/dist/typeshed-fallback/stdlib/_io.pyi. I found this line in the stub file: class BytesIO(BufferedIOBase, _BufferedIOBase, BinaryIO):, which implies that things should be as they should be for my intuition.

Is this intentional design or a bug? If is a design, why?

I'm using Python 3.12.3 with mypy 1.13.0, under VSCode 1.93.1 with pylance 2024.11.1 extension.


Solution

  • Classes in the typing module are not meant to be used for instance / subclass checks at runtime. Their purpose is type hinting.

    If you want to use instance / subclass checks like that, check out collections.abc, especially this overview. For io.StringIO and io.BytesIO, their abstract base classes are io.TextIOBase and io.BufferedIOBase. Their common base class is io.IOBase.