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..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) { @@ -1031,6 +1032,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;