Sitelet https://github.com/python/cpython/commit/ad1a25f499362eaf9cbfcafa0b8e2454eb43dcf1
Skip to content

Commit ad1a25f

Browse files
mariocj89ncoghlan
authored andcommitted
bpo-32512: Add -m option to profile for profiling modules (#5132)
The new option in the CLI of the profile module allow to profile executable modules. This change follows the same implementation as the one already present in `cProfile`. As the argument is now present on both modules, move the tests to the common test case to be run with profile as well.
1 parent 2810dd7 commit ad1a25f

5 files changed

Lines changed: 42 additions & 27 deletions

File tree

‎Doc/library/profile.rst‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@ results to a file by specifying a filename to the :func:`run` function::
120120
The :class:`pstats.Stats` class reads profile results from a file and formats
121121
them in various ways.
122122

123-
The file :mod:`cProfile` can also be invoked as a script to profile another
124-
script. For example::
123+
The files :mod:`cProfile` and :mod:`profile` can also be invoked as a script to
124+
profile another script. For example::
125125

126126
python -m cProfile [-o output_file] [-s sort_order] (-m module | myscript.py)
127127

@@ -133,7 +133,10 @@ the output by. This only applies when ``-o`` is not supplied.
133133
``-m`` specifies that a module is being profiled instead of a script.
134134

135135
.. versionadded:: 3.7
136-
Added the ``-m`` option.
136+
Added the ``-m`` option to :mod:`cProfile`.
137+
138+
.. versionadded:: 3.8
139+
Added the ``-m`` option to :mod:`profile`.
137140

138141
The :mod:`pstats` module's :class:`~pstats.Stats` class has a variety of methods
139142
for manipulating and printing the data saved into a profile results file::

‎Lib/profile.py‎

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -553,11 +553,13 @@ def main():
553553
import os
554554
from optparse import OptionParser
555555

556-
usage = "profile.py [-o output_file_path] [-s sort] scriptfile [arg] ..."
556+
usage = "profile.py [-o output_file_path] [-s sort] [-m module | scriptfile] [arg] ..."
557557
parser = OptionParser(usage=usage)
558558
parser.allow_interspersed_args = False
559559
parser.add_option('-o', '--outfile', dest="outfile",
560560
help="Save stats to <outfile>", default=None)
561+
parser.add_option('-m', dest="module", action="store_true",
562+
help="Profile a library module.", default=False)
561563
parser.add_option('-s', '--sort', dest="sort",
562564
help="Sort order when printing to stdout, based on pstats.Stats class",
563565
default=-1)
@@ -570,16 +572,24 @@ def main():
570572
sys.argv[:] = args
571573

572574
if len(args) > 0:
573-
progname = args[0]
574-
sys.path.insert(0, os.path.dirname(progname))
575-
with open(progname, 'rb') as fp:
576-
code = compile(fp.read(), progname, 'exec')
577-
globs = {
578-
'__file__': progname,
579-
'__name__': '__main__',
580-
'__package__': None,
581-
'__cached__': None,
582-
}
575+
if options.module:
576+
import runpy
577+
code = "run_module(modname, run_name='__main__')"
578+
globs = {
579+
'run_module': runpy.run_module,
580+
'modname': args[0]
581+
}
582+
else:
583+
progname = args[0]
584+
sys.path.insert(0, os.path.dirname(progname))
585+
with open(progname, 'rb') as fp:
586+
code = compile(fp.read(), progname, 'exec')
587+
globs = {
588+
'__file__': progname,
589+
'__name__': '__main__',
590+
'__package__': None,
591+
'__cached__': None,
592+
}
583593
runctx(code, globs, None, options.outfile, options.sort)
584594
else:
585595
parser.print_usage()

‎Lib/test/test_cprofile.py‎

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,6 @@ def test_bad_counter_during_dealloc(self):
3737
finally:
3838
unlink(TESTFN)
3939

40-
# Issue 21862
41-
def test_module_path_option(self):
42-
# Test -m switch with modules
43-
44-
# Test that -m switch needs an argument
45-
assert_python_failure('-m', 'cProfile', '-m')
46-
47-
# Test failure for not-existent module
48-
assert_python_failure('-m', 'cProfile', '-m', 'random_module_xyz')
49-
50-
# Test successful run
51-
assert_python_ok('-m', 'cProfile', '-m', 'timeit', '-n', '1')
52-
5340
def test_profile_enable_disable(self):
5441
prof = self.profilerclass()
5542
# Make sure we clean ourselves up if the test fails for some reason.

‎Lib/test/test_profile.py‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import profile
1313
from test.profilee import testfunc, timer
14+
from test.support.script_helper import assert_python_failure, assert_python_ok
1415

1516

1617
class ProfileTest(unittest.TestCase):
@@ -98,6 +99,18 @@ def test_runctx(self):
9899
filename=TESTFN)
99100
self.assertTrue(os.path.exists(TESTFN))
100101

102+
def test_run_profile_as_module(self):
103+
# Test that -m switch needs an argument
104+
assert_python_failure('-m', self.profilermodule.__name__, '-m')
105+
106+
# Test failure for not-existent module
107+
assert_python_failure('-m', self.profilermodule.__name__,
108+
'-m', 'random_module_xyz')
109+
110+
# Test successful run
111+
assert_python_ok('-m', self.profilermodule.__name__,
112+
'-m', 'timeit', '-n', '1')
113+
101114

102115
def regenerate_expected_output(filename, cls):
103116
filename = filename.rstrip('co')
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:mod:`profile` CLI accepts `-m module_name` as an alternative to
2+
script path.

0 commit comments

Comments
 (0)