summaryrefslogtreecommitdiff
path: root/coverage/execfile.py
diff options
context:
space:
mode:
Diffstat (limited to 'coverage/execfile.py')
-rw-r--r--coverage/execfile.py78
1 files changed, 72 insertions, 6 deletions
diff --git a/coverage/execfile.py b/coverage/execfile.py
index 333163f8..587c2d3c 100644
--- a/coverage/execfile.py
+++ b/coverage/execfile.py
@@ -2,7 +2,7 @@
import imp, os, sys
-from coverage.backward import exec_code_object
+from coverage.backward import exec_code_object, open_source
from coverage.misc import NoSource, ExceptionDuringRun
@@ -14,12 +14,68 @@ except KeyError:
BUILTINS = sys.modules['builtins']
-def run_python_file(filename, args):
+def rsplit1(s, sep):
+ """The same as s.rsplit(sep, 1), but works in 2.3"""
+ parts = s.split(sep)
+ return sep.join(parts[:-1]), parts[-1]
+
+
+def run_python_module(modulename, args):
+ """Run a python module, as though with ``python -m name args...``.
+
+ `modulename` is the name of the module, possibly a dot-separated name.
+ `args` is the argument array to present as sys.argv, including the first
+ element naming the module being executed.
+
+ """
+ openfile = None
+ glo, loc = globals(), locals()
+ try:
+ try:
+ # Search for the module - inside its parent package, if any - using
+ # standard import mechanics.
+ if '.' in modulename:
+ packagename, name = rsplit1(modulename, '.')
+ package = __import__(packagename, glo, loc, ['__path__'])
+ searchpath = package.__path__
+ else:
+ packagename, name = None, modulename
+ searchpath = None # "top-level search" in imp.find_module()
+ openfile, pathname, _ = 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, glo, loc, ['__path__'])
+ searchpath = package.__path__
+ openfile, pathname, _ = imp.find_module(name, searchpath)
+ except ImportError:
+ _, err, _ = sys.exc_info()
+ raise NoSource(str(err))
+ finally:
+ if openfile:
+ openfile.close()
+
+ # Finally, hand the file off to run_python_file for execution.
+ args[0] = pathname
+ 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.
`args` is the argument array to present as sys.argv, including the first
- element representing the file being executed.
+ element naming the file being executed. `package` is the name of the
+ enclosing package, if any.
"""
# Create a module to serve as __main__
@@ -27,24 +83,34 @@ def run_python_file(filename, args):
main_mod = imp.new_module('__main__')
sys.modules['__main__'] = main_mod
main_mod.__file__ = filename
+ if package:
+ main_mod.__package__ = package
main_mod.__builtins__ = BUILTINS
# Set sys.argv and the first path element properly.
old_argv = sys.argv
old_path0 = sys.path[0]
sys.argv = args
- sys.path[0] = os.path.dirname(filename)
+ if package:
+ sys.path[0] = ''
+ else:
+ sys.path[0] = os.path.abspath(os.path.dirname(filename))
try:
# Open the source file.
try:
- source = open(filename, 'rU').read()
+ source_file = open_source(filename)
except IOError:
raise NoSource("No file to run: %r" % filename)
+ try:
+ source = source_file.read()
+ finally:
+ source_file.close()
+
# We have the source. `compile` still needs the last line to be clean,
# so make sure it is, then compile a code object from it.
- if source[-1] != '\n':
+ if not source or source[-1] != '\n':
source += '\n'
code = compile(source, filename, "exec")