DebugClients/Python/coverage/execfile.py

branch
debugger speed
changeset 5178
878ce843ca9f
parent 5051
3586ebd9fac8
child 6219
d6c795b5ce33
equal deleted inserted replaced
5174:8c48f5e0cd92 5178:878ce843ca9f
1 # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2 # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
3
4 """Execute files of Python code."""
5
6 import marshal
7 import os
8 import sys
9 import types
10
11 from coverage.backward import BUILTINS
12 from coverage.backward import PYC_MAGIC_NUMBER, imp, importlib_util_find_spec
13 from coverage.misc import ExceptionDuringRun, NoCode, NoSource, isolate_module
14 from coverage.phystokens import compile_unicode
15 from coverage.python import get_python_source
16
17 os = isolate_module(os)
18
19
20 class DummyLoader(object):
21 """A shim for the pep302 __loader__, emulating pkgutil.ImpLoader.
22
23 Currently only implements the .fullname attribute
24 """
25 def __init__(self, fullname, *_args):
26 self.fullname = fullname
27
28
29 if importlib_util_find_spec:
30 def find_module(modulename):
31 """Find the module named `modulename`.
32
33 Returns the file path of the module, and the name of the enclosing
34 package.
35 """
36 try:
37 spec = importlib_util_find_spec(modulename)
38 except ImportError as err:
39 raise NoSource(str(err))
40 if not spec:
41 raise NoSource("No module named %r" % (modulename,))
42 pathname = spec.origin
43 packagename = spec.name
44 if pathname.endswith("__init__.py") and not modulename.endswith("__init__"):
45 mod_main = modulename + ".__main__"
46 spec = importlib_util_find_spec(mod_main)
47 if not spec:
48 raise NoSource(
49 "No module named %s; "
50 "%r is a package and cannot be directly executed"
51 % (mod_main, modulename)
52 )
53 pathname = spec.origin
54 packagename = spec.name
55 packagename = packagename.rpartition(".")[0]
56 return pathname, packagename
57 else:
58 def find_module(modulename):
59 """Find the module named `modulename`.
60
61 Returns the file path of the module, and the name of the enclosing
62 package.
63 """
64 openfile = None
65 glo, loc = globals(), locals()
66 try:
67 # Search for the module - inside its parent package, if any - using
68 # standard import mechanics.
69 if '.' in modulename:
70 packagename, name = modulename.rsplit('.', 1)
71 package = __import__(packagename, glo, loc, ['__path__'])
72 searchpath = package.__path__
73 else:
74 packagename, name = None, modulename
75 searchpath = None # "top-level search" in imp.find_module()
76 openfile, pathname, _ = imp.find_module(name, searchpath)
77
78 # Complain if this is a magic non-file module.
79 if openfile is None and pathname is None:
80 raise NoSource(
81 "module does not live in a file: %r" % modulename
82 )
83
84 # If `modulename` is actually a package, not a mere module, then we
85 # pretend to be Python 2.7 and try running its __main__.py script.
86 if openfile is None:
87 packagename = modulename
88 name = '__main__'
89 package = __import__(packagename, glo, loc, ['__path__'])
90 searchpath = package.__path__
91 openfile, pathname, _ = imp.find_module(name, searchpath)
92 except ImportError as err:
93 raise NoSource(str(err))
94 finally:
95 if openfile:
96 openfile.close()
97
98 return pathname, packagename
99
100
101 def run_python_module(modulename, args):
102 """Run a Python module, as though with ``python -m name args...``.
103
104 `modulename` is the name of the module, possibly a dot-separated name.
105 `args` is the argument array to present as sys.argv, including the first
106 element naming the module being executed.
107
108 """
109 pathname, packagename = find_module(modulename)
110
111 pathname = os.path.abspath(pathname)
112 args[0] = pathname
113 run_python_file(pathname, args, package=packagename, modulename=modulename, path0="")
114
115
116 def run_python_file(filename, args, package=None, modulename=None, path0=None):
117 """Run a Python file as if it were the main program on the command line.
118
119 `filename` is the path to the file to execute, it need not be a .py file.
120 `args` is the argument array to present as sys.argv, including the first
121 element naming the file being executed. `package` is the name of the
122 enclosing package, if any.
123
124 `modulename` is the name of the module the file was run as.
125
126 `path0` is the value to put into sys.path[0]. If it's None, then this
127 function will decide on a value.
128
129 """
130 if modulename is None and sys.version_info >= (3, 3):
131 modulename = '__main__'
132
133 # Create a module to serve as __main__
134 old_main_mod = sys.modules['__main__']
135 main_mod = types.ModuleType('__main__')
136 sys.modules['__main__'] = main_mod
137 main_mod.__file__ = filename
138 if package:
139 main_mod.__package__ = package
140 if modulename:
141 main_mod.__loader__ = DummyLoader(modulename)
142
143 main_mod.__builtins__ = BUILTINS
144
145 # Set sys.argv properly.
146 old_argv = sys.argv
147 sys.argv = args
148
149 if os.path.isdir(filename):
150 # Running a directory means running the __main__.py file in that
151 # directory.
152 my_path0 = filename
153
154 for ext in [".py", ".pyc", ".pyo"]:
155 try_filename = os.path.join(filename, "__main__" + ext)
156 if os.path.exists(try_filename):
157 filename = try_filename
158 break
159 else:
160 raise NoSource("Can't find '__main__' module in '%s'" % filename)
161 else:
162 my_path0 = os.path.abspath(os.path.dirname(filename))
163
164 # Set sys.path correctly.
165 old_path0 = sys.path[0]
166 sys.path[0] = path0 if path0 is not None else my_path0
167
168 try:
169 # Make a code object somehow.
170 if filename.endswith((".pyc", ".pyo")):
171 code = make_code_from_pyc(filename)
172 else:
173 code = make_code_from_py(filename)
174
175 # Execute the code object.
176 try:
177 exec(code, main_mod.__dict__)
178 except SystemExit:
179 # The user called sys.exit(). Just pass it along to the upper
180 # layers, where it will be handled.
181 raise
182 except:
183 # Something went wrong while executing the user code.
184 # Get the exc_info, and pack them into an exception that we can
185 # throw up to the outer loop. We peel one layer off the traceback
186 # so that the coverage.py code doesn't appear in the final printed
187 # traceback.
188 typ, err, tb = sys.exc_info()
189
190 # PyPy3 weirdness. If I don't access __context__, then somehow it
191 # is non-None when the exception is reported at the upper layer,
192 # and a nested exception is shown to the user. This getattr fixes
193 # it somehow? https://bitbucket.org/pypy/pypy/issue/1903
194 getattr(err, '__context__', None)
195
196 raise ExceptionDuringRun(typ, err, tb.tb_next)
197 finally:
198 # Restore the old __main__, argv, and path.
199 sys.modules['__main__'] = old_main_mod
200 sys.argv = old_argv
201 sys.path[0] = old_path0
202
203
204 def make_code_from_py(filename):
205 """Get source from `filename` and make a code object of it."""
206 # Open the source file.
207 try:
208 source = get_python_source(filename)
209 except (IOError, NoSource):
210 raise NoSource("No file to run: '%s'" % filename)
211
212 code = compile_unicode(source, filename, "exec")
213 return code
214
215
216 def make_code_from_pyc(filename):
217 """Get a code object from a .pyc file."""
218 try:
219 fpyc = open(filename, "rb")
220 except IOError:
221 raise NoCode("No file to run: '%s'" % filename)
222
223 with fpyc:
224 # First four bytes are a version-specific magic number. It has to
225 # match or we won't run the file.
226 magic = fpyc.read(4)
227 if magic != PYC_MAGIC_NUMBER:
228 raise NoCode("Bad magic number in .pyc file")
229
230 # Skip the junk in the header that we don't need.
231 fpyc.read(4) # Skip the moddate.
232 if sys.version_info >= (3, 3):
233 # 3.3 added another long to the header (size), skip it.
234 fpyc.read(4)
235
236 # The rest of the file is the code object we want.
237 code = marshal.load(fpyc)
238
239 return code

eric ide

mercurial