[Python-checkins] bpo-32512: Add -m option to profile for profiling modules (#5132)

Nick Coghlan webhook-mailer at python.org
Mon Nov 5 07:03:51 EST 2018


https://github.com/python/cpython/commit/ad1a25f499362eaf9cbfcafa0b8e2454eb43dcf1
commit: ad1a25f499362eaf9cbfcafa0b8e2454eb43dcf1
branch: master
author: Mario Corchero <mariocj89 at gmail.com>
committer: Nick Coghlan <ncoghlan at gmail.com>
date: 2018-11-05T22:03:46+10:00
summary:

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.

files:
A Misc/NEWS.d/next/Library/2018-01-07-17-43-10.bpo-32512.flC-dE.rst
M Doc/library/profile.rst
M Lib/profile.py
M Lib/test/test_cprofile.py
M Lib/test/test_profile.py

diff --git a/Doc/library/profile.rst b/Doc/library/profile.rst
index 1a772fb7f941..9ceb81603c95 100644
--- a/Doc/library/profile.rst
+++ b/Doc/library/profile.rst
@@ -120,8 +120,8 @@ results to a file by specifying a filename to the :func:`run` function::
 The :class:`pstats.Stats` class reads profile results from a file and formats
 them in various ways.
 
-The file :mod:`cProfile` can also be invoked as a script to profile another
-script.  For example::
+The files :mod:`cProfile` and :mod:`profile` can also be invoked as a script to
+profile another script.  For example::
 
    python -m cProfile [-o output_file] [-s sort_order] (-m module | myscript.py)
 
@@ -133,7 +133,10 @@ the output by. This only applies when ``-o`` is not supplied.
 ``-m`` specifies that a module is being profiled instead of a script.
 
    .. versionadded:: 3.7
-      Added the ``-m`` option.
+      Added the ``-m`` option to :mod:`cProfile`.
+
+   .. versionadded:: 3.8
+      Added the ``-m`` option to :mod:`profile`.
 
 The :mod:`pstats` module's :class:`~pstats.Stats` class has a variety of methods
 for manipulating and printing the data saved into a profile results file::
diff --git a/Lib/profile.py b/Lib/profile.py
index 0340a7907bfd..5df43604acdd 100755
--- a/Lib/profile.py
+++ b/Lib/profile.py
@@ -553,11 +553,13 @@ def main():
     import os
     from optparse import OptionParser
 
-    usage = "profile.py [-o output_file_path] [-s sort] scriptfile [arg] ..."
+    usage = "profile.py [-o output_file_path] [-s sort] [-m module | scriptfile] [arg] ..."
     parser = OptionParser(usage=usage)
     parser.allow_interspersed_args = False
     parser.add_option('-o', '--outfile', dest="outfile",
         help="Save stats to <outfile>", default=None)
+    parser.add_option('-m', dest="module", action="store_true",
+        help="Profile a library module.", default=False)
     parser.add_option('-s', '--sort', dest="sort",
         help="Sort order when printing to stdout, based on pstats.Stats class",
         default=-1)
@@ -570,16 +572,24 @@ def main():
     sys.argv[:] = args
 
     if len(args) > 0:
-        progname = args[0]
-        sys.path.insert(0, os.path.dirname(progname))
-        with open(progname, 'rb') as fp:
-            code = compile(fp.read(), progname, 'exec')
-        globs = {
-            '__file__': progname,
-            '__name__': '__main__',
-            '__package__': None,
-            '__cached__': None,
-        }
+        if options.module:
+            import runpy
+            code = "run_module(modname, run_name='__main__')"
+            globs = {
+                'run_module': runpy.run_module,
+                'modname': args[0]
+            }
+        else:
+            progname = args[0]
+            sys.path.insert(0, os.path.dirname(progname))
+            with open(progname, 'rb') as fp:
+                code = compile(fp.read(), progname, 'exec')
+            globs = {
+                '__file__': progname,
+                '__name__': '__main__',
+                '__package__': None,
+                '__cached__': None,
+            }
         runctx(code, globs, None, options.outfile, options.sort)
     else:
         parser.print_usage()
diff --git a/Lib/test/test_cprofile.py b/Lib/test/test_cprofile.py
index 406d70305f9e..efcf6bc92803 100644
--- a/Lib/test/test_cprofile.py
+++ b/Lib/test/test_cprofile.py
@@ -37,19 +37,6 @@ def test_bad_counter_during_dealloc(self):
         finally:
             unlink(TESTFN)
 
-    # Issue 21862
-    def test_module_path_option(self):
-        # Test -m switch with modules
-
-        # Test that -m switch needs an argument
-        assert_python_failure('-m', 'cProfile', '-m')
-
-        # Test failure for not-existent module
-        assert_python_failure('-m', 'cProfile', '-m', 'random_module_xyz')
-
-        # Test successful run
-        assert_python_ok('-m', 'cProfile', '-m', 'timeit', '-n', '1')
-
     def test_profile_enable_disable(self):
         prof = self.profilerclass()
         # Make sure we clean ourselves up if the test fails for some reason.
diff --git a/Lib/test/test_profile.py b/Lib/test/test_profile.py
index a9982663175a..01a8a6eaf5a2 100644
--- a/Lib/test/test_profile.py
+++ b/Lib/test/test_profile.py
@@ -11,6 +11,7 @@
 
 import profile
 from test.profilee import testfunc, timer
+from test.support.script_helper import assert_python_failure, assert_python_ok
 
 
 class ProfileTest(unittest.TestCase):
@@ -98,6 +99,18 @@ def test_runctx(self):
                                   filename=TESTFN)
         self.assertTrue(os.path.exists(TESTFN))
 
+    def test_run_profile_as_module(self):
+        # Test that -m switch needs an argument
+        assert_python_failure('-m', self.profilermodule.__name__, '-m')
+
+        # Test failure for not-existent module
+        assert_python_failure('-m', self.profilermodule.__name__,
+                              '-m', 'random_module_xyz')
+
+        # Test successful run
+        assert_python_ok('-m', self.profilermodule.__name__,
+                         '-m', 'timeit', '-n', '1')
+
 
 def regenerate_expected_output(filename, cls):
     filename = filename.rstrip('co')
diff --git a/Misc/NEWS.d/next/Library/2018-01-07-17-43-10.bpo-32512.flC-dE.rst b/Misc/NEWS.d/next/Library/2018-01-07-17-43-10.bpo-32512.flC-dE.rst
new file mode 100644
index 000000000000..0a7763daffad
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2018-01-07-17-43-10.bpo-32512.flC-dE.rst
@@ -0,0 +1,2 @@
+:mod:`profile` CLI accepts `-m module_name` as an alternative to
+script path.



More information about the Python-checkins mailing list