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

PythonPython 3.5Type Hinting

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionpaul23View Question on Stackoverflow
Solution 1 - PythonEugene YarmashView Answer on Stackoverflow
Solution 2 - PythonStop harming MonicaView Answer on Stackoverflow
Solution 3 - Pythontoto_ticoView Answer on Stackoverflow
Solution 4 - PythonKacheView Answer on Stackoverflow