python / python/cpython

Implement `anext` and `aiter` in pure Python

Open
#157,361 8 comments 2 reactions 1 assignee View on GitHub

@kumaraditya303 is already working on this.

Since Sep 12, 2026.

3.16 interpreter-core topic-asyncio type-feature
Dominant language
Python
Stars
77.2k
Forks
35.9k
PR merge metrics
PR metrics pending

Description

Feature or enhancement

Feature or enhancement

I propose to implement anext() and aiter() in Python instead of C, compiled at interpreter startup and copied into builtins. This removes the private anext_awaitable, async_callable_iterator and async_callable_iterator_awaitable types.

anext(it, default) becomes a plain coroutine that awaits type(it).__anext__(it) and converts StopAsyncIteration into the default. The callable form of aiter() (gh-64862) becomes a small class with async def __anext__ that calls and awaits the callable and turns the sentinel or stop_exception into StopAsyncIteration. Semantics stay the same.

The motivation is #157032 and #157044: the C awaitables break the asyncio await graph. capture_call_graph walks cr_await/ag_await, and these types have neither, so the graph stops at the frame calling anext(it, default) or iterating aiter(callable, sentinel) and hides where the task is actually suspended. This would fix #157032, #157044 without any special casing.

Repro with a class-based async iterator:

import asyncio

async def fetch():
    await asyncio.sleep(10)

class AIter:
    def __aiter__(self): return self
    async def __anext__(self):
        await fetch()
        return 1

async def consumer():
    await anext(AIter(), None)

async def main():
    t = asyncio.create_task(consumer(), name="consumer")
    for _ in range(3):
        await asyncio.sleep(0)
    asyncio.print_call_graph(t)
    t.cancel()

asyncio.run(main())

Before:

* Task(name='consumer', id=0x10a42c7d0)
  + Call stack:
  |   File 'demo.py', line 13, in async consumer()

After:

* Task(name='consumer', id=0x108959b80)
  + Call stack:
  |   File 'Lib/asyncio/tasks.py', line 707, in async sleep()
  |   File 'demo.py', line 4, in async fetch()
  |   File 'demo.py', line 9, in async AIter.__anext__()
  |   File '<builtins>', line 26, in async _anext_with_default()
  |   File 'demo.py', line 13, in async consumer()
Linked PRs
  • gh-157362
  • gh-157687

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.