sys.stdout 和文件的正确输入

Proper typing for sys.stdout and files

我正在尝试创建一个方法来处理表示文件名的字符串、Path 对象或已经打开的输出流(sys.stdoutopen('...', 'w'))。我正在尝试正确设置 mypy 的类型以检查它们。

到目前为止我得到了:

import io
from pathlib import Path
from typing import Union, TextIO, Text


def generate(output: Union[Text, Path, TextIO]) -> None:
    if isinstance(output, io.IOBase):
        output.write("data")
    else:
        if isinstance(output, Text):
            output = Path(output)
        with output.open("w") as output_file:
            output_file.write("data")

但是mypy一直在抱怨

Item "TextIO" of "Union[Path, TextIO]" has no attribute "open"

AFAIK,TextIO 是用于文本文件的正确类型,但无法针对此类型进行 isinstance 检查。代码结构确保在错误点我们不能有一个 TestIO 对象,因为它已在上一个分支中处理过。

我应该如何标记这里的所有类型?

这段代码可以重写如下,在 Path 分支中隔离 open,因为 Mypy 理解 isinstance 检查,并在一个地方调用 write

import io
from pathlib import Path
from typing import Union, TextIO, Text
from contextlib import ExitStack


def generate(output: Union[Text, Path, TextIO]) -> None:
    with ExitStack() as stack:
        if isinstance(output, Text):
            output = Path(output)
        if isinstance(output, Path):
            output = stack.enter_context(output.open("w"))
        output.write("data")