Coverage for coverage / execfile.py: 98.655%
181 statements
« prev ^ index » next coverage.py v7.12.1a0.dev1, created at 2025-11-30 17:57 +0000
« prev ^ index » next coverage.py v7.12.1a0.dev1, created at 2025-11-30 17:57 +0000
1# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2# For details: https://github.com/coveragepy/coveragepy/blob/main/NOTICE.txt
4"""Execute files of Python code."""
6from __future__ import annotations 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
8import importlib.machinery 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
9import importlib.util 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
10import inspect 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
11import marshal 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
12import os 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
13import struct 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
14import sys 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
15from importlib.machinery import ModuleSpec 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
16from types import CodeType, ModuleType 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
17from typing import Any 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
19from coverage.exceptions import CoverageException, NoCode, NoSource, _ExceptionDuringRun 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
20from coverage.files import canonical_filename, python_reported_file 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
21from coverage.misc import isolate_module 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
22from coverage.python import get_python_source 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
24os = isolate_module(os) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
27PYC_MAGIC_NUMBER = importlib.util.MAGIC_NUMBER 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
30class DummyLoader: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
31 """A shim for the pep302 __loader__, emulating pkgutil.ImpLoader.
33 Currently only implements the .fullname attribute
34 """
36 def __init__(self, fullname: str, *_args: Any) -> None: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
37 self.fullname = fullname 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
40def find_module( 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
41 modulename: str,
42) -> tuple[str | None, str, ModuleSpec]:
43 """Find the module named `modulename`.
45 Returns the file path of the module, the name of the enclosing
46 package, and the spec.
47 """
48 try: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
49 spec = importlib.util.find_spec(modulename) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
50 except ImportError as err: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
51 raise NoSource(str(err)) from err 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
52 if not spec: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
53 raise NoSource(f"No module named {modulename!r}") 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
54 pathname = spec.origin 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
55 packagename = spec.name 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
56 if spec.submodule_search_locations: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
57 mod_main = modulename + ".__main__" 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
58 spec = importlib.util.find_spec(mod_main) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
59 if not spec: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
60 raise NoSource( 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
61 f"No module named {mod_main}; "
62 + f"{modulename!r} is a package and cannot be directly executed",
63 )
64 pathname = spec.origin 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
65 packagename = spec.name 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
66 packagename = packagename.rpartition(".")[0] 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
67 return pathname, packagename, spec 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
70class PyRunner: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
71 """Multi-stage execution of Python code.
73 This is meant to emulate real Python execution as closely as possible.
75 """
77 def __init__(self, args: list[str], as_module: bool = False) -> None: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
78 self.args = args 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
79 self.as_module = as_module 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
81 self.arg0 = args[0] 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
82 self.package: str | None = None 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
83 self.modulename: str | None = None 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
84 self.pathname: str | None = None 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
85 self.loader: DummyLoader | None = None 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
86 self.spec: ModuleSpec | None = None 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
88 def prepare(self) -> None: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
89 """Set sys.path properly.
91 This needs to happen before any importing, and without importing anything.
92 """
93 path0: str | None
94 if getattr(sys.flags, "safe_path", False): 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
95 # See https://docs.python.org/3/using/cmdline.html#cmdoption-P
96 path0 = None 1abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
97 elif self.as_module: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
98 path0 = os.getcwd() 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
99 elif os.path.isdir(self.arg0): 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
100 # Running a directory means running the __main__.py file in that
101 # directory.
102 path0 = self.arg0 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
103 else:
104 path0 = os.path.abspath(os.path.dirname(self.arg0)) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
106 if os.path.isdir(sys.path[0]): 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
107 # sys.path fakery. If we are being run as a command, then sys.path[0]
108 # is the directory of the "coverage" script. If this is so, replace
109 # sys.path[0] with the directory of the file we're running, or the
110 # current directory when running modules. If it isn't so, then we
111 # don't know what's going on, and just leave it alone.
112 top_file = inspect.stack()[-1][0].f_code.co_filename 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
113 sys_path_0_abs = os.path.abspath(sys.path[0]) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
114 top_file_dir_abs = os.path.abspath(os.path.dirname(top_file)) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
115 sys_path_0_abs = canonical_filename(sys_path_0_abs) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
116 top_file_dir_abs = canonical_filename(top_file_dir_abs) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
117 if sys_path_0_abs != top_file_dir_abs: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
118 path0 = None 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
120 else:
121 # sys.path[0] is a file. Is the next entry the directory containing
122 # that file?
123 if sys.path[1] == os.path.dirname(sys.path[0]): 123 ↛ 125line 123 didn't jump to line 125 because the condition on line 123 was never true1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
124 # Can it be right to always remove that?
125 del sys.path[1]
127 if path0 is not None: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
128 sys.path[0] = python_reported_file(path0) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
130 def _prepare2(self) -> None: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
131 """Do more preparation to run Python code.
133 Includes finding the module to run and adjusting sys.argv[0].
134 This method is allowed to import code.
136 """
137 if self.as_module: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
138 self.modulename = self.arg0 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
139 pathname, self.package, self.spec = find_module(self.modulename) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
140 if self.spec is not None: 140 ↛ 142line 140 didn't jump to line 142 because the condition on line 140 was always true1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
141 self.modulename = self.spec.name 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
142 self.loader = DummyLoader(self.modulename) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
143 assert pathname is not None 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
144 self.pathname = os.path.abspath(pathname) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
145 self.args[0] = self.arg0 = self.pathname 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
146 elif os.path.isdir(self.arg0): 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
147 # Running a directory means running the __main__.py file in that
148 # directory.
149 for ext in [".py", ".pyc", ".pyo"]: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
150 try_filename = os.path.join(self.arg0, f"__main__{ext}") 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
151 # 3.8.10 changed how files are reported when running a
152 # directory.
153 try_filename = os.path.abspath(try_filename) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
154 if os.path.exists(try_filename): 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
155 self.arg0 = try_filename 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
156 break 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
157 else:
158 raise NoSource(f"Can't find '__main__' module in '{self.arg0}'") 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
160 # Make a spec. I don't know if this is the right way to do it.
161 try_filename = python_reported_file(try_filename) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
162 self.spec = importlib.machinery.ModuleSpec("__main__", None, origin=try_filename) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
163 self.spec.has_location = True 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
164 self.package = "" 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
165 self.loader = DummyLoader("__main__") 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
166 else:
167 self.loader = DummyLoader("__main__") 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
169 self.arg0 = python_reported_file(self.arg0) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
171 def run(self) -> None: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
172 """Run the Python code!"""
174 self._prepare2() 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
176 # Create a module to serve as __main__
177 main_mod = ModuleType("__main__") 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
179 from_pyc = self.arg0.endswith((".pyc", ".pyo")) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
180 main_mod.__file__ = self.arg0 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
181 if from_pyc: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
182 main_mod.__file__ = main_mod.__file__[:-1] 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
183 if self.package is not None: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
184 main_mod.__package__ = self.package 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
185 main_mod.__loader__ = self.loader # type: ignore[assignment] 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
186 if self.spec is not None: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
187 main_mod.__spec__ = self.spec 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
189 main_mod.__builtins__ = sys.modules["builtins"] # type: ignore[attr-defined] 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
191 sys.modules["__main__"] = main_mod 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
193 # Set sys.argv properly.
194 sys.argv = self.args 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
196 try: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
197 # Make a code object somehow.
198 if from_pyc: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
199 code = make_code_from_pyc(self.arg0) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
200 else:
201 code = make_code_from_py(self.arg0) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
202 except CoverageException: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
203 raise 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
204 except Exception as exc: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
205 msg = f"Couldn't run '{self.arg0}' as Python code: {exc.__class__.__name__}: {exc}" 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
206 raise CoverageException(msg) from exc 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
208 # Execute the code object.
209 # Return to the original directory in case the test code exits in
210 # a non-existent directory.
211 cwd = os.getcwd() 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
212 try: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
213 exec(code, main_mod.__dict__) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
214 except SystemExit: # pylint: disable=try-except-raise 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
215 # The user called sys.exit(). Just pass it along to the upper
216 # layers, where it will be handled.
217 raise 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
218 except Exception: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
219 # Something went wrong while executing the user code.
220 # Get the exc_info, and pack them into an exception that we can
221 # throw up to the outer loop. We peel one layer off the traceback
222 # so that the coverage.py code doesn't appear in the final printed
223 # traceback.
224 typ, err, tb = sys.exc_info() 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
225 assert typ is not None 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
226 assert err is not None 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
227 assert tb is not None 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
229 # PyPy3 weirdness. If I don't access __context__, then somehow it
230 # is non-None when the exception is reported at the upper layer,
231 # and a nested exception is shown to the user. This getattr fixes
232 # it somehow? https://bitbucket.org/pypy/pypy/issue/1903
233 getattr(err, "__context__", None) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
235 # Call the excepthook.
236 try: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
237 assert err.__traceback__ is not None 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
238 err.__traceback__ = err.__traceback__.tb_next 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
239 sys.excepthook(typ, err, tb.tb_next) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
240 except SystemExit: # pylint: disable=try-except-raise 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
241 raise 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
242 except Exception as exc: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
243 # Getting the output right in the case of excepthook
244 # shenanigans is kind of involved.
245 sys.stderr.write("Error in sys.excepthook:\n") 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
246 typ2, err2, tb2 = sys.exc_info() 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
247 assert typ2 is not None 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
248 assert err2 is not None 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
249 assert tb2 is not None 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
250 err2.__suppress_context__ = True 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
251 assert err2.__traceback__ is not None 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
252 err2.__traceback__ = err2.__traceback__.tb_next 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
253 sys.__excepthook__(typ2, err2, tb2.tb_next) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
254 sys.stderr.write("\nOriginal exception was:\n") 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
255 raise _ExceptionDuringRun(typ, err, tb.tb_next) from exc 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
256 else:
257 sys.exit(1) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
258 finally:
259 os.chdir(cwd) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
262def run_python_module(args: list[str]) -> None: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
263 """Run a Python module, as though with ``python -m name args...``.
265 `args` is the argument array to present as sys.argv, including the first
266 element naming the module being executed.
268 This is a helper for tests, to encapsulate how to use PyRunner.
270 """
271 runner = PyRunner(args, as_module=True) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
272 runner.prepare() 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
273 runner.run() 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
276def run_python_file(args: list[str]) -> None: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
277 """Run a Python file as if it were the main program on the command line.
279 `args` is the argument array to present as sys.argv, including the first
280 element naming the file being executed. `package` is the name of the
281 enclosing package, if any.
283 This is a helper for tests, to encapsulate how to use PyRunner.
285 """
286 runner = PyRunner(args, as_module=False) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
287 runner.prepare() 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
288 runner.run() 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
291def make_code_from_py(filename: str) -> CodeType: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
292 """Get source from `filename` and make a code object of it."""
293 try: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
294 source = get_python_source(filename) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
295 except (OSError, NoSource) as exc: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
296 raise NoSource(f"No file to run: '{filename}'") from exc 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
298 code = compile(source, filename, mode="exec", dont_inherit=True) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
299 return code 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
302def make_code_from_pyc(filename: str) -> CodeType: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
303 """Get a code object from a .pyc file."""
304 try: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
305 fpyc = open(filename, "rb") 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
306 except OSError as exc: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
307 raise NoCode(f"No file to run: '{filename}'") from exc 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
309 with fpyc: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
310 # First four bytes are a version-specific magic number. It has to
311 # match or we won't run the file.
312 magic = fpyc.read(4) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
313 if magic != PYC_MAGIC_NUMBER: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
314 raise NoCode(f"Bad magic number in .pyc file: {magic!r} != {PYC_MAGIC_NUMBER!r}") 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
316 flags = struct.unpack("<L", fpyc.read(4))[0] 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
317 hash_based = flags & 0x01 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
318 if hash_based: 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
319 fpyc.read(8) # Skip the hash. 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
320 else:
321 # Skip the junk in the header that we don't need.
322 fpyc.read(4) # Skip the moddate. 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
323 fpyc.read(4) # Skip the size. 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
325 # The rest of the file is the code object we want.
326 code = marshal.load(fpyc) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
327 assert isinstance(code, CodeType) 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89
329 return code 1!#$%'(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567)89