The correct way to annotate a "file type" in Python
Question:
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?
Answers:
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()
.
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.
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()
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?
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.BinaryIOGeneric type
IO[AnyStr]
and its subclassesTextIO(IO[str])
andBinaryIO(IO[bytes])
represent the types of I/O streams such as
returned byopen()
.
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.
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()