Skip to content

Commit ea46bab

Browse files
committed
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.
1 parent 9d22a53 commit ea46bab

4 files changed

Lines changed: 27 additions & 3 deletions

File tree

‎Lib/profile.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,7 @@ def main():
590590
if len(args) > 0:
591591
if options.module:
592592
import runpy
593-
code = "run_module(modname, run_name='__main__')"
593+
code = "run_module(modname, run_name='__main__', alter_sys=True)"
594594
globs = {
595595
'run_module': runpy.run_module,
596596
'modname': args[0]

‎Lib/profiling/tracing/__init__.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ def main():
176176

177177
if len(args) > 0:
178178
if options.module:
179-
code = "run_module(modname, run_name='__main__')"
179+
code = "run_module(modname, run_name='__main__', alter_sys=True)"
180180
globs = {
181181
'run_module': runpy.run_module,
182182
'modname': args[0]

‎Lib/test/test_profile.py‎

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import pstats
55
import unittest
66
import os
7+
import textwrap
78
import warnings
89
from difflib import unified_diff
910
from io import StringIO
@@ -15,7 +16,8 @@
1516
warnings.simplefilter("ignore", DeprecationWarning)
1617
import profile
1718
from test.profilee import testfunc, timer
18-
from test.support.script_helper import assert_python_failure, assert_python_ok
19+
from test.support.script_helper import (
20+
assert_python_failure, assert_python_ok, make_script)
1921

2022

2123
class ProfileTest(unittest.TestCase):
@@ -120,6 +122,23 @@ def test_run_profile_as_module(self):
120122
assert_python_ok('-m', self.profilermodule.__name__,
121123
'-m', 'timeit', '-n', '1')
122124

125+
def test_profile_module_as_main(self):
126+
# The module must run as __main__, like with "python -m module".
127+
with temp_dir() as tmpdir:
128+
make_script(tmpdir, 'profiled_module', textwrap.dedent("""\
129+
import pickle
130+
import sys
131+
132+
class Foo:
133+
pass
134+
135+
assert sys.modules['__main__'].Foo is Foo
136+
assert sys.argv[0].endswith('profiled_module.py')
137+
pickle.dumps(Foo())
138+
"""))
139+
assert_python_ok('-m', self.profilermodule.__name__,
140+
'-m', 'profiled_module', PYTHONPATH=tmpdir)
141+
123142
def test_output_file_when_changing_directory(self):
124143
with temp_dir() as tmpdir, change_cwd(tmpdir):
125144
os.mkdir('dest')
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Fix :mod:`cProfile` and :mod:`profile` when profiling a module with the
2+
``-m`` option: the module now runs as ``__main__`` and ``sys.argv[0]`` is
3+
set to its path, as with ``python -m``. This fixes errors when pickling
4+
objects defined in the module, for example when using :mod:`multiprocessing`
5+
with the ``spawn`` start method.

0 commit comments

Comments
 (0)