Skip to content

@overload doesn't work with @asynccontextmanager #17340

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

Open
alenzo-arch opened this issue Jun 6, 2024 · 2 comments
Open

@overload doesn't work with @asynccontextmanager #17340

alenzo-arch opened this issue Jun 6, 2024 · 2 comments
Labels
bug mypy got something wrong

Comments

@alenzo-arch
Copy link

Bug Report

When trying to annotate overloads for an asynccontextmanager, I think mypy incorrectly reports an invalid return type.

To Reproduce

from contextlib import asynccontextmanager, contextmanager
from typing import AsyncIterator, Iterator, overload

@overload
@asynccontextmanager
async def test_async() -> AsyncIterator[int]: ...


@overload
@asynccontextmanager
async def test_async(val: int = ...) -> AsyncIterator[int]: ...


@asynccontextmanager
async def test_async(val: int = 1) -> AsyncIterator[int]:
    yield val


@overload
@contextmanager
def test_sync() -> Iterator[int]: ...


@overload
@contextmanager
def test_sync(val: int = ...) -> Iterator[int]: ...


@contextmanager
def test_sync(val: int = 1) -> Iterator[int]:
    yield val

This gives an error of "Argument 1 to "asynccontextmanager" has incompatible type "Callable[[int], Coroutine[Any, Any, AsyncIterator[int]]]"; expected "Callable[[int], AsyncIterator[Never]]"

Where the synchronous version checks fine.

Expected Behavior

I expect the async version to work the same as the sync version

Actual Behavior

Mypy reports and error

mypy test.py
test.py:5: error: Argument 1 to "asynccontextmanager" has incompatible type "Callable[[], Coroutine[Any, Any, AsyncIterator[int]]]"; expected "Callable[[], AsyncIterator[Never]]"  [arg-type]
test.py:10: error: Argument 1 to "asynccontextmanager" has incompatible type "Callable[[int], Coroutine[Any, Any, AsyncIterator[int]]]"; expected "Callable[[int], AsyncIterator[Never]]"  [arg-type]
Found 2 errors in 1 file (checked 1 source file)

Your Environment

  • Mypy version used: 1.10.0
  • Mypy command-line flags: mypy test.py
  • Mypy configuration options from mypy.ini (and other config files):
  • Python version used: Python 3.11.4
@alenzo-arch alenzo-arch added the bug mypy got something wrong label Jun 6, 2024
@sterliakov
Copy link
Collaborator

sterliakov commented Jun 12, 2024

Funny enough, the following typechecks (note how async disappears in overload stubs). This seems to be the same kind of problem as functions/methods and decorators: too much of "indirectly applied" stuff confuses the checker. In your original snippet, the function is "async twice": mypy thinks that it returns a Coroutine which, when awaited, produces an AsyncIterator. But this only happens when applying a decorator to overloaded definition (see the full playground, reveal_type produces a right type indeed).

from contextlib import asynccontextmanager, contextmanager
from typing import AsyncIterator, Iterator, overload

@overload
@asynccontextmanager
def test_async() -> AsyncIterator[int]: ...


@overload
@asynccontextmanager
def test_async(val: int = ...) -> AsyncIterator[int]: ...


@asynccontextmanager
async def test_async(val: int = 1) -> AsyncIterator[int]:
    yield val

(I'm posting this more like a temporary workaround, this definitely looks like a typechecker bug to me, and pyright has no objections to your snippet)

@alenzo-arch
Copy link
Author

@sterliakov Thank for for addressing this as well as providing a temporary work around

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

Successfully merging a pull request may close this issue.

2 participants