]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-140729: Fix the cProfile module when the executed script contains calls to multipr...
authorDuprat <yduprat@gmail.com>
Mon, 6 Jul 2026 23:39:06 +0000 (01:39 +0200)
committerGitHub <noreply@github.com>
Mon, 6 Jul 2026 23:39:06 +0000 (00:39 +0100)
Co-authored-by: Pablo Galindo Salgado <pablogsal@gmail.com>
Lib/profiling/tracing/__init__.py
Lib/test/test_profiling/test_tracing_profiler.py
Misc/NEWS.d/next/Library/2026-02-11-16-47-27.gh-issue-140729.2uTPQp.rst [new file with mode: 0644]

index bd3cbf299aab3b9c59b651353101a9fde10376ab..165665304e05a4019a96c918ab706fc6d4a07772 100644 (file)
@@ -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,
index e9f55613b6cfbb8c92cb6a3f6b7e7db3d3164508..8a7070142b60eec5dd04d0106bb72377f07a40a6 100644 (file)
@@ -1,5 +1,4 @@
 """Test suite for the cProfile module."""
-
 import sys
 import unittest
 
@@ -193,6 +192,40 @@ class TestCommandLine(unittest.TestCase):
             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 (file)
index 0000000..49c9adc
--- /dev/null
@@ -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.