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?

Asked By: paul23

||

Answers:

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.

Answered By: Stop harming Monica

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().

Answered By: Eugene Yarmash

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.

Answered By: toto_tico

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()
Answered By: Kache
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.