gh-157361: Implement anext() in Python instead of C - #157362
gh-157361: Implement anext() in Python instead of C#157362kumaraditya303 wants to merge 5 commits into
anext() in Python instead of C#157362Conversation
Remove the C implementation of the anext() builtin and the anext_awaitable helper type. Instead, compile a small Python source at interpreter startup and copy the resulting anext() function into the builtins dict. The Python version keeps the C semantics: __anext__ is looked up on the type and called eagerly, the one-argument form returns the awaitable unchanged, and the two-argument form wraps it in a coroutine that returns the default on StopAsyncIteration. The source is executed from pycore_init_builtins() rather than _PyBuiltin_Init(), since running bytecode requires the interpreter's common constants, which are only set up after the builtins module is created.
5a5f663 to
52befa6
Compare
|
🤖 New build scheduled with the buildbot fleet by @kumaraditya303 for commit 9db7837 🤖 Results will be shown at: https://buildbot.python.org/all/#/grid?branch=refs%2Fpull%2F157362%2Fmerge If you want to schedule another build, you need to add the 🔨 test-with-buildbots label again. |
| try: | ||
| # Looked up on the type, like the C slot am_anext. | ||
| anext_method = cls.__anext__ | ||
| except AttributeError: |
There was a problem hiding this comment.
Strictly speaking, there is now a slight divergence where accessing __anext__ could raise something other than an AttributeError and this would leak. Should we worry about those cases? (previoulsy we directly accessed the structs, so we were bypassing getattr).
There was a problem hiding this comment.
am_next is the underlying slot for __anext__ and the method is being looked up on the type so there isn't much divergence (the instance getattr cannot be triggered) so apart from contrived hand-crafted cases this is safe.
| anext_method = cls.__anext__ | ||
| except AttributeError: | ||
| raise TypeError( | ||
| f"'{cls.__name__}' object is not an async iterator" |
There was a problem hiding this comment.
| f"'{cls.__name__}' object is not an async iterator" | |
| f"{cls.__name__!r} object is not an async iterator" |
| @@ -0,0 +1,4 @@ | |||
| Implement :func:`anext` in Python instead of C, in a frozen ``_pybuiltins`` | |||
There was a problem hiding this comment.
Since it's a built-in change I think you should also mention it in What's New 3.16 because it's kind of a breaking change for anyone having a _pybuiltins momdule in their project.
There was a problem hiding this comment.
I'll do that after I do the other ones as well like aiter.
| p = ait_class() | ||
| obj = anext(p, "completed") | ||
| self.assertRaises(SyntaxError, obj.throw, SyntaxError) | ||
| with warnings.catch_warnings(): |
There was a problem hiding this comment.
Isn't this a change of behavior then? maybe document it as well?
There was a problem hiding this comment.
It is but not important, throwing or sending something to just created generator always errors so in practice no one does it. The important part is that it raises exception for that and it does.
Remove the C implementation of the
anext()builtin and theanext_awaitablehelper type. A_pybuiltinsmodule is created with the implementation and that is frozen into the interpreter using the existing freeze infrastructure.The Python version keeps the C semantics:
__anext__is looked up on the type and called eagerly, the one-argument form returns the awaitable unchanged, and the two-argument form wraps it in a coroutine that returns the default onStopAsyncIteration.I'll implement
aitersimilarly in a followup.anextandaiterin pure Python #157361