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.
ContextDecorator makes it possible to use a context manager in both an ordinary with statement and also as a function decorator. Note that there is one additional limitation when using context managers as function decorators: there's no way to access the return value of __enter__() .
A context manager usually takes care of setting up some resource, e.g. opening a connection, and automatically handles the clean up when we are done with it. Probably, the most common use case is opening a file. with open('/path/to/file.txt', 'r') as f: for line in f: print(line)
Overview. The contextlib module of Python's standard library provides utilities for resource allocation to the with statement. The with statement in Python is used for resource management and exception handling. Therefore, it serves as a good Context Manager.
We can simply make any function as a context manager with the help of contextlib. contextmanager decorator without having to write a separate class or __enter__ and __exit__ functions.
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
This is a current PyCharm issue: PY-36444
A workaround for the issue is to rewrite an example code of:
from contextlib import contextmanager
@contextmanager
def generator_function():
yield "some value"
with generator_function() as value:
print(value.upper()) # no PyCharm autocompletion
to
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
There is also an easier workaround of annotating the return type with ContextManager[str]
but there are multiple reasons against this:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With