Skip to content

Commit c7a7aa9

Browse files
authored
gh-132737: Support profiling modules that require __main___ (#132738)
1 parent e1c09ff commit c7a7aa9

File tree

3 files changed

+29
-3
lines changed

3 files changed

+29
-3
lines changed

Lib/cProfile.py

+12-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import _lsprof
88
import importlib.machinery
9+
import importlib.util
910
import io
1011
import profile as _pyprofile
1112

@@ -173,13 +174,22 @@ def main():
173174
code = compile(fp.read(), progname, 'exec')
174175
spec = importlib.machinery.ModuleSpec(name='__main__', loader=None,
175176
origin=progname)
176-
globs = {
177+
module = importlib.util.module_from_spec(spec)
178+
# Set __main__ so that importing __main__ in the profiled code will
179+
# return the same namespace that the code is executing under.
180+
sys.modules['__main__'] = module
181+
# Ensure that we're using the same __dict__ instance as the module
182+
# for the global variables so that updates to globals are reflected
183+
# in the module's namespace.
184+
globs = module.__dict__
185+
globs.update({
177186
'__spec__': spec,
178187
'__file__': spec.origin,
179188
'__name__': spec.name,
180189
'__package__': None,
181190
'__cached__': None,
182-
}
191+
})
192+
183193
try:
184194
runctx(code, globs, None, options.outfile, options.sort)
185195
except BrokenPipeError as exc:

Lib/test/test_cprofile.py

+16-1
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55

66
# rip off all interesting stuff from test_profile
77
import cProfile
8+
import tempfile
9+
import textwrap
810
from test.test_profile import ProfileTest, regenerate_expected_output
9-
from test.support.script_helper import assert_python_failure
11+
from test.support.script_helper import assert_python_failure, assert_python_ok
1012
from test import support
1113

1214

@@ -154,6 +156,19 @@ def test_sort(self):
154156
self.assertGreater(rc, 0)
155157
self.assertIn(b"option -s: invalid choice: 'demo'", err)
156158

159+
def test_profile_script_importing_main(self):
160+
"""Check that scripts that reference __main__ see their own namespace
161+
when being profiled."""
162+
with tempfile.NamedTemporaryFile("w+", delete_on_close=False) as f:
163+
f.write(textwrap.dedent("""\
164+
class Foo:
165+
pass
166+
import __main__
167+
assert Foo == __main__.Foo
168+
"""))
169+
f.close()
170+
assert_python_ok('-m', "cProfile", f.name)
171+
157172

158173
def main():
159174
if '-r' not in sys.argv:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Support profiling code that requires ``__main__``, such as :mod:`pickle`.

0 commit comments

Comments
 (0)