-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
Unexpected behavior regarding async generator #5070
Comments
Your The issue with overrides can be explained by the same logic: the base class's |
The There is unfortunately no simple solution, we may just document this in common issues. |
Thank you both, now I get it. My typo (which I will correct in a second) only added to my confusion. I agree that this probably should be explained in docs somewhere. |
Update: I started to use plain |
Summary: Came across this because we were wrapping functions returning `AsyncGenerator` inside an `Awaitable`, which was throwing false positive errors later on when we tried to call `__aiter__` on it, for instance. Turns out functions prefixed with `async` wrap the return type in a `Coroutine`, not an `Awaitable` (see: python/mypy#3569), and functions that are actually generators (contain a yield) just take the return annotation of `AsyncGenerator` at face value - otherwise, the function signature is understood as asynchronously returning a generator object just like any other async function (see: python/mypy#5070) Reviewed By: dkgi Differential Revision: D13864544 fbshipit-source-id: 0d201735252b77688a5491428cfb5818d000754b
I too like the plain |
A slightly different case to this (that is still fixed by doing class Base(abc.ABC):
@abc.abstractmethod
def run(self) -> AsyncIterator[int]:
raise NotImplementedError("must implement run()")
class A(Base):
def run(self) -> AsyncIterator[int]:
while True:
yield 1 This will fail with
By making it a generator it passes @abc.abstractmethod
def run(self) -> AsyncIterator[int]:
raise NotImplementedError("must implement run()")
if False:
yield 0 Even if the |
Sharing a similar example as the previous comment: approach.py: from abc import ABC, abstractmethod
from typing import Any, AsyncGenerator
class ChatApproach(ABC):
@abstractmethod
async def run(self, history: list[dict[str, str]], overrides: dict[str, Any], should_stream: bool) -> AsyncGenerator[dict, None]:
... chatreadretrieveread.py: from approaches.approach import ChatApproach
class ChatReadRetrieveReadApproach(ChatApproach):
async def run(self, history: list[dict[str, str]], overrides: dict[str, Any], should_stream: bool=False) -> AsyncGenerator[dict, None]: results in:
The "if False: yield" trick does work to remove the mypy errors. |
This has been documented at https://mypy.readthedocs.io/en/stable/more_types.html#asynchronous-iterators for a couple months now |
Took a stab at adding contextual help in #15883. (... Although, this wouldn't help #5070 (comment) since it's a difference in more than just the return type...) |
Trying to get typing work in an asynchronous code and I don't understand mypy's behavior.
Let's say we have two coroutines typed in the following way:
mypy:
So the type of the first one gets wrapped in
Awaitable
. I don't fully understand why. I thought allAsync...
are Awaitables by definition. I did not find anything about it but here #3576, which is not enough for me to get it.The same thing in case of methods:
mypy:
So now I cannot define abstract methods that are async generators, in a straightforward way.
Versions
Python 3.6.5
mypy==0.600
EDIT: I fixed a random typo @JelleZijlstra found and edited parts of the text based on the typo. Now the whole problem is clearer.
The text was updated successfully, but these errors were encountered: