-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Fix contextlib.asynccontextmanager
to work with coroutine functions
#10753
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This comment has been minimized.
This comment has been minimized.
Could you defer that to a separate PR, so we can weigh it up on its own? |
Technically, this line is not quite correct as well: typeshed/stdlib/contextlib.pyi Line 76 in e1b6006
Because CPython calls |
Diff from mypy_primer, showing the effect of this PR on open source code: prefect (https://github.com/PrefectHQ/prefect)
- src/prefect/client/base.py:37: error: Argument 1 to "asynccontextmanager" has incompatible type "Callable[[Any], AbstractContextManager[None]]"; expected "Callable[[Any], AsyncIterator[<nothing>]]" [arg-type]
+ src/prefect/client/base.py:37: error: Argument 1 to "asynccontextmanager" has incompatible type "Callable[[Any], AbstractContextManager[None]]"; expected "Callable[[Any], Coroutine[Any, Any, AsyncIterator[<nothing>]]]" [arg-type]
|
perfect's annotation is not perfect: https://github.com/PrefectHQ/prefect/blob/d739f53f4ae7cbea8ca2f42e42881d4a80481abc/src/prefect/client/base.py#L37-L38 @asynccontextmanager
async def app_lifespan_context(app: FastAPI) -> ContextManager[None]: So, this is not a regression. |
It is `AsyncGenerator[None, None]` and not `ContextManager` :) Found in python/typeshed#10753
@asynccontextmanager | ||
async def async_context() -> AsyncGenerator[str, None]: | ||
yield "example" | ||
|
||
|
||
async def async_gen() -> AsyncGenerator[str, None]: | ||
yield "async gen" | ||
|
||
|
||
@asynccontextmanager | ||
def async_cm_func() -> AsyncGenerator[str, None]: | ||
return async_gen() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All these test cases appear to pass on main
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, mypy already knows how to solve this on main
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, mypy already knows how to solve this on
main
👍
Then I'm confused. What's the problem we're trying to fix, if these tests all already pass?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeap, since it was fixed on main
, we can drop this fix from typeshed
This fails mypy currently: from contextlib import asynccontextmanager
from typing import AsyncIterator, AsyncGenerator
@asynccontextmanager
async def db_connection() -> AsyncGenerator[None, None]: ... But this doesn't: from contextlib import asynccontextmanager
from typing import AsyncIterator, AsyncGenerator
@asynccontextmanager
async def db_connection() -> AsyncGenerator[None, None]:
yield None I think this is because of the rules laid out in https://mypy.readthedocs.io/en/latest/more_types.html#asynchronous-iterators. https://mypy-play.net/?mypy=latest&python=3.11&gist=1c3911b9a48d2b1ec0e19e0cfee36b16 |
Right now a code from the docs: https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager does not type-check.
Example: https://mypy-play.net/?mypy=latest&python=3.11&gist=f20e230fa7b1af15064b2828dfd7dfd7
We are also required to have
AsyncGenerator
annotation here, because.athrow()
method is used in this function: https://github.com/python/cpython/blob/e8be0c9c5a7c2327b3dd64009f45ee0682322dcb/Lib/contextlib.py#L226 (since 3.8: https://github.com/python/cpython/blob/3.8/Lib/contextlib.py#L189)Runtime:
So, I went with the fix that also has some tests.