The correct way to annotate a "file type" in Python
PythonPython 3.5Type HintingPython Problem Overview
In modern versions of Python one can have static type analysis using function annotations, according to PEP 484. This is made easy through the typing module.
Now I'm wondering how I would give a "type hint" towards a "filestream".
def myfunction(file: FILETYPE):
pass
with open(fname) as file:
myfunction(file)
What would I insert as FILETYPE
?
Using print(type(file))
returns <class '_io.TextIOWrapper'>
which isn't clear at all.
Isn't there a generic "file" type?
Python Solutions
Solution 1 - Python
You can use typing.IO
, typing.TextIO
, and typing.BinaryIO
to represent different types of I/O streams. To quote the documentation:
> сlass typing.IO
> class typing.TextIO
> class typing.BinaryIO
>
> Generic type IO[AnyStr]
and its subclasses TextIO(IO[str])
and BinaryIO(IO[bytes])
represent the types of I/O streams such as
> returned by open()
.
Solution 2 - Python
I think you want io.IOBase
, "[t]he abstract base class for all I/O classes, acting on streams of bytes."
Note that this includes also in-memory streams like io.StringIO
and io.BytesIO
. Read the documentation on the module io
for details.
Solution 3 - Python
Either this:
from typing import TextIO # or IO or BinaryIO
def myfunction(file: TextIO ):
pass
OR this
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import TextIO # or IO or BinaryIO
def myfunction(file: 'TextIO'):
pass
The second approach would avoid to import the class during execution. Although python would still have to import TYPE_CHECKING
during execution, it is a good practice to avoid importing classes for type hinting only: (1) doesn't get executed (just parsed), and (2) it could avoid cyclic imports.
Solution 4 - Python
typeshed has a SupportsRead
protocol:
from __future__ import annotations
from typing import TYPE_CHECKING, AnyStr
if TYPE_CHECKING:
from _typeshed import SupportsRead
def takes_readable_str(fo: SupportsRead[str]):
return fo.read()
def takes_readable_bytes(fo: SupportsRead[bytes]):
return fo.read()
def takes_readable_any(fo: SupportsRead[AnyStr]):
return fo.read()