Skip to content

gh-124872: Back up exception before calling PyContext_WatchCallback #124741

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

rhansen
Copy link
Contributor

@rhansen rhansen commented Sep 29, 2024

I believe that the value of a simpler API (and defense against poorly written callbacks) outweighs the cost of backing up and restoring the thread's exception state.

Also change the return type from int to void. The callback cannot prevent the event from occurring by raising an exception. Nor should it be able to; any failure to switch contexts would be difficult if not impossible to handle correctly. The API should reflect that the callback is purely informational, and that the context switch will happen even if the callback doesn't want it to.

I don't think a NEWS blurb is needed because this amends a feature that is new to v3.14; the existing blurb should suffice.

cc @fried


📚 Documentation preview 📚: https://cpython-previews--124741.org.readthedocs.build/

@bedevere-app
Copy link

bedevere-app bot commented Sep 29, 2024

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@rruuaanng
Copy link
Contributor

rruuaanng commented Sep 29, 2024

I think it still needs to be added because this behavior is new.

@rhansen
Copy link
Contributor Author

rhansen commented Sep 29, 2024

I don't understand. What should be added beyond what is already in Misc/NEWS.d/next/C API/2024-05-21-18-28-44.gh-issue-119333.OTsYVX.rst?

@rhansen rhansen force-pushed the gh-119333-exception branch from 1636f10 to 9e4ea98 Compare September 29, 2024 23:20
@bedevere-app
Copy link

bedevere-app bot commented Sep 29, 2024

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@bedevere-app
Copy link

bedevere-app bot commented Sep 30, 2024

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

2 similar comments
@bedevere-app
Copy link

bedevere-app bot commented Sep 30, 2024

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@bedevere-app
Copy link

bedevere-app bot commented Sep 30, 2024

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@rhansen rhansen force-pushed the gh-119333-exception branch from 212948c to 5f8590c Compare October 1, 2024 23:23
@bedevere-app
Copy link

bedevere-app bot commented Oct 1, 2024

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@rhansen rhansen changed the title gh-119333: Back up exception before calling PyContext_WatchCallback gh-124872: Back up exception before calling PyContext_WatchCallback Oct 1, 2024
@rhansen
Copy link
Contributor Author

rhansen commented Oct 1, 2024

Apologies for the force-push; I wanted to update the commit message to reference the new issue I just opened (gh-124872).

@1st1
Copy link
Member

1st1 commented Oct 9, 2024

I'm +0 for this change. Curious what @fried would say.

@fried
Copy link
Contributor

fried commented Oct 10, 2024

I'm +0 for this change. Curious what @fried would say.

The existing behavior mirrors the other object event "watchers"

@1st1
Copy link
Member

1st1 commented Oct 12, 2024

Ah, I see, e.g. https://docs.python.org/3/c-api/code.html#c.PyCode_WatchCallback is similarly designed. Not going to lie, I like what @rhansen proposes more, so I'm +1 for this PR.

Maybe I can hear from @pablogsal or @vstinner what they think of this?

In the meantime, @rhansen please rebase the PR to the latest main.

…back

I believe that the value of a simpler API (and defense against poorly
written callbacks) outweighs the cost of backing up and restoring the
thread's exception state.
@rhansen rhansen force-pushed the gh-119333-exception branch from 5f8590c to ca49b94 Compare October 12, 2024 21:34
@pablogsal
Copy link
Member

I'm with @1st1 on this one (+1 to this design).

Maybe the C-API working group has some input? @iritkatriel

if (cb(event, ctx) < 0) {
PyObject *exc = _PyErr_GetRaisedException(ts);
cb(event, ctx);
if (_PyErr_Occurred(ts) != NULL) {
Copy link
Member

Choose a reason for hiding this comment

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

Can this use cb's return value as before, rather than checking _PyErr_Occurred?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This PR changes the callback's return type to void to discourage the use of exceptions (since they get ignored anyway), so there is no return value to check.

Copy link
Member

Choose a reason for hiding this comment

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

I noticed, but I'm suggesting to not do that.

Also, the documentation is incorrect: "If the callback raises an exception it will be ignored."
it's not completely ignored.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, I see. I think that discarding this PR's second commit would address both of your concerns, though I would still like to tweak the documentation's wording a bit to be more precise.

Part of the reason I want to change the return value to void is to cement a future where context switches cannot fail. For gh-99633, context switches can happen when generators or coroutines resume or suspend, where a failure to switch would be particularly difficult to handle correctly. I want the event notification API to make it clear to developers that the callback is informational only; the context switch will happen even if they don't want it to.

(I should express this rationale in the commit message and PR description.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tweaked the wording of the documentation and the commit message. I still believe that it is better to return void so I kept that, but I can easily undo it by discarding the final commit if you disagree. Please let me know what you think.

Copy link
Member

@1st1 1st1 Oct 14, 2024

Choose a reason for hiding this comment

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

But in this case we know where the exception is coming from, _PyErr_GetRaisedException resets the current exception to NULL. So if _PyErr_Occurred returns anything it must be coming from the callback.

Copy link
Member

Choose a reason for hiding this comment

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

(FWIW I don't feel strong about this, but I do like the idea somewhat)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@iritkatriel Does the thumbs-up reaction on @1st1's comment mean you're OK with this PR?

Copy link
Member

Choose a reason for hiding this comment

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

It related to the comment it's on.

I would prefer avoiding _PyErr_Occurred as a matter of style but I agree that in this case it's harmless.

Copy link
Member

Choose a reason for hiding this comment

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

@ambv @pablogsal can one of you weigh in here and give a third opinion? I basically like the PR as is as I think it makes a better API this way, but I also understand the point Irit is making. Also this might be the first CPython API designed this way.

The callback cannot prevent the event from occurring by raising an
exception.  Nor should it be able to; any failure to switch contexts
would be difficult if not impossible to handle correctly.  The API
should reflect that the callback is purely informational, and that the
context switch will happen even if the callback doesn't want it to.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants