1313import sys
1414import tempfile
1515import threading
16- from collections .abc import Callable
17- from contextlib import ExitStack , suppress
16+ from collections .abc import Callable , Iterator
17+ from contextlib import ExitStack , contextmanager , suppress
1818from dataclasses import dataclass
1919from enum import IntEnum
2020from functools import partial
@@ -145,8 +145,12 @@ def setup_testcase_dir(package: DistributionTests, tempdir: Path, verbosity: Ver
145145 if requirements .external_pkgs :
146146 venv_location = str (tempdir / VENV_DIR )
147147 subprocess .run (["uv" , "venv" , venv_location ], check = True , capture_output = True )
148- # Use --no-cache-dir to avoid issues with concurrent read/writes to the cache
149- uv_command = ["uv" , "pip" , "install" , get_mypy_req (), * requirements .external_pkgs , "--no-cache-dir" ]
148+ uv_command = ["uv" , "pip" , "install" , get_mypy_req (), * requirements .external_pkgs ]
149+ if sys .platform == "win32" :
150+ # Reads/writes to the cache are threadsafe with uv generally...
151+ # but not on old Windows versions
152+ # https://github.com/astral-sh/uv/issues/2810
153+ uv_command .append ("--no-cache-dir" )
150154 if verbosity is Verbosity .VERBOSE :
151155 verbose_log (f"{ package .name } : Setting up venv in { venv_location } . { uv_command = } \n " )
152156 try :
@@ -309,6 +313,19 @@ def concurrently_run_testcases(
309313 if not to_do :
310314 return []
311315
316+ @contextmanager
317+ def cleanup_threads (
318+ event : threading .Event , printer_thread : threading .Thread , executor : concurrent .futures .ThreadPoolExecutor
319+ ) -> Iterator [None ]:
320+ try :
321+ yield
322+ except :
323+ _PRINT_QUEUE .put ("Shutting down worker threads..." )
324+ event .set ()
325+ printer_thread .join ()
326+ executor .shutdown (cancel_futures = True )
327+ raise
328+
312329 event = threading .Event ()
313330 printer_thread = threading .Thread (target = print_queued_messages , args = (event ,))
314331 printer_thread .start ()
@@ -321,10 +338,14 @@ def concurrently_run_testcases(
321338 executor .submit (setup_testcase_dir , package , tempdir , verbosity )
322339 for package , tempdir in packageinfo_to_tempdir .items ()
323340 ]
324- concurrent .futures .wait (testcase_futures )
341+
342+ with cleanup_threads (event , printer_thread , executor ):
343+ concurrent .futures .wait (testcase_futures )
325344
326345 mypy_futures = [executor .submit (task ) for task in to_do ]
327- results = [future .result () for future in mypy_futures ]
346+
347+ with cleanup_threads (event , printer_thread , executor ):
348+ results = [future .result () for future in mypy_futures ]
328349
329350 event .set ()
330351 printer_thread .join ()
0 commit comments