From cea9d4ea82abcb2c6f1d83a2fe819859da4bbda4 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Thu, 29 Jun 2023 16:14:09 -0700 Subject: [PATCH] GH-106152: Add PY_THROW event to cProfile (GH-106161) --- Lib/test/test_cprofile.py | 20 +++++++++++++++++++ ...-06-27-23-22-37.gh-issue-106152.ya5jBT.rst | 1 + Modules/_lsprof.c | 1 + 3 files changed, 22 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-06-27-23-22-37.gh-issue-106152.ya5jBT.rst diff --git a/Lib/test/test_cprofile.py b/Lib/test/test_cprofile.py index 484b8f8e3a365c..3056fe84dac5dd 100644 --- a/Lib/test/test_cprofile.py +++ b/Lib/test/test_cprofile.py @@ -66,6 +66,26 @@ def test_second_profiler(self): self.assertRaises(ValueError, pr2.enable) pr.disable() + def test_throw(self): + """ + gh-106152 + generator.throw() should trigger a call in cProfile + In the any() call below, there should be two entries for the generator: + * one for the call to __next__ which gets a True and terminates any + * one when the generator is garbage collected which will effectively + do a throw. + """ + pr = self.profilerclass() + pr.enable() + any(a == 1 for a in (1, 2)) + pr.disable() + pr.create_stats() + + for func, (cc, nc, _, _, _) in pr.stats.items(): + if func[2] == "": + self.assertEqual(cc, 2) + self.assertEqual(nc, 2) + class TestCommandLine(unittest.TestCase): def test_sort(self): diff --git a/Misc/NEWS.d/next/Library/2023-06-27-23-22-37.gh-issue-106152.ya5jBT.rst b/Misc/NEWS.d/next/Library/2023-06-27-23-22-37.gh-issue-106152.ya5jBT.rst new file mode 100644 index 00000000000000..da9d2605f46294 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-06-27-23-22-37.gh-issue-106152.ya5jBT.rst @@ -0,0 +1 @@ +Added PY_THROW event hook for :mod:`cProfile` for generators diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index 1c84f66ee6f579..257de4387c0ab9 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -678,6 +678,7 @@ static const struct { } callback_table[] = { {PY_MONITORING_EVENT_PY_START, "_pystart_callback"}, {PY_MONITORING_EVENT_PY_RESUME, "_pystart_callback"}, + {PY_MONITORING_EVENT_PY_THROW, "_pystart_callback"}, {PY_MONITORING_EVENT_PY_RETURN, "_pyreturn_callback"}, {PY_MONITORING_EVENT_PY_YIELD, "_pyreturn_callback"}, {PY_MONITORING_EVENT_PY_UNWIND, "_pyreturn_callback"},