|
21 | 21 | import signal |
22 | 22 | import subprocess |
23 | 23 | import sys |
24 | | -from concurrent.futures import ProcessPoolExecutor |
25 | | -from concurrent.futures import as_completed |
| 24 | +from multiprocessing.pool import Pool |
26 | 25 | from pathlib import Path |
27 | 26 |
|
28 | 27 | from dotenv import dotenv_values |
@@ -245,42 +244,58 @@ def main(junit_xml: str | None, |
245 | 244 |
|
246 | 245 | failures = 0 |
247 | 246 |
|
248 | | - with ProcessPoolExecutor(max_workers=jobs) as executor: |
249 | | - ex = executor |
| 247 | + orig_handler = signal.getsignal(signal.SIGINT) |
250 | 248 |
|
251 | | - def shutdown_executor(_signum, _frame, wait: bool = False): |
| 249 | + def _restore_handler(): |
| 250 | + if orig_handler is not None: |
| 251 | + signal.signal(signal.SIGINT, orig_handler) |
| 252 | + |
| 253 | + with Pool(processes=jobs) as pool: |
| 254 | + ex = pool |
| 255 | + |
| 256 | + def shutdown_pool(_signum, _frame): |
252 | 257 | nonlocal ex |
| 258 | + |
| 259 | + shutdown_msg = "Exiting" |
253 | 260 | if ex is not None: |
254 | | - print("Shutting down executor...") |
255 | | - ex.shutdown(wait=wait, cancel_futures=True) |
| 261 | + print("Shutting down pool...") |
| 262 | + ex.terminate() |
| 263 | + ex.join() |
| 264 | + if _signum is not None: |
| 265 | + shutdown_msg = f"Received signal {_signum}, exiting" |
| 266 | + |
256 | 267 | else: |
257 | | - print("Executor not found") |
| 268 | + print("Pool not found") |
| 269 | + |
| 270 | + _restore_handler() |
| 271 | + raise SystemExit(shutdown_msg) |
258 | 272 |
|
259 | | - signal.signal(signal.SIGINT, shutdown_executor) |
| 273 | + signal.signal(signal.SIGINT, shutdown_pool) |
260 | 274 | futs = [ |
261 | | - ex.submit(run_one, |
262 | | - p, |
263 | | - enable_coverage=cov_xml is not None, |
264 | | - enable_junit=junit_xml is not None, |
265 | | - run_slow=run_slow, |
266 | | - run_integration=run_integration, |
267 | | - exitfirst=exitfirst, |
268 | | - is_verbose=has_verbose_flag, |
269 | | - extra_flags=extra_flags, |
270 | | - no_tests=no_tests) for p in projects |
| 275 | + pool.apply_async(run_one, |
| 276 | + args=(p, ), |
| 277 | + kwds=dict(enable_coverage=cov_xml is not None, |
| 278 | + enable_junit=junit_xml is not None, |
| 279 | + run_slow=run_slow, |
| 280 | + run_integration=run_integration, |
| 281 | + exitfirst=exitfirst, |
| 282 | + is_verbose=has_verbose_flag, |
| 283 | + extra_flags=extra_flags, |
| 284 | + no_tests=no_tests)) for p in projects |
271 | 285 | ] |
272 | 286 | try: |
273 | | - for fut in as_completed(futs): |
274 | | - if fut.result() != 0: |
| 287 | + for fut in futs: |
| 288 | + if fut.get() != 0: |
275 | 289 | failures += 1 |
276 | 290 | if exitfirst: |
277 | 291 | raise TestFailure("Exiting on first failure as requested.") |
278 | 292 |
|
279 | 293 | except TestFailure: |
280 | 294 | print("Cancelling remaining tests...") |
281 | | - shutdown_executor(None, None, wait=True) |
| 295 | + shutdown_pool(None, None) |
282 | 296 | finally: |
283 | 297 | ex = None |
| 298 | + _restore_handler() |
284 | 299 | for p in projects: |
285 | 300 | sh(["rm", "-rf", str(p / ".venv")]) |
286 | 301 |
|
|
0 commit comments