Skip to content

Remove typing.AwaitableGenerator #13804

Description

@AlanBogarin

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.

Activity

  1. brianschubert commented on Apr 7, 2025

    @brianschubert
    Collaborator

    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 :)

  2. srittau commented on Apr 7, 2025

    @srittau
    Collaborator

    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.

  3. changed the title [-]Unused type variable in AwaitableGenerator[/-] [+]Remove typing.AwaitableGenerator[/+] on Apr 7, 2025
  4. added
    status: deferredIssue or PR deferred until some precondition is fixed
    on Apr 7, 2025
  5. AlanBogarin commented on Apr 9, 2025

    @AlanBogarin
    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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: deferredIssue or PR deferred until some precondition is fixed

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions