From ea46babfb3e18d61c474fb7e4df398e9c9e05e40 Mon Sep 17 00:00:00 2001 From: sricursion Date: Thu, 8 Oct 2026 01:32:15 +0530 Subject: [PATCH] gh-158985: Make profile and cProfile -m run the module as __main__ Pass alter_sys=True to runpy.run_module() in the -m branch of profile and profiling.tracing, so that sys.modules['__main__'] and sys.argv[0] refer to the profiled module, as with python -m. --- Lib/profile.py | 2 +- Lib/profiling/tracing/__init__.py | 2 +- Lib/test/test_profile.py | 21 ++++++++++++++++++- ...-10-08-01-32-15.gh-issue-158985.tKnysx.rst | 5 +++++ 4 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-10-08-01-32-15.gh-issue-158985.tKnysx.rst diff --git a/Lib/profile.py b/Lib/profile.py index 304284da4211632..f554422e4552a95 100644 --- a/Lib/profile.py +++ b/Lib/profile.py @@ -590,7 +590,7 @@ def main(): if len(args) > 0: if options.module: import runpy - code = "run_module(modname, run_name='__main__')" + code = "run_module(modname, run_name='__main__', alter_sys=True)" globs = { 'run_module': runpy.run_module, 'modname': args[0] diff --git a/Lib/profiling/tracing/__init__.py b/Lib/profiling/tracing/__init__.py index 165665304e05a40..5a299d66a4dede6 100644 --- a/Lib/profiling/tracing/__init__.py +++ b/Lib/profiling/tracing/__init__.py @@ -176,7 +176,7 @@ def main(): if len(args) > 0: if options.module: - code = "run_module(modname, run_name='__main__')" + code = "run_module(modname, run_name='__main__', alter_sys=True)" globs = { 'run_module': runpy.run_module, 'modname': args[0] diff --git a/Lib/test/test_profile.py b/Lib/test/test_profile.py index c4b2d7ca05c0a6c..b55641a5a3d94f7 100644 --- a/Lib/test/test_profile.py +++ b/Lib/test/test_profile.py @@ -4,6 +4,7 @@ import pstats import unittest import os +import textwrap import warnings from difflib import unified_diff from io import StringIO @@ -15,7 +16,8 @@ warnings.simplefilter("ignore", DeprecationWarning) import profile from test.profilee import testfunc, timer -from test.support.script_helper import assert_python_failure, assert_python_ok +from test.support.script_helper import ( + assert_python_failure, assert_python_ok, make_script) class ProfileTest(unittest.TestCase): @@ -120,6 +122,23 @@ def test_run_profile_as_module(self): assert_python_ok('-m', self.profilermodule.__name__, '-m', 'timeit', '-n', '1') + def test_profile_module_as_main(self): + # The module must run as __main__, like with "python -m module". + with temp_dir() as tmpdir: + make_script(tmpdir, 'profiled_module', textwrap.dedent("""\ + import pickle + import sys + + class Foo: + pass + + assert sys.modules['__main__'].Foo is Foo + assert sys.argv[0].endswith('profiled_module.py') + pickle.dumps(Foo()) + """)) + assert_python_ok('-m', self.profilermodule.__name__, + '-m', 'profiled_module', PYTHONPATH=tmpdir) + def test_output_file_when_changing_directory(self): with temp_dir() as tmpdir, change_cwd(tmpdir): os.mkdir('dest') diff --git a/Misc/NEWS.d/next/Library/2026-10-08-01-32-15.gh-issue-158985.tKnysx.rst b/Misc/NEWS.d/next/Library/2026-10-08-01-32-15.gh-issue-158985.tKnysx.rst new file mode 100644 index 000000000000000..ec7915a831bec54 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-10-08-01-32-15.gh-issue-158985.tKnysx.rst @@ -0,0 +1,5 @@ +Fix :mod:`cProfile` and :mod:`profile` when profiling a module with the +``-m`` option: the module now runs as ``__main__`` and ``sys.argv[0]`` is +set to its path, as with ``python -m``. This fixes errors when pickling +objects defined in the module, for example when using :mod:`multiprocessing` +with the ``spawn`` start method.