Commits

Ned Batchelder  committed ce5ea97 Merge

Automated merge with file:///home/ned/coverage/trunk

  • Participants
  • Parent commits b32ba92, e482029

Comments (0)

Files changed (2)

File coverage/cmdline.py

 import optparse, re, sys, traceback
 
 from coverage.backward import sorted                # pylint: disable=W0622
-from coverage.execfile import run_python_file
+from coverage.execfile import run_python_file, run_python_module
 from coverage.misc import CoverageException, ExceptionDuringRun
 
 
                 ".coverage data file name to simplify collecting data from "
                 "many processes."
         )
+    module = optparse.make_option(
+        '-m', '--module', action='store_true',
+        help="First argument is a Python module, not a script path,"
+                " which should be run as `python -m` would run it."
+        )
     rcfile = optparse.make_option(
         '', '--rcfile', action='store',
         help="Specify configuration file.  Defaults to '.coveragerc'"
             include=None,
             omit=None,
             parallel_mode=None,
+            module=None,
             pylib=None,
             rcfile=True,
             show_missing=None,
             Opts.branch,
             Opts.pylib,
             Opts.parallel_mode,
+            Opts.module,
             Opts.timid,
             Opts.source,
             Opts.omit,
 class CoverageScript(object):
     """The command-line interface to Coverage."""
 
-    def __init__(self, _covpkg=None, _run_python_file=None, _help_fn=None):
+    def __init__(self, _covpkg=None, _run_python_file=None,
+                 _run_python_module=None, _help_fn=None):
         # _covpkg is for dependency injection, so we can test this code.
         if _covpkg:
             self.covpkg = _covpkg
             import coverage
             self.covpkg = coverage
 
-        # _run_python_file is for dependency injection also.
+        # For dependency injection:
         self.run_python_file = _run_python_file or run_python_file
-
-        # _help_fn is for dependency injection.
+        self.run_python_module = _run_python_module or run_python_module
         self.help_fn = _help_fn or self.help
 
         self.coverage = None
             # Run the script.
             self.coverage.start()
             try:
-                self.run_python_file(args[0], args)
+                if options.module:
+                    self.run_python_module(args[0], args)
+                else:
+                    self.run_python_file(args[0], args)
             finally:
                 self.coverage.stop()
                 self.coverage.save()

File coverage/execfile.py

     BUILTINS = sys.modules['builtins']
 
 
-def run_python_file(filename, args):
+def run_python_module(modulename, args):
+    """Run a python module, as though with ``python -m name args...``.
+
+    """
+    # Search for the module - inside its parent package, if any - using
+    # standard import mechanics.
+    if '.' in modulename:
+        packagename, name = modulename.rsplit('.')
+        package = __import__(packagename, fromlist=['__path__'])
+        searchpath = package.__path__
+    else:
+        packagename = None
+        name = modulename
+        searchpath = None  # means "top-level search" to find_module()
+    openfile, pathname, description = imp.find_module(name, searchpath)
+
+    # Complain if this is a magic non-file module.
+    if openfile is None and pathname is None:
+        raise NoSource("module does not live in a file: %r" % modulename)
+
+    # If `modulename` is actually a package, not a mere module, then we
+    # pretend to be Python 2.7 and try running its __main__.py script.
+    if openfile is None:
+        packagename = modulename
+        name = '__main__'
+
+        package = __import__(packagename, fromlist=['__path__'])
+        searchpath = package.__path__
+        openfile, pathname, description = imp.find_module(name, searchpath)
+
+    # Finally, hand the file off to run_python_file for execution.
+    openfile.close()
+    run_python_file(pathname, args, package=packagename)
+
+
+def run_python_file(filename, args, package=None):
     """Run a python file as if it were the main program on the command line.
 
     `filename` is the path to the file to execute, it need not be a .py file.
     main_mod = imp.new_module('__main__')
     sys.modules['__main__'] = main_mod
     main_mod.__file__ = filename
+    main_mod.__package__ = package
     main_mod.__builtins__ = BUILTINS
 
     # Set sys.argv and the first path element properly.