Skip to content
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

AsyncGenerator abstractmethods typechecked as coroutine incorrectly #2287

Closed
SandyChapman opened this issue Jan 25, 2022 · 4 comments
Closed
Labels
bug Something isn't working fixed in next version (main) A fix has been implemented and will appear in an upcoming version

Comments

@SandyChapman
Copy link

I'm trying to define an abstract base class with an abstractmethod that returns an AsyncGenerator. The typechecker appears to operate inconsistently between usages of the abstract base vs concrete implementations.

E.g.

"""Base class for Extractors."""

import abc
from typing import AsyncGenerator
import asyncio


class AbstractBase(abc.ABC):
    """ABC for Extractors."""

    @abc.abstractmethod
    async def get_entries(self) -> AsyncGenerator[str, None]:
        """Retrieves all of the entries given by this extractor."""
        ...

class Concrete(AbstractBase):

    async def get_entries(self) -> AsyncGenerator[str, None]:
        await asyncio.sleep(0.5)
        yield "Implement2-1"
        await asyncio.sleep(1.5)
        yield "Implement2-2"

async def async_main(base: AbstractBase):
    async for x in base.get_entries():  # "Coroutine[Any, Any, AsyncGenerator[str, None]]" is not iterable  "__aiter__" method not defined reportGeneralTypeIssues
        print(x)
    async for x in Concrete().get_entries():
        print(x)


def main():
    impl = Concrete()
    asyncio.run(async_main(impl))

if __name__ == '__main__':
    main()

Removing async from the abstractmethod causes the error to disappear, but I don't believe this is the correct annotation (and pylint also reports it as an error that the base class signature does not match the concrete class). This doesn't appear to report an error when running pyright 1.1.208 directly.

pyrightconfig.json:

{
    "typeCheckingMode": "basic"
}

I'm running Pylance v2022.1.3 on VS Code Version: 1.63.2 (Universal) (Mac OS)

image

@erictraut
Copy link
Contributor

The problem is that the abstract method is missing a yield statement, so it's being treated differently. If you add a yield "" statement before the ..., it will work as expected. Without a yield statement, it's not considered a generator. Given that you've annotated it explicitly as returning a generator object, it should probably still be considered a generator. I'll look into fixing that.

For what it's worth, mypy issues the same error in this case.

@SandyChapman
Copy link
Author

Thanks, @erictraut ! This seems like a less common usage, so thanks for addressing it.

@erictraut
Copy link
Contributor

I've added special-case code to handle this condition. It will be fixed in the next release.

@erictraut erictraut added bug Something isn't working fixed in next version (main) A fix has been implemented and will appear in an upcoming version and removed triage labels Jan 25, 2022
@debonte
Copy link
Contributor

debonte commented Feb 4, 2022

This issue was fixed in version 2022.1.5. You can find the changelog here: CHANGELOG.md

@debonte debonte closed this as completed Feb 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working fixed in next version (main) A fix has been implemented and will appear in an upcoming version
Projects
None yet
Development

No branches or pull requests

3 participants