如何在PyCharm中正确注释ContextManager?

时间:2018-03-17 11:06:29

标签: pycharm typing contextmanager

如何在PyCharm中注释contextmanager的yield类型,以便正确猜出with子句中使用的值的类型 - 就像它猜测f一样在with open(...) as 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(从而为Path上的border_f方法启用自动完成功能?当然,我可以在每个# type: Path语句后发表with之类的评论,但似乎可以通过正确注释temp_border_file来完成此操作。

我尝试Pathtyping.Iterator[Path]typing.Generator[Path, None, None]作为temp_border_file的返回类型,并在# type: Path内添加borders_file上下文管理器的代码,但它似乎没有帮助。

2 个答案:

答案 0 :(得分:4)

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

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

答案 1 :(得分:1)

这是当前的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]注释返回类型还有一种更简单的解决方法,但是有多种理由反对这种情况:

  • mypy将为此注释正确发出错误,如PyCharm问题中所述。
  • 不能保证此方法将来会成功,因为PyCharm有望解决此问题,从而打破此变通办法