Search code examples
pythonpycharmpython-typingcontextmanager

How to properly annotate a ContextManager in PyCharm?


How can I annotate the yield type of a contextmanager in PyCharm so that it properly guesses the type of the value used in the with clauses - just as it guesses that the f created in with open(...) as f is a file?

For example, I have a context manager like this:

@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...)

How do I let PyCharm know that every borders_f created like this is a pathlib.Path (and thus enable the autocompletion for the Path methods on border_f)? Of course, I can make a comment like # type: Path after every with statement, but it seems that this can be done by properly annotating temp_border_file.

I tried Path, typing.Iterator[Path] and typing.Generator[Path, None, None] as the return type of temp_border_file, as well as adding # type: Path on borders_file within the context manager's code, but it seems like it doesn't help.


Solution

  • Dirty workaround below. Will break mypy. Better don't use it.


    I believe you can use ContextManager from typing, e.g.:

    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