Skip to content

Remove typing.AwaitableGenerator #13804

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
AlanBogarin opened this issue Apr 7, 2025 · 3 comments
Closed

Remove typing.AwaitableGenerator #13804

AlanBogarin opened this issue Apr 7, 2025 · 3 comments
Labels
status: deferred Issue or PR deferred until some precondition is fixed

Comments

@AlanBogarin
Copy link

AlanBogarin commented Apr 7, 2025

While manipulating coroutines, I came across AwaitableGenerator. Everything was going well until I noticed it had four type parameters. So, I checked the code.
Apparently, they have an additional type variable _S, which, to me, makes no sense since it's not used in the protocol.

So, I want to know if this feature is intentional and if it has any use.
If not, I think it's appropriate to follow the Generator[YieldT, SendT, ReturnT] structure because it is a generator but it supports await.


Blocked by python/mypy#8240 and pyright.

@brianschubert
Copy link
Contributor

I don't know the background, but mypy makes use of this, e.g. here https://github.com/python/mypy/blob/749f2584da9425173d68eb220db7e92aa13ad8ea/mypy/checkexpr.py#L6361-L6382

So I would say it's intentional :)

@srittau
Copy link
Collaborator

srittau commented Apr 7, 2025

AwaitableGenerator should probably not exist in typeshed. It's a holdover from when mypy and typeshed were tightly coupled. Cf. python/mypy#8699 and python/mypy#8240.

@srittau srittau changed the title Unused type variable in AwaitableGenerator Remove typing.AwaitableGenerator Apr 7, 2025
@srittau srittau added the status: deferred Issue or PR deferred until some precondition is fixed label Apr 7, 2025
@AlanBogarin
Copy link
Author

I have a proposal for typing generator-based coroutines.

When using yield from with a types.CoroutineType, replace AwaitableGenerator with Generator.

This is consistent with its runtime type types.GeneratorType, prevents using await if it is not decorated with @types.coroutine, and Generator has existed since v3.5.

Some drawbacks:
Extending linters’ functionality to determine the types involved in a coroutine for yield from.

from __future__ import annotations

import types
import asyncio

from collections.abc import Generator
from typing import Any

@types.coroutine
def generator_a(): # () -> Generator[None, Any, None]
    yield None

# @types.coroutine
def generator_b() -> Generator[Any, Any, None]:
    yield from asyncio.sleep(1)  # type: ignore[misc]

# () -> AwaitableGenerator[Any, Any, None, Any]
def generator_c():
    yield from asyncio.sleep(1)

async def test_awaitable() -> None:
    await generator_a() # ok
    await generator_b()  # TypeError! without @coroutine
    await generator_c() # bad: no @coroutine mark

Taking advantage of the topic: inspect can detect these objects marked with @types.coroutine via inspect.isawaitable, but it lacks an introspection function specifically for them.

def isgeneratorcoroutine(o: object) -> typing.TypeGuard[types.GeneratorType[Any, Any, Any]]:
    return inspect.isgenerator(o) and bool(o.gi_code.co_flags & inspect.CO_ITERABLE_COROUTINE)

@srittau srittau closed this as completed Apr 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: deferred Issue or PR deferred until some precondition is fixed
Projects
None yet
Development

No branches or pull requests

3 participants