-
-
Notifications
You must be signed in to change notification settings - Fork 30.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bpo-31861: Add operator.aiter and operator.anext #8895
Conversation
b467ec3
to
6aa0fa5
Compare
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
@asvetlov Thank you for the helpful review. I have addressed all your comments in 908227b. GitHub reports that all CI checks are passing. In particular, I see " Locally I get:
I'm not sure the destroyed pending task there is my fault or whether this is even a problem. Any further reworking needed before this can be merged? |
I have made the requested changes; please review again. |
Thanks for making the requested changes! @asvetlov: please review the changes made to this pull request. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't merge this yet. I'm not convinced that aiter and anext shouldn't be builtins.
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
@1st1 Would it be useful if I submitted another change here that moved these two Python functions from |
Regardless, I'd be curious if you can spot anything in the tests I added that could be responsible for the lingering pending task and if there's anything I should do about that. The question about whether the |
@jab I know that @wolkodav was (is?) working on implementing builtin versions of these functions (in C), but I'm not sure what's his latest progress. Perhaps you guys can collaborate and work together on this. In my opinion it would be great to have |
@1st1 Thanks for the additional info!
(I'm more comfortable with Python than C but) would be happy to try to help @wolkodav in any way I can.
So even if there were a PR adding this to builtins that was ready to merge now, we would still have to wait for a new governance model before it could be merged. Rather than blocking all progress on this, would it make sense to merge this PR so we can make incremental progress in the meantime, and then once the governance question has been settled, the decision to move these into builtins could be made independently? Then if at that point it's decided to keep these in |
I don't see how merging either PR right now (with a non-zero chance of it being reverted later) can be beneficial. I don't think this feature would see a lot of work and refinement after we merge it. I would also like to avoid any confusing churn in APIs/docs if possible.
I think that we'll simply email python-dev and ask when the time is right. Please be patient! If you want to work on something else meanwhile I'm sure that there are some open issues in asyncio that could be easier to merge/fix. |
Ok, just trying to maximize results while I had the bandwidth now. I don't subscribe to python-dev so please link to the thread here once it's started if possible. I actually already have another PR outstanding that's been awaiting review for a few weeks, in case it's one you feel comfortable reviewing: #8792 |
Yes, I work on C implementation in builtins for |
Hey @wolkodav, sorry to hear you had laptop trouble and great to hear you're working on this! If/when you're ready to share your work, please link to it from here. |
@jab, i have some problem at the moment with default parameter. I need some time to understand how work coroutine at C level... At the moment you can view work in my fork: https://github.com/WolkoDav/cpython |
@jab, Yuri has already watched my code and left comments there. I think that in a week I will be able to add the parameter "default". |
@ikrivosheev are you still working on this? I want to work on another PR for a C implementation for this. Can i pick up. Am fine if you still want to work on this. |
@1st1, would now be an ok time to ask about this? |
Thanks for reviewing and approving this, @eric-wieser, great to see some activity here again! Is the question of whether these should be in operator vs. builtins is still unresolved, though? If so, @1st1, do you still want (me?) to start a thread on python-dev about this when the time is right? Happy to do that now if that'd be helpful. It'd be great for Would be sweet to get a fix for BPO-31861 landed by the time this PR turns 2 years old at end of August, and just want to help in any way I can :) |
A C implementation might make more sense, especially if it could live next to the existing Lines 174 to 288 in c3dd7e4
Lines 1509 to 1535 in c3dd7e4
From what I can tell, that style of implementation of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I agree, this is good feedback for @ikrivosheev but anyone can pick up these suggestions in a different PR unless @ikrivosheev commits again.
Thanks for looking at this, @eric-wieser and @nanjekyejoannah, good to cross paths with you again here and hope you’ve been well! I’d love to work on a C implementation in another PR (which could maybe even reuse the tests I wrote in this PR), but would need a little help getting started on the C side (I know C pretty well from a past life, but have only written 100 lines in the last 15 years) and don’t know the CPython code well yet. Would anyone with more experience be willing to mentor me for this? |
Lib/operator.py
Outdated
if isinstance(obj, AsyncIterator): | ||
return obj | ||
return (i async for i in obj) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if isinstance(obj, AsyncIterator): | |
return obj | |
return (i async for i in obj) | |
ait = obj.__aiter__() | |
if not hasattr(ait, '__anext__'): | |
raise TypeError(f"aiter() returned non-AsyncIterator of type {type(ait)!r}") | |
return ait |
I think it should be this way for a few reasons:
- It eliminates the two separate non-raising cases and return statements/types
- It eliminates the overhead of the extra async generator expression and is more easily implemented in C.
- For any AsyncIterator
a
, we "should" havea.__aiter__() is a
, so the behavior shouldn't change much. - For the cases where that isn't true, in analogy with the builtin
iter()
, one might expectaiter(x)
to always callx.__aiter__()
:
from collections.abc import Iterator, AsyncIterator
class A:
def __next__(self):
return 1
def __iter__(self):
return iter([])
# "a" is already an iterator, but a.__iter__ is called anyway.
a = A()
assert isinstance(a, Iterator)
assert iter(a) is not a
assert type(iter(a)) is not type(a)
assert type(iter(a)) is type(iter([]))
############################
async def another_aiter():
yield 1
class B:
def __anext__(self):
return 1
def __aiter__(self):
return another_aiter()
b = B()
assert isinstance(b, AsyncIterator)
# These three assertions fail, but pass with the change.
assert aiter(b) is not b
assert type(aiter(b)) is not type(b)
assert type(aiter(b)) is type(aiter(another_aiter()))
See the implementation of iter()
here, which uses PyObject_GetIter()
from here.
I wonder if a PyObject_GetAsyncIter
needs to be added to the C-API so that aiter()
and the GET_AITER opcode can use the same code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we call type(obj).__aiter__(obj)
(and the analogue for __anext__
)? That's how dunder methods are generally called by the interpreter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for reviewing! Updated this patch based on the good suggestions.
(Note, I used isinstance(ait, AsyncIterator)
rather than the hasattr(ait, '__anext__')
that was suggested, figuring that's the preferred spelling. Also, after rebasing on latest master, I had to move the from collections.abc ...
imports from module scope to function scope as a workaround to avoid a circular dependency between operator
and collections
, which wasn't an issue when I first submitted this PR. Sounds like this PR will now serve as a reference implementation for a reimplementation in C (submitted in a separate PR) anyway, where I guess such a workaround won't be necessary?)
69b302e
to
8b2b120
Compare
...on top of latest master. Also drop now-removed `loop` kwarg from asyncio.sleep call. Ref: https://bugs.python.org/issue42392
Please see #23847 for a C implementation of aiter and anext added to builtins. |
Closing in favor of #23847 (adding them to builtins). |
...along with passing tests. (I added the tests to
test_asyncgen.py
rather than totest_operator.py
because they fit much better there.)/cc @1st1 @njsmith @JelleZijlstra et al.
https://bugs.python.org/issue31861