When writing a class that implements a file-like interface we can inherit one of the abstract base classes from the io module, for example TextIOBase, as shown in Adapt an iterator to behave like a file-like object in Python.
On the other hand, in type annotations we are supposed to use the classes derived from typing.IO (e.g. TextIO) to represent such objects, as shown in Type hint for a file or file-like object? or Type-checking issue with io.TextIOBase in a Union.
However, this does not seem to work as I expected:
import io
import sys
import typing
class MyIO(io.TextIOBase):
def write(self, text: str):
pass
def hello(f: typing.TextIO):
f.write('hello')
hello(sys.stdout) # type checks
hello(open('temp.txt', 'w')) # type checks
hello(MyIO()) # does not type check
When running mypy on this code (using Python 3.7.3 and mypy 0.910), we get
error: Argument 1 to "hello" has incompatible type "MyIO"; expected "TextIO"
Question
How can the MyIO class be written such that it is accepted as a function argument of type typing.TextIO (without just using typing.cast(typing.TextIO, ...))?
Failed attempts
Using
typing.TextIOas a base class is not possible:When using
class MyIO(typing.TextIO):error: Cannot instantiate abstract class "MyIO" with abstract attributes "__enter__", "__exit__", ... and "writelines" (15 methods suppressed)
When using
class MyIO(io.TextIOBase, typing.TextIO)::error: Definition of "readlines" in base class "IOBase" is incompatible with definition in base class "IO"
and the same for several other methods.
Overriding
__new__and annotatingtyping.TextIOas return type does not work:def __new__(cls, *args, **kwargs) -> typing.TextIO: return super().__new__(cls, *args, **kwargs)results in
error: Incompatible return type for "__new__" (returns "TextIO", but must return a subtype of "MyIO")
error: Incompatible return value type (got "MyIO", expected "TextIO")
Or is this already supposed to work, and I'm using too old a version of Python and/or mypy? Using --python-version 3.8 or 3.9 or 3.10 as option for mypy does not change anything, however.