diff --git a/Lib/profiling/tracing/__init__.py b/Lib/profiling/tracing/__init__.py index bd3cbf299aab3b..6423e8c9f4e93d 100644 --- a/Lib/profiling/tracing/__init__.py +++ b/Lib/profiling/tracing/__init__.py @@ -197,7 +197,10 @@ def main(): # in the module's namespace. globs = module.__dict__ globs.update({ - '__spec__': spec, + # See gh-140729, set None to __spec__ according + # to the documentation, + # https://docs.python.org/3/reference/import.html#module-specs + '__spec__': None, '__file__': spec.origin, '__name__': spec.name, '__package__': None, diff --git a/Lib/test/test_profiling/test_sampling_profiler/test_advanced.py b/Lib/test/test_profiling/test_sampling_profiler/test_advanced.py index 11b1ad84242fd4..67fb3f281e5a97 100644 --- a/Lib/test/test_profiling/test_sampling_profiler/test_advanced.py +++ b/Lib/test/test_profiling/test_sampling_profiler/test_advanced.py @@ -234,3 +234,50 @@ def worker(x): self.assertIn("Results: [2, 4, 6]", stdout) self.assertNotIn("Can't pickle", stderr) + + +@requires_remote_subprocess_debugging() +class TestProcessRunSupport(unittest.TestCase): + """ + Test that Process works correctly with cProfile. + """ + + def test_process_run_pickle(self): + # gh-140729: test use Process in cProfile. + val = 10 + test_script = f''' +import multiprocessing + +def worker(x): + print(__name__) + exit(x ** 2) + +if __name__ == "__main__": + multiprocessing.set_start_method("spawn") + p = multiprocessing.Process(target=worker, args=({val},)) + p.start() + p.join() + print("p.exitcode =", p.exitcode) +''' + + with os_helper.temp_dir() as temp_dir: + script = script_helper.make_script( + temp_dir, 'test_process_run_pickle', test_script + ) + with SuppressCrashReport(): + with script_helper.spawn_python( + "-m", "cProfile", + script, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True + ) as proc: + try: + stdout, stderr = proc.communicate(timeout=SHORT_TIMEOUT) + except subprocess.TimeoutExpired: + proc.kill() + stdout, stderr = proc.communicate() + + self.assertIn("__mp_main__", stdout) + self.assertIn(f"exitcode = {val**2}", stdout) + self.assertNotIn("Can't pickle", stderr) 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 00000000000000..ce099debc7e67a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-02-11-16-47-27.gh-issue-140729.2uTPQp.rst @@ -0,0 +1,2 @@ +Fix pickling error in the cProfile module when using ``multiprocessing.Process`` +script, which can not be properly pickled and executed.