diff --git a/Lib/test/test_sys_setprofile.py b/Lib/test/test_sys_setprofile.py index 34c70d6c8de0c4..9e8936630de920 100644 --- a/Lib/test/test_sys_setprofile.py +++ b/Lib/test/test_sys_setprofile.py @@ -255,6 +255,25 @@ def g(p): (1, 'return', g_ident), ]) + def test_unfinished_generator(self): + def f(): + for i in range(2): + yield i + def g(p): + next(f()) + + f_ident = ident(f) + g_ident = ident(g) + self.check_events(g, [(1, 'call', g_ident), + (2, 'call', f_ident), + (2, 'return', f_ident), + # once more; the generator is being garbage collected + # and it will do a PY_THROW + (2, 'call', f_ident), + (2, 'return', f_ident), + (1, 'return', g_ident), + ]) + def test_stop_iteration(self): def f(): for i in range(2): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-10-08-20-08-54.gh-issue-110514.Q9bdRU.rst b/Misc/NEWS.d/next/Core and Builtins/2023-10-08-20-08-54.gh-issue-110514.Q9bdRU.rst new file mode 100644 index 00000000000000..96363c2b9d88be --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-10-08-20-08-54.gh-issue-110514.Q9bdRU.rst @@ -0,0 +1 @@ +Add ``PY_THROW`` to :func:`sys.setprofile` events diff --git a/Python/legacy_tracing.c b/Python/legacy_tracing.c index b0136d2ebc7554..43fa5910ef6dd1 100644 --- a/Python/legacy_tracing.c +++ b/Python/legacy_tracing.c @@ -377,6 +377,11 @@ _PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) PY_MONITORING_EVENT_PY_START, PY_MONITORING_EVENT_PY_RESUME)) { return -1; } + if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID, + (vectorcallfunc)sys_profile_func3, PyTrace_CALL, + PY_MONITORING_EVENT_PY_THROW, -1)) { + return -1; + } if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID, (vectorcallfunc)sys_profile_func3, PyTrace_RETURN, PY_MONITORING_EVENT_PY_RETURN, PY_MONITORING_EVENT_PY_YIELD)) { @@ -417,7 +422,8 @@ _PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) events = (1 << PY_MONITORING_EVENT_PY_START) | (1 << PY_MONITORING_EVENT_PY_RESUME) | (1 << PY_MONITORING_EVENT_PY_RETURN) | (1 << PY_MONITORING_EVENT_PY_YIELD) | - (1 << PY_MONITORING_EVENT_CALL) | (1 << PY_MONITORING_EVENT_PY_UNWIND); + (1 << PY_MONITORING_EVENT_CALL) | (1 << PY_MONITORING_EVENT_PY_UNWIND) | + (1 << PY_MONITORING_EVENT_PY_THROW); } return _PyMonitoring_SetEvents(PY_MONITORING_SYS_PROFILE_ID, events); }