如何在PyCharm中正确注解ContextManager?

4xrmg8kj  于 2022-11-23  发布在  PyCharm
关注(0)|答案(2)|浏览(125)

如何在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(从而启用border_fPath方法的自动完成)?当然,我可以在每个with语句后添加一个注解,如# type: Path,但似乎可以通过正确注解temp_border_file来完成。
我尝试将Pathtyping.Iterator[Path]typing.Generator[Path, None, None]作为temp_border_file的返回类型,并在上下文管理器的代码中将# type: Path添加到borders_file上,但似乎没有帮助。

mdfafbf1

mdfafbf11#

下面是一个肮脏的解决方案。将破坏mypy。最好不要使用它。
我相信您可以从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
lskq00tm

lskq00tm2#

这是当前的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有望修复该问题,因此无法保证将来能够正常工作

相关问题