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