'The correct way to annotate a "file type" in Python

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?



Solution 1:[1]

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 2:[2]

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 3:[3]

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

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 Alex Waygood