Skip to content

gh-112182: Replace StopIteration with RuntimeError for future#113220

Merged
gvanrossum merged 10 commits into
python:mainfrom
ordinary-jamie:asyncio-future-stopiteration
Jan 10, 2024
Merged

gh-112182: Replace StopIteration with RuntimeError for future#113220
gvanrossum merged 10 commits into
python:mainfrom
ordinary-jamie:asyncio-future-stopiteration

Conversation

@ordinary-jamie

@ordinary-jamie ordinary-jamie commented Dec 16, 2023

Copy link
Copy Markdown
Contributor

Issue: #112182

When an StopIteration raises into asyncio.Future, this will cause a thread to hang. This commit address this by not raising an exception and silently transforming the StopIteration with a RuntimeError, which the caller can reconstruct from fut.exception().__cause__

When an `StopIteration` raises into `asyncio.Future`, this will cause
a thread to hang. This commit address this by not raising an exception
and silently transforming the `StopIteration` with a `RuntimeError`,
which the caller can reconstruct from `fut.exception().__cause__`

@gvanrossum gvanrossum left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @ordinary-jamie, your Python's pretty good, your C could use a bit more care with reference counts and such. I think I caught everything. (BTW did you see the similar code in intrinsics.c in stopiteration_error()? It could serve as a useful comparison.)

@NewUserHa -- do you have any feedback on this PR? Do you have a version of your own that's further developed?

Comment thread Lib/asyncio/futures.py Outdated
Comment thread Modules/_asynciomodule.c Outdated
Comment thread Misc/NEWS.d/next/Library/2023-12-17-10-22-55.gh-issue-112182.jLWGlr.rst Outdated
Comment thread Modules/_asynciomodule.c
Comment thread Modules/_asynciomodule.c Outdated
Comment thread Modules/_asynciomodule.c
Comment thread Modules/_asynciomodule.c Outdated
@ordinary-jamie

Copy link
Copy Markdown
Contributor Author

Hey @ordinary-jamie, your Python's pretty good, your C could use a bit more care with reference counts and such. I think I caught everything.

Thanks for the detailed review @gvanrossum! Yes, sorry about my C, got a bit too eager to try and contribute before finishing my studies with CPython/C. I'll address your comments asap and let you know :)

(BTW did you see the similar code in intrinsics.c in stopiteration_error()? It could serve as a useful comparison.)

👀 thanks!

@serhiy-storchaka serhiy-storchaka left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with all of Guido's comments.

Comment thread Modules/_asynciomodule.c

@gvanrossum gvanrossum left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a nit for the blurb, otherwise LGTM. But let's make sure @serhiy-storchaka also agrees (I might have missed something).

Comment thread Misc/NEWS.d/next/Library/2023-12-17-10-22-55.gh-issue-112182.jLWGlr.rst Outdated
@ordinary-jamie

Copy link
Copy Markdown
Contributor Author

Happy holidays @gvanrossum @serhiy-storchaka -- sorry for the slow response on this, just came back from leave.

Side question: should PyObject_CallOneArg be updated in the docs with the reference count annotation "Return value: New reference." (as is the case with PyObject_CallFunction et al.)

@gvanrossum

Copy link
Copy Markdown
Member

Side question: should PyObject_CallOneArg be updated in the docs with the reference count annotation "Return value: New reference." (as is the case with PyObject_CallFunction et al.)

I have no idea. I don't even know where that is generated -- I don't see it in the .rst file.

@ordinary-jamie

ordinary-jamie commented Jan 4, 2024

Copy link
Copy Markdown
Contributor Author

Side question: should PyObject_CallOneArg be updated in the docs with the reference count annotation "Return value: New reference." (as is the case with PyObject_CallFunction et al.)

I have no idea. I don't even know where that is generated -- I don't see it in the .rst file.

I believe its set here: Doc/data/refcounts.dat

edit: I can look into it and raise a separate issue ticket

@ordinary-jamie

Copy link
Copy Markdown
Contributor Author

Sorry @gvanrossum -- missed out a fix in the Python stub

@gvanrossum gvanrossum left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LG -- waiting for @serhiy-storchaka

Comment thread Lib/asyncio/futures.py Outdated
@bedevere-app

bedevere-app Bot commented Jan 4, 2024

Copy link
Copy Markdown

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 I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

Comment thread Modules/_asynciomodule.c
assert(PyExceptionInstance_Check(err));

PyException_SetCause(err, Py_NewRef(exc_val));
PyException_SetContext(err, Py_NewRef(exc_val));

@kumaraditya303 kumaraditya303 Jan 4, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need set this to exc_val.__context__ not exc_val itself.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was taken from the similar, existing code in intrinsics.c that also handles StopIteration for asyncio:

PyException_SetContext(error, Py_NewRef(exc));

Would this need updating as well?

Comment thread Lib/test/test_asyncio/test_futures.py Outdated
Comment thread Lib/test/test_asyncio/test_futures.py Outdated
Comment thread Modules/_asynciomodule.c Outdated
Comment thread Lib/asyncio/futures.py Outdated
@ordinary-jamie

Copy link
Copy Markdown
Contributor Author

Sorry about the mistakes @serhiy-storchaka and @kumaraditya303

I've addressed the comments, except for one RE: setting the context. The current code copies over the logic from PyObject *stopiteration_error in intrinsics.c so am unsure which way to go forward.

@serhiy-storchaka serhiy-storchaka left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was surprised that the Python code set exception.__context__. Was there any reason for this or it was a typo? There are no tests for this.

Besides this minor question, LGTM.

@ordinary-jamie

Copy link
Copy Markdown
Contributor Author

I was surprised that the Python code set exception.__context__. Was there any reason for this or it was a typo? There are no tests for this.

typo 😳 sorry about that!

@gvanrossum

Copy link
Copy Markdown
Member

I was surprised that the Python code set exception.__context__. Was there any reason for this or it was a typo? There are no tests for this.

typo 😳 sorry about that!

@ordinary-jamie I lost track of the state of this PR. Did you fix that typo yet?

@ordinary-jamie

ordinary-jamie commented Jan 10, 2024

Copy link
Copy Markdown
Contributor Author

I was surprised that the Python code set exception.__context__. Was there any reason for this or it was a typo? There are no tests for this.

typo 😳 sorry about that!

@ordinary-jamie I lost track of the state of this PR. Did you fix that typo yet?

Yes! The typo is already fixed (sorry for the comment spam)

@gvanrossum
gvanrossum merged commit 4826d52 into python:main Jan 10, 2024
@gvanrossum

Copy link
Copy Markdown
Member

Thanks @ordinary-jamie ! We'll get the other thing sorted too. Happy to work with you more.

kulikjak pushed a commit to kulikjak/cpython that referenced this pull request Jan 22, 2024
…ython#113220)

When an `StopIteration` raises into `asyncio.Future`, this will cause
a thread to hang. This commit address this by not raising an exception
and silently transforming the `StopIteration` with a `RuntimeError`,
which the caller can reconstruct from `fut.exception().__cause__`
aisk pushed a commit to aisk/cpython that referenced this pull request Feb 11, 2024
…ython#113220)

When an `StopIteration` raises into `asyncio.Future`, this will cause
a thread to hang. This commit address this by not raising an exception
and silently transforming the `StopIteration` with a `RuntimeError`,
which the caller can reconstruct from `fut.exception().__cause__`
@bharel

bharel commented Aug 15, 2024

Copy link
Copy Markdown
Contributor

What version was this fixed in?
For some reason I still get it on 3.12.5 but not on 13rc1.
Did we forget backporting?

@serhiy-storchaka

Copy link
Copy Markdown
Member

It was not backported to 3.12.

Taking into account that the current behavior is wrong, and it is very unlikely that any code depends on it (how can you depend on hanging code?), I think that it is reasonable to backport this change (if there was no other changes that can prevent this).

@serhiy-storchaka serhiy-storchaka added the needs backport to 3.12 only security fixes label Aug 15, 2024
@miss-islington-app

Copy link
Copy Markdown

Thanks @ordinary-jamie for the PR, and @gvanrossum for merging it 🌮🎉.. I'm working now to backport this PR to: 3.12.
🐍🍒⛏🤖

miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Aug 15, 2024
…ythonGH-113220)

When an `StopIteration` raises into `asyncio.Future`, this will cause
a thread to hang. This commit address this by not raising an exception
and silently transforming the `StopIteration` with a `RuntimeError`,
which the caller can reconstruct from `fut.exception().__cause__`
(cherry picked from commit 4826d52)

Co-authored-by: Jamie Phan <jamie@ordinarylab.dev>
@bedevere-app

bedevere-app Bot commented Aug 15, 2024

Copy link
Copy Markdown

GH-123033 is a backport of this pull request to the 3.12 branch.

@bedevere-app bedevere-app Bot removed the needs backport to 3.12 only security fixes label Aug 15, 2024
serhiy-storchaka pushed a commit that referenced this pull request Aug 15, 2024
…H-113220) (GH-123033)

When an `StopIteration` raises into `asyncio.Future`, this will cause
a thread to hang. This commit address this by not raising an exception
and silently transforming the `StopIteration` with a `RuntimeError`,
which the caller can reconstruct from `fut.exception().__cause__`
(cherry picked from commit 4826d52)

Co-authored-by: Jamie Phan <jamie@ordinarylab.dev>
Glyphack pushed a commit to Glyphack/cpython that referenced this pull request Sep 2, 2024
…ython#113220)

When an `StopIteration` raises into `asyncio.Future`, this will cause
a thread to hang. This commit address this by not raising an exception
and silently transforming the `StopIteration` with a `RuntimeError`,
which the caller can reconstruct from `fut.exception().__cause__`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants