1"""Execute files of Python code.""" 2 3import imp, os, sys 4 5from coverage.backward import exec_code_object, open_source 6from coverage.misc import NoSource, ExceptionDuringRun 7 8 9try: 10 # In Py 2.x, the builtins were in __builtin__ 11 BUILTINS = sys.modules['__builtin__'] 12except KeyError: 13 # In Py 3.x, they're in builtins 14 BUILTINS = sys.modules['builtins'] 15 16 17def 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 23def 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 71def 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