From 6b4de53b974d21b321507113511e385012eb90ee Mon Sep 17 00:00:00 2001 From: sobolevn Date: Tue, 3 Nov 2026 10:34:36 +0300 Subject: [PATCH 1/2] gh-161233: Fix `TypeError` when `timer=None` was passed to `cProfile.Profile` --- Lib/test/test_profiling/test_tracing_profiler.py | 14 ++++++++++++++ .../2026-11-03-10-33-33.gh-issue-161233._9VrfL.rst | 2 ++ Modules/_lsprof.c | 3 +++ 3 files changed, 19 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-11-03-10-33-33.gh-issue-161233._9VrfL.rst diff --git a/Lib/test/test_profiling/test_tracing_profiler.py b/Lib/test/test_profiling/test_tracing_profiler.py index 7e2ed24f4918e82..ac8fdf343b4fd16 100644 --- a/Lib/test/test_profiling/test_tracing_profiler.py +++ b/Lib/test/test_profiling/test_tracing_profiler.py @@ -139,6 +139,20 @@ def timer(): profiler.disable() profiler.clear() + def test_external_timer_is_none(self): + # gh-161233 + def work(): + pass + + for kwargs in ({}, {'timer': None}): + with self.subTest(kwargs=kwargs): + profiler = cProfile.Profile(**kwargs) + profiler.enable() + with support.catch_unraisable_exception() as cm: + work() + self.assertIsNone(cm.unraisable) + profiler.disable() + def test_profile_enable_disable(self): prof = self.profilerclass() # Make sure we clean ourselves up if the test fails for some reason. diff --git a/Misc/NEWS.d/next/Library/2026-11-03-10-33-33.gh-issue-161233._9VrfL.rst b/Misc/NEWS.d/next/Library/2026-11-03-10-33-33.gh-issue-161233._9VrfL.rst new file mode 100644 index 000000000000000..96e9f5e39df3ec1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-11-03-10-33-33.gh-issue-161233._9VrfL.rst @@ -0,0 +1,2 @@ +Fix unraisable :exc:`TypeError` when ``None`` was passed as a *timer* to +:class:`cProfile.Profile `. diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index 42fd1eaa0f088a5..0457f06342bb434 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -1031,6 +1031,9 @@ profiler_init_impl(ProfilerObject *self, PyObject *timer, double timeunit, if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0) { return -1; } + if (timer == Py_None) { + timer = NULL; + } self->externalTimerUnit = timeunit; Py_XSETREF(self->externalTimer, Py_XNewRef(timer)); self->tool_id = PY_MONITORING_PROFILER_ID; From 58db649dd3c22719ae9f89465c10ac9bc27c15c6 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Tue, 3 Nov 2026 10:47:03 +0300 Subject: [PATCH 2/2] Address review --- Modules/_lsprof.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index 0457f06342bb434..c11973d3ed1ff0f 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -92,6 +92,7 @@ _lsprof_get_state(PyObject *module) static PyTime_t CallExternalTimer(ProfilerObject *pObj) { + assert(pObj->externalTimer != NULL && pObj->externalTimer != Py_None); PyObject *o = _PyObject_CallNoArgs(pObj->externalTimer); if (o == NULL) {