8000 Mypy doesn't work well with AsyncGenerator and @abstractmethod · Issue #18681 · python/mypy · GitHub
[go: up one dir, main page]

Skip to content

Mypy doesn't work well with AsyncGenerator and @abstractmethod #18681

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

Closed
1st opened this issue Feb 14, 2025 · 5 comments
Closed

Mypy doesn't work well with AsyncGenerator and @abstractmethod #18681

1st opened this issue Feb 14, 2025 · 5 comments
Labels
bug mypy got something wrong

Comments

@1st
Copy link
1st commented Feb 14, 2025

Bug Report

Mypy doesn't work well with AsyncGenerator and @abstractmethod

To Reproduce

Working (without async def): https://mypy-play.net/?mypy=latest&python=3.12&gist=b3f4c282f2435ac7bbbee2f435de3de7

Not working (with async def): https://mypy-play.net/?mypy=latest&python=3.12&gist=83f18b68c8ce201ecc907714bf947571

Image

Expected Behavior

I want to define "async def" method with @abstractmethod decorator, to show that all subclasses need to use asynchronous version. But problem is that when I do this - mypy gets crazy and tells that it has a problem in implementation of the interface method.

I think that problem is in usage of yield in the actual method to make it a generator, and just pass for the abstract method, that is missing yield. but in this case we sacrifice the correct definition of the base method and it seems misleading for developer that want to implement the base method that is missing he async keyword.

Actual Behavior

Return type "AsyncGenerator[int, None]" of "get" incompatible with return type "Coroutine[Any, Any, AsyncGenerator[int, None]]" in supertype "Base" [override]

@1st 1st added the bug mypy got something wrong label Feb 14, 2025
@TeamSpen210
Copy link
Contributor

Yep, it's the lack of yield, meaning the checker just wraps AsyncGenerator in Coroutine. If you make the abstract method a synchronous method it'll work fine, since the only difference between the different function types is their return type.

@1st
Copy link
Author
1st commented Feb 14, 2025

Yep, it's the lack of yield, meaning the checker just wraps AsyncGenerator in Coroutine. If you make the abstract method a synchronous method it'll work fine, since the only difference between the different function types is their return type.

Can you give an example of how to define asynchronous def as abstract method? Maybe I miss something

@TeamSpen210
Copy link
Contributor

Just do def func(self) -> Coroutine[int]:, or the same with AsyncGenerator, Generator or superclasses of those. It’s more explicit, but there’s no wrapping going on so the result is clear.

@1st
Copy link
Author
1st commented Feb 15, 2025

Just do def func(self) -> Coroutine[int]:, or the same with AsyncGenerator, Generator or superclasses of those. It’s more explicit, but there’s no wrapping going on so the result is clear.

My target goal is to define asynchronous abstract method to show the interface to use to implement a final class. I posted two links with code and just wondering how to tell mypy to keep my abstract as it is. Maybe I need use another decorator, like async_abstract or something like this?

@sterliakov
Copy link
Collaborator

This is just another manifestation of #5385 with s/Protocol/ABC/ (or also #5070 with more discussion, if you prefer). The most common approach that still uses async def for intuitively correct interface is

class Base(ABC):
    @abstractmethod
    async def get(self, start: int, end: int) -> AsyncGenerator[int, None]:
        if False: yield 1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong
Projects
None yet
Development

No branches or pull requests

3 participants
0