classification
Title: anext_awaitable is not a collections.abc.Generator
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 3.11, Python 3.10
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: asvetlov, graingert, jab, lordmauve, lukasz.langa, miss-islington, pablogsal, yselivanov
Priority: release blocker Keywords: patch

Created on 2021-08-20 17:24 by lordmauve, last changed 2021-09-07 11:07 by pablogsal. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 27955 merged pablogsal, 2021-08-25 22:07
PR 28198 merged miss-islington, 2021-09-07 10:30
Messages (5)
msg399982 - (view) Author: Daniel Pope (lordmauve) * Date: 2021-08-20 17:24
The anext_awaitable object returned by anext(..., default) does not support .send()/.throw(). It only supports __next__().

So we can pass messages from the suspending coroutine to the event loop but not from the event loop to the suspending coroutine.

trio and curio rely on both directions working. (I don't know about asyncio.)

For example, this trio code fails:

    import trio

    async def produce():
       for v in range(3):
           await trio.sleep(1)
           yield v

    async def consume():
       p = produce()
       while True:
            print(await anext(p, 'finished'))

    trio.run(consume)

raising AttributeError: 'anext_awaitable' object has no attribute 'send'.

I realise that any awaitable that wants to await another awaitable must return not an iterator from __await__() but something that implements the full PEP-342 generator protocol. Should PEP-492 section on __await__()[1] say something about that?

[1] https://www.python.org/dev/peps/pep-0492/#await-expression
msg399993 - (view) Author: Thomas Grainger (graingert) * Date: 2021-08-20 20:39
it also fails with asyncio.create_task

```
import asyncio

async def agen():
    yield

async def main():
    p = agen()
    await asyncio.create_task(anext(p, 'finished'))

asyncio.run(main())
```

```
Traceback (most recent call last):
  File "/home/graingert/projects/datapraxis/analysis/foo.py", line 10, in <module>
    asyncio.run(main())
  File "/usr/lib/python3.10/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.10/asyncio/base_events.py", line 641, in run_until_complete
    return future.result()
  File "/home/graingert/projects/asyncio-demo/foo.py", line 8, in main
    await asyncio.create_task(anext(p, 'finished'))
  File "/usr/lib/python3.10/asyncio/tasks.py", line 337, in create_task
    task = loop.create_task(coro)
  File "/usr/lib/python3.10/asyncio/base_events.py", line 433, in create_task
    task = tasks.Task(coro, loop=self, name=name)
TypeError: a coroutine was expected, got <anext_awaitable object at 0x7f67f5587550>
```


there's also a problem with cancelling and aclosing an async gen this way:

```
import asyncio
import contextlib

async def agen():
    await asyncio.sleep(1)
    yield

async def main():
    async with contextlib.aclosing(agen()) as p:
        asyncio.current_task().cancel()
        try:
            await anext(p, 'finished')
        except asyncio.CancelledError:
            pass

asyncio.run(main())
```

```
an error occurred during closing of asynchronous generator <async_generator object agen at 0x7f2061a61dc0>
asyncgen: <async_generator object agen at 0x7f2061a61dc0>
Traceback (most recent call last):
  File "/usr/lib/python3.10/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.10/asyncio/base_events.py", line 641, in run_until_complete
    return future.result()
  File "/home/graingert/projects/asyncio-demo/foo.py", line 9, in main
    async with contextlib.aclosing(agen()) as p:
  File "/usr/lib/python3.10/contextlib.py", line 366, in __aexit__
    await self.thing.aclose()
RuntimeError: aclose(): asynchronous generator is already running

During handling of the above exception, another exception occurred:

RuntimeError: aclose(): asynchronous generator is already running
Traceback (most recent call last):
  File "/home/graingert/projects/datapraxis/analysis/foo.py", line 16, in <module>
    asyncio.run(main())
  File "/usr/lib/python3.10/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.10/asyncio/base_events.py", line 641, in run_until_complete
    return future.result()
  File "/home/graingert/projects/asyncio-demo/foo.py", line 9, in main
    async with contextlib.aclosing(agen()) as p:
  File "/usr/lib/python3.10/contextlib.py", line 366, in __aexit__
    await self.thing.aclose()
RuntimeError: aclose(): asynchronous generator is already running
```
msg400039 - (view) Author: Pablo Galindo Salgado (pablogsal) * (Python committer) Date: 2021-08-21 18:56
I am marking this as a release blocker, given that this is probably going to trip a lot of users.
msg401223 - (view) Author: Pablo Galindo Salgado (pablogsal) * (Python committer) Date: 2021-09-07 10:30
New changeset 533e725821b15e2df2cd4479a34597c1d8faf616 by Pablo Galindo Salgado in branch 'main':
bpo-44963: Implement send() and throw() methods for anext_awaitable objects (GH-27955)
https://github.com/python/cpython/commit/533e725821b15e2df2cd4479a34597c1d8faf616
msg401233 - (view) Author: miss-islington (miss-islington) Date: 2021-09-07 10:52
New changeset adc80a58f9683468e0ba5a6eed72040f7f6ba405 by Miss Islington (bot) in branch '3.10':
bpo-44963: Implement send() and throw() methods for anext_awaitable objects (GH-27955)
https://github.com/python/cpython/commit/adc80a58f9683468e0ba5a6eed72040f7f6ba405
History
Date User Action Args
2021-09-07 11:07:01pablogsalsetstatus: open -> closed
resolution: fixed
stage: patch review -> resolved
2021-09-07 10:52:57miss-islingtonsetmessages: + msg401233
2021-09-07 10:30:23miss-islingtonsetnosy: + miss-islington
pull_requests: + pull_request26623
2021-09-07 10:30:18pablogsalsetmessages: + msg401223
2021-08-25 22:07:52pablogsalsetkeywords: + patch
stage: patch review
pull_requests: + pull_request26401
2021-08-25 21:33:58pablogsalsetnosy: + lukasz.langa
2021-08-21 18:56:28pablogsalsetpriority: normal -> release blocker

messages: + msg400039
2021-08-21 13:20:41graingertsetnosy: + pablogsal
2021-08-21 00:36:02terry.reedysetnosy: + asvetlov, yselivanov
2021-08-20 20:39:05graingertsetnosy: + graingert
messages: + msg399993
2021-08-20 20:17:56jabsetnosy: + jab
2021-08-20 17:24:00lordmauvecreate