3 |
3 |
4 """Execute files of Python code.""" |
4 """Execute files of Python code.""" |
5 |
5 |
6 import marshal |
6 import marshal |
7 import os |
7 import os |
|
8 import struct |
8 import sys |
9 import sys |
9 import types |
10 import types |
10 |
11 |
11 from coverage.backward import BUILTINS |
12 from coverage.backward import BUILTINS |
12 from coverage.backward import PYC_MAGIC_NUMBER, imp, importlib_util_find_spec |
13 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.misc import CoverageException, ExceptionDuringRun, NoCode, NoSource, isolate_module |
14 from coverage.phystokens import compile_unicode |
15 from coverage.phystokens import compile_unicode |
15 from coverage.python import get_python_source |
16 from coverage.python import get_python_source |
16 |
17 |
17 os = isolate_module(os) |
18 os = isolate_module(os) |
18 |
19 |
164 # Set sys.path correctly. |
165 # Set sys.path correctly. |
165 old_path0 = sys.path[0] |
166 old_path0 = sys.path[0] |
166 sys.path[0] = path0 if path0 is not None else my_path0 |
167 sys.path[0] = path0 if path0 is not None else my_path0 |
167 |
168 |
168 try: |
169 try: |
169 # Make a code object somehow. |
170 try: |
170 if filename.endswith((".pyc", ".pyo")): |
171 # Make a code object somehow. |
171 code = make_code_from_pyc(filename) |
172 if filename.endswith((".pyc", ".pyo")): |
172 else: |
173 code = make_code_from_pyc(filename) |
173 code = make_code_from_py(filename) |
174 else: |
|
175 code = make_code_from_py(filename) |
|
176 except CoverageException: |
|
177 raise |
|
178 except Exception as exc: |
|
179 msg = "Couldn't run {filename!r} as Python code: {exc.__class__.__name__}: {exc}" |
|
180 raise CoverageException(msg.format(filename=filename, exc=exc)) |
174 |
181 |
175 # Execute the code object. |
182 # Execute the code object. |
176 try: |
183 try: |
177 exec(code, main_mod.__dict__) |
184 exec(code, main_mod.__dict__) |
178 except SystemExit: |
185 except SystemExit: |
179 # The user called sys.exit(). Just pass it along to the upper |
186 # The user called sys.exit(). Just pass it along to the upper |
180 # layers, where it will be handled. |
187 # layers, where it will be handled. |
181 raise |
188 raise |
182 except: |
189 except Exception: |
183 # Something went wrong while executing the user code. |
190 # Something went wrong while executing the user code. |
184 # Get the exc_info, and pack them into an exception that we can |
191 # 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 |
192 # 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 |
193 # so that the coverage.py code doesn't appear in the final printed |
187 # traceback. |
194 # traceback. |
191 # is non-None when the exception is reported at the upper layer, |
198 # 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 |
199 # and a nested exception is shown to the user. This getattr fixes |
193 # it somehow? https://bitbucket.org/pypy/pypy/issue/1903 |
200 # it somehow? https://bitbucket.org/pypy/pypy/issue/1903 |
194 getattr(err, '__context__', None) |
201 getattr(err, '__context__', None) |
195 |
202 |
196 raise ExceptionDuringRun(typ, err, tb.tb_next) |
203 # Call the excepthook. |
|
204 try: |
|
205 if hasattr(err, "__traceback__"): |
|
206 err.__traceback__ = err.__traceback__.tb_next |
|
207 sys.excepthook(typ, err, tb.tb_next) |
|
208 except SystemExit: |
|
209 raise |
|
210 except Exception: |
|
211 # Getting the output right in the case of excepthook |
|
212 # shenanigans is kind of involved. |
|
213 sys.stderr.write("Error in sys.excepthook:\n") |
|
214 typ2, err2, tb2 = sys.exc_info() |
|
215 err2.__suppress_context__ = True |
|
216 if hasattr(err2, "__traceback__"): |
|
217 err2.__traceback__ = err2.__traceback__.tb_next |
|
218 sys.__excepthook__(typ2, err2, tb2.tb_next) |
|
219 sys.stderr.write("\nOriginal exception was:\n") |
|
220 raise ExceptionDuringRun(typ, err, tb.tb_next) |
|
221 else: |
|
222 sys.exit(1) |
|
223 |
197 finally: |
224 finally: |
198 # Restore the old __main__, argv, and path. |
225 # Restore the old __main__, argv, and path. |
199 sys.modules['__main__'] = old_main_mod |
226 sys.modules['__main__'] = old_main_mod |
200 sys.argv = old_argv |
227 sys.argv = old_argv |
201 sys.path[0] = old_path0 |
228 sys.path[0] = old_path0 |
225 # match or we won't run the file. |
252 # match or we won't run the file. |
226 magic = fpyc.read(4) |
253 magic = fpyc.read(4) |
227 if magic != PYC_MAGIC_NUMBER: |
254 if magic != PYC_MAGIC_NUMBER: |
228 raise NoCode("Bad magic number in .pyc file") |
255 raise NoCode("Bad magic number in .pyc file") |
229 |
256 |
230 # Skip the junk in the header that we don't need. |
257 date_based = True |
231 fpyc.read(4) # Skip the moddate. |
258 if sys.version_info >= (3, 7, 0, 'alpha', 4): |
232 if sys.version_info >= (3, 3): |
259 flags = struct.unpack('<L', fpyc.read(4))[0] |
233 # 3.3 added another long to the header (size), skip it. |
260 hash_based = flags & 0x01 |
234 fpyc.read(4) |
261 if hash_based: |
|
262 fpyc.read(8) # Skip the hash. |
|
263 date_based = False |
|
264 if date_based: |
|
265 # Skip the junk in the header that we don't need. |
|
266 fpyc.read(4) # Skip the moddate. |
|
267 if sys.version_info >= (3, 3): |
|
268 # 3.3 added another long to the header (size), skip it. |
|
269 fpyc.read(4) |
235 |
270 |
236 # The rest of the file is the code object we want. |
271 # The rest of the file is the code object we want. |
237 code = marshal.load(fpyc) |
272 code = marshal.load(fpyc) |
238 |
273 |
239 return code |
274 return code |