summaryrefslogtreecommitdiff
path: root/python/helpers/coverage/execfile.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/helpers/coverage/execfile.py')
-rw-r--r--python/helpers/coverage/execfile.py86
1 files changed, 62 insertions, 24 deletions
diff --git a/python/helpers/coverage/execfile.py b/python/helpers/coverage/execfile.py
index 71227b715a3e..f6ebdf79bb9e 100644
--- a/python/helpers/coverage/execfile.py
+++ b/python/helpers/coverage/execfile.py
@@ -1,9 +1,9 @@
"""Execute files of Python code."""
-import imp, os, sys
+import imp, marshal, os, sys
from coverage.backward import exec_code_object, open_source
-from coverage.misc import NoSource, ExceptionDuringRun
+from coverage.misc import ExceptionDuringRun, NoCode, NoSource
try:
@@ -65,6 +65,8 @@ def run_python_module(modulename, args):
openfile.close()
# Finally, hand the file off to run_python_file for execution.
+ pathname = os.path.abspath(pathname)
+ args[0] = pathname
run_python_file(pathname, args, package=packagename)
@@ -82,34 +84,22 @@ def run_python_file(filename, args, package=None):
main_mod = imp.new_module('__main__')
sys.modules['__main__'] = main_mod
main_mod.__file__ = filename
- main_mod.__package__ = package
+ if package:
+ main_mod.__package__ = package
main_mod.__builtins__ = BUILTINS
- # Set sys.argv and the first path element properly.
+ # Set sys.argv properly.
old_argv = sys.argv
- old_path0 = sys.path[0]
sys.argv = args
- sys.path[0] = os.path.abspath(os.path.dirname(filename))
try:
- # Open the source file.
- try:
- source_file = open_source(filename)
- except IOError:
- raise NoSource("No file to run: %r" % filename)
+ # Make a code object somehow.
+ if filename.endswith(".pyc") or filename.endswith(".pyo"):
+ code = make_code_from_pyc(filename)
+ else:
+ code = make_code_from_py(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':
- source += '\n'
- code = compile(source, filename, "exec")
-
- # Execute the source file.
+ # Execute the code object.
try:
exec_code_object(code, main_mod.__dict__)
except SystemExit:
@@ -130,4 +120,52 @@ def run_python_file(filename, args, package=None):
# Restore the old argv and path
sys.argv = old_argv
- sys.path[0] = old_path0
+
+def make_code_from_py(filename):
+ """Get source from `filename` and make a code object of it."""
+ # Open the source file.
+ try:
+ 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 not source or source[-1] != '\n':
+ source += '\n'
+ code = compile(source, filename, "exec")
+
+ return code
+
+
+def make_code_from_pyc(filename):
+ """Get a code object from a .pyc file."""
+ try:
+ fpyc = open(filename, "rb")
+ except IOError:
+ raise NoCode("No file to run: %r" % filename)
+
+ try:
+ # First four bytes are a version-specific magic number. It has to
+ # match or we won't run the file.
+ magic = fpyc.read(4)
+ if magic != imp.get_magic():
+ raise NoCode("Bad magic number in .pyc file")
+
+ # Skip the junk in the header that we don't need.
+ fpyc.read(4) # Skip the moddate.
+ if sys.version_info >= (3, 3):
+ # 3.3 added another long to the header (size), skip it.
+ fpyc.read(4)
+
+ # The rest of the file is the code object we want.
+ code = marshal.load(fpyc)
+ finally:
+ fpyc.close()
+
+ return code