diff --git a/Lib/profiling/tracing/__init__.py b/Lib/profiling/tracing/__init__.py index bd3cbf299aab3b9..165665304e05a40 100644 --- a/Lib/profiling/tracing/__init__.py +++ b/Lib/profiling/tracing/__init__.py @@ -197,7 +197,9 @@ def main(): # in the module's namespace. globs = module.__dict__ globs.update({ - '__spec__': spec, + # Set __spec__ to None so the profiled program behaves like a + # script run directly (gh-140729). + '__spec__': None, '__file__': spec.origin, '__name__': spec.name, '__package__': None, diff --git a/Lib/test/test_profiling/test_tracing_profiler.py b/Lib/test/test_profiling/test_tracing_profiler.py index 3668e24e073ce4d..a4fabe9d3cc75bf 100644 --- a/Lib/test/test_profiling/test_tracing_profiler.py +++ b/Lib/test/test_profiling/test_tracing_profiler.py @@ -1,5 +1,4 @@ """Test suite for the cProfile module.""" - import sys import unittest @@ -192,6 +191,40 @@ class Foo: f.close() assert_python_ok('-m', "cProfile", f.name) + def _test_process_run_pickle(self, start_method): + val = 10 + with tempfile.NamedTemporaryFile("w+", delete_on_close=False) as f: + f.write(textwrap.dedent( + f'''\ + import multiprocessing + + def worker(x): + print(__name__) + exit(x ** 2) + + if __name__ == "__main__": + multiprocessing.set_start_method('{start_method}') + p = multiprocessing.Process(target=worker, args=({val},)) + p.start() + p.join() + print("p.exitcode =", p.exitcode) + ''')) + f.close() + _, out, err = assert_python_ok('-m', "cProfile", f.name) + self.assertIn(b"__mp_main__", out) + self.assertIn(bytes(f"exitcode = {val**2}", encoding='utf8'), out) + self.assertNotIn(b"Can't pickle", err) + + def test_process_spawn_pickle(self): + # gh-140729: test use Process in cProfile. + self._test_process_run_pickle('spawn') + + @unittest.skipIf(sys.platform == 'win32', + "No 'forkserver' start method on Windows") + def test_process_forkserver_pickle(self): + # gh-140729: test use Process in cProfile. + self._test_process_run_pickle('forkserver') + def main(): if '-r' not in sys.argv: diff --git a/Misc/NEWS.d/next/Library/2026-02-11-16-47-27.gh-issue-140729.2uTPQp.rst b/Misc/NEWS.d/next/Library/2026-02-11-16-47-27.gh-issue-140729.2uTPQp.rst new file mode 100644 index 000000000000000..49c9adc4679abbf --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-02-11-16-47-27.gh-issue-140729.2uTPQp.rst @@ -0,0 +1,3 @@ +Fix a pickling error in the ``cProfile`` module when profiling a script that +uses :class:`multiprocessing.Process` with the ``spawn`` and ``forkserver`` +start methods.