Skip to content

asyncio no longer supports generator-based coroutines in 3.12+ #10116

@AlexWaygood

Description

@AlexWaygood

What the title says.

On Python 3.11:

>python -m asyncio
asyncio REPL 3.11.2 (tags/v3.11.2:878ead1, Feb  7 2023, 16:38:35) [MSC v.1934 64 bit (AMD64)] on win32
Use "await" directly instead of "asyncio.run()".
Type "help", "copyright", "credits" or "license" for more information.
>>> import asyncio
>>> def foo():
...     yield from []
...
>>> asyncio.create_task(foo())
<Task pending name='Task-1' coro=<foo() running at <console>:1>>
>>> exit()

On Python 3.12:

>python -m asyncio
Running PGUpdate|x64 interpreter...
asyncio REPL 3.12.0a7+ (heads/main-dirty:79b9db9295, Apr 28 2023, 22:41:05) [MSC v.1932 64 bit (AMD64)] on win32
Use "await" directly instead of "asyncio.run()".
Type "help", "copyright", "credits" or "license" for more information.
>>> import asyncio
>>> def foo():
...     yield from []
...
>>> asyncio.create_task(foo())
Traceback (most recent call last):
  File "C:\Users\alexw\coding\cpython\Lib\concurrent\futures\_base.py", line 449, in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
  File "C:\Users\alexw\coding\cpython\Lib\concurrent\futures\_base.py", line 401, in __get_result
    raise self._exception
  File "C:\Users\alexw\coding\cpython\Lib\asyncio\__main__.py", line 34, in callback
    coro = func()
           ^^^^^^
  File "<console>", line 1, in <module>
  File "C:\Users\alexw\coding\cpython\Lib\asyncio\tasks.py", line 377, in create_task
    task = loop.create_task(coro)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\alexw\coding\cpython\Lib\asyncio\base_events.py", line 436, in create_task
    task = tasks.Task(coro, loop=self, name=name, context=context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: a coroutine was expected, got <generator object foo at 0x000001E6821AA200>

@kumaraditya303 tells me that the same change has been made across asyncio on Python 3.12.

We'll need to change annotations like this:

def create_task(
coro: Generator[Any, None, _T] | Coroutine[Any, Any, _T], *, name: str | None = None, context: Context | None = None
) -> Task[_T]: ...

We should branch on sys.version_info, like this:

if sys.version_info >= (3, 12):
    def create_task(
        coro: Coroutine[Any, Any, _T], *, name: str | None = None, context: Context | None = None
    ) -> Task[_T]: ...
elif sys.version_info >= (3, 11):
    def create_task(
        coro: Generator[Any, None, _T] | Coroutine[Any, Any, _T], *, name: str | None = None, context: Context | None = None
    ) -> Task[_T]: ...
elif sys.version_info >= (3, 8):
    # etc.

We should probably make the change ASAP, so that people testing with the Python 3.12 betas get accurate type hints.

Metadata

Metadata

Assignees

No one assigned

    Labels

    help wantedAn actionable problem of low to medium complexity where a PR would be very welcomestubs: false negativeType checkers do not report an error, but shouldtopic: asyncioAsyncio-related issues

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions