|
7 | 7 | import contextlib |
8 | 8 | import shutil |
9 | 9 | import sys |
10 | | -from typing import Iterator, Optional |
| 10 | +from typing import Any, Iterator, Optional, List, cast |
11 | 11 |
|
12 | 12 | from mypy import build |
13 | 13 | from mypy.test.data import DataDrivenTestCase |
|
24 | 24 | show_c |
25 | 25 | ) |
26 | 26 |
|
27 | | -from distutils.core import run_setup |
28 | | - |
29 | 27 | files = [ |
30 | 28 | 'run-functions.test', |
31 | 29 | 'run.test', |
|
46 | 44 | """ |
47 | 45 |
|
48 | 46 |
|
| 47 | +def run_setup(script_name: str, script_args: List[str]) -> bool: |
| 48 | + """Run a setup script in a somewhat controlled environment. |
| 49 | +
|
| 50 | + This is adapted from code in distutils and our goal here is that is |
| 51 | + faster to not need to spin up a python interpreter to run it. |
| 52 | +
|
| 53 | + We had to fork it because the real run_setup swallows errors |
| 54 | + and KeyboardInterrupt with no way to recover them (!). |
| 55 | + The real version has some extra features that we removed since |
| 56 | + we weren't using them. |
| 57 | +
|
| 58 | + Returns whether the setup succeeded. |
| 59 | + """ |
| 60 | + save_argv = sys.argv.copy() |
| 61 | + g = {'__file__': script_name} |
| 62 | + try: |
| 63 | + try: |
| 64 | + sys.argv[0] = script_name |
| 65 | + sys.argv[1:] = script_args |
| 66 | + with open(script_name, 'rb') as f: |
| 67 | + exec(f.read(), g) |
| 68 | + finally: |
| 69 | + sys.argv = save_argv |
| 70 | + except SystemExit as e: |
| 71 | + # typeshed reports code as being an int but that is wrong |
| 72 | + code = cast(Any, e).code |
| 73 | + # distutils converts KeyboardInterrupt into a SystemExit with |
| 74 | + # "interrupted" as the argument. Convert it back so that |
| 75 | + # pytest will exit instead of just failing the test. |
| 76 | + if code == "interrupted": |
| 77 | + raise KeyboardInterrupt |
| 78 | + |
| 79 | + return code == 0 or code is None |
| 80 | + |
| 81 | + return True |
| 82 | + |
| 83 | + |
49 | 84 | @contextlib.contextmanager |
50 | 85 | def chdir_manager(target: str) -> Iterator[None]: |
51 | 86 | dir = os.getcwd() |
@@ -150,15 +185,15 @@ def run_case(self, testcase: DataDrivenTestCase) -> None: |
150 | 185 | with open(setup_file, 'w') as f: |
151 | 186 | f.write(setup_format.format(module_paths)) |
152 | 187 |
|
153 | | - run_setup(setup_file, ['build_ext', '--inplace']) |
154 | | - # Oh argh run_setup doesn't propagate failure. For now we'll just assert |
155 | | - # that the file is there. |
156 | | - suffix = 'pyd' if sys.platform == 'win32' else 'so' |
157 | | - if not glob.glob('native.*.{}'.format(suffix)): |
| 188 | + if not run_setup(setup_file, ['build_ext', '--inplace']): |
158 | 189 | if testcase.config.getoption('--mypyc-showc'): |
159 | 190 | show_c(cfiles) |
160 | 191 | assert False, "Compilation failed" |
161 | 192 |
|
| 193 | + # Assert that an output file got created |
| 194 | + suffix = 'pyd' if sys.platform == 'win32' else 'so' |
| 195 | + assert glob.glob('native.*.{}'.format(suffix)) |
| 196 | + |
162 | 197 | for p in to_delete: |
163 | 198 | os.remove(p) |
164 | 199 |
|
|
0 commit comments