如何在 PyCharm 中正确注释 ContextManager?

How to properly annotate a ContextManager in PyCharm?

如何在 PyCharm 中注释 contextmanager 的 yield 类型,以便它正确猜测 with 子句中使用的值的类型 - 就像它猜测的那样在 with open(...) as f 中创建的 f 是一个文件?

例如,我有一个这样的上下文管理器:

@contextlib.contextmanager
def temp_borders_file(geometry: GEOSGeometry, name='borders.json'):
    with TemporaryDirectory() as temp_dir:
        borders_file = Path(dir) / name
        with borders_file.open('w+') as f:
            f.write(geometry.json)
        yield borders_file

with temp_borders_file(my_geom) as borders_f:
    do_some_code_with(borders_f...)

如何让 PyCharm 知道像这样创建的每个 borders_f 都是 pathlib.Path(从而为 [=19] 上的 Path 方法启用自动完成=])?当然,我可以在每个 with 语句之后做一个像 # type: Path 这样的注释,但似乎可以通过适当注释 temp_border_file.

来完成

我尝试将 Pathtyping.Iterator[Path]typing.Generator[Path, None, None] 作为 temp_border_file 的 return 类型,并在 borders_file 在上下文管理器的代码中,但它似乎没有帮助。

我相信您可以使用 typing 中的 ContextManager,例如:

import contextlib
from typing import ContextManager
from pathlib import Path


@contextlib.contextmanager
def temp_borders_file() -> ContextManager[Path]:
    pass


with temp_borders_file() as borders_f:
    borders_f  # has type Path here

这是当前 PyCharm 期:PY-36444

该问题的解决方法是重写示例代码:

from contextlib import contextmanager

@contextmanager
def generator_function():
    yield "some value"

with generator_function() as value:
    print(value.upper())  # no PyCharm autocompletion

from contextlib import contextmanager
from typing import ContextManager

def wrapper() -> ContextManager[str]:
    @contextmanager
    def generator_function():
        yield "some value"

    return generator_function()

with wrapper() as value:
    print(value.upper())  # PyCharm autocompletion works

还有一个更简单的解决方法,即使用 ContextManager[str] 注释 return 类型,但有多种原因反对这样做:

  • mypy 将正确发出此注释的错误,如 PyCharm 问题中更详细的描述。
  • 这不能保证在未来工作,因为 PyCharm 有望解决问题并因此打破此解决方法