Home | History | Annotate | Download | only in coverage
      1 """Execute files of Python code."""
      2 
      3 import imp, os, sys
      4 
      5 from coverage.backward import exec_code_object, open_source
      6 from coverage.misc import NoSource, ExceptionDuringRun
      7 
      8 
      9 try:
     10     # In Py 2.x, the builtins were in __builtin__
     11     BUILTINS = sys.modules['__builtin__']
     12 except KeyError:
     13     # In Py 3.x, they're in builtins
     14     BUILTINS = sys.modules['builtins']
     15 
     16 
     17 def rsplit1(s, sep):
     18     """The same as s.rsplit(sep, 1), but works in 2.3"""
     19     parts = s.split(sep)
     20     return sep.join(parts[:-1]), parts[-1]
     21 
     22 
     23 def run_python_module(modulename, args):
     24     """Run a python module, as though with ``python -m name args...``.
     25 
     26     `modulename` is the name of the module, possibly a dot-separated name.
     27     `args` is the argument array to present as sys.argv, including the first
     28     element naming the module being executed.
     29 
     30     """
     31     openfile = None
     32     glo, loc = globals(), locals()
     33     try:
     34         try:
     35             # Search for the module - inside its parent package, if any - using
     36             # standard import mechanics.
     37             if '.' in modulename:
     38                 packagename, name = rsplit1(modulename, '.')
     39                 package = __import__(packagename, glo, loc, ['__path__'])
     40                 searchpath = package.__path__
     41             else:
     42                 packagename, name = None, modulename
     43                 searchpath = None  # "top-level search" in imp.find_module()
     44             openfile, pathname, _ = imp.find_module(name, searchpath)
     45 
     46             # Complain if this is a magic non-file module.
     47             if openfile is None and pathname is None:
     48                 raise NoSource(
     49                     "module does not live in a file: %r" % modulename
     50                     )
     51 
     52             # If `modulename` is actually a package, not a mere module, then we
     53             # pretend to be Python 2.7 and try running its __main__.py script.
     54             if openfile is None:
     55                 packagename = modulename
     56                 name = '__main__'
     57                 package = __import__(packagename, glo, loc, ['__path__'])
     58                 searchpath = package.__path__
     59                 openfile, pathname, _ = imp.find_module(name, searchpath)
     60         except ImportError:
     61             _, err, _ = sys.exc_info()
     62             raise NoSource(str(err))
     63     finally:
     64         if openfile:
     65             openfile.close()
     66 
     67     # Finally, hand the file off to run_python_file for execution.
     68     run_python_file(pathname, args, package=packagename)
     69 
     70 
     71 def run_python_file(filename, args, package=None):
     72     """Run a python file as if it were the main program on the command line.
     73 
     74     `filename` is the path to the file to execute, it need not be a .py file.
     75     `args` is the argument array to present as sys.argv, including the first
     76     element naming the file being executed.  `package` is the name of the
     77     enclosing package, if any.
     78 
     79     """
     80     # Create a module to serve as __main__
     81     old_main_mod = sys.modules['__main__']
     82     main_mod = imp.new_module('__main__')
     83     sys.modules['__main__'] = main_mod
     84     main_mod.__file__ = filename
     85     main_mod.__package__ = package
     86     main_mod.__builtins__ = BUILTINS
     87 
     88     # Set sys.argv and the first path element properly.
     89     old_argv = sys.argv
     90     old_path0 = sys.path[0]
     91     sys.argv = args
     92     sys.path[0] = os.path.abspath(os.path.dirname(filename))
     93 
     94     try:
     95         # Open the source file.
     96         try:
     97             source_file = open_source(filename)
     98         except IOError:
     99             raise NoSource("No file to run: %r" % filename)
    100 
    101         try:
    102             source = source_file.read()
    103         finally:
    104             source_file.close()
    105 
    106         # We have the source.  `compile` still needs the last line to be clean,
    107         # so make sure it is, then compile a code object from it.
    108         if source[-1] != '\n':
    109             source += '\n'
    110         code = compile(source, filename, "exec")
    111 
    112         # Execute the source file.
    113         try:
    114             exec_code_object(code, main_mod.__dict__)
    115         except SystemExit:
    116             # The user called sys.exit().  Just pass it along to the upper
    117             # layers, where it will be handled.
    118             raise
    119         except:
    120             # Something went wrong while executing the user code.
    121             # Get the exc_info, and pack them into an exception that we can
    122             # throw up to the outer loop.  We peel two layers off the traceback
    123             # so that the coverage.py code doesn't appear in the final printed
    124             # traceback.
    125             typ, err, tb = sys.exc_info()
    126             raise ExceptionDuringRun(typ, err, tb.tb_next.tb_next)
    127     finally:
    128         # Restore the old __main__
    129         sys.modules['__main__'] = old_main_mod
    130 
    131         # Restore the old argv and path
    132         sys.argv = old_argv
    133         sys.path[0] = old_path0
    134