3030from utils import (
3131 PYTHON_VERSION ,
3232 VERSIONS_RE as VERSION_LINE_RE ,
33- VenvInfo ,
3433 colored ,
3534 get_gitignore_spec ,
3635 get_mypy_req ,
37- make_venv ,
3836 print_error ,
3937 print_success_msg ,
4038 spec_matches_path ,
4139 strip_comments ,
40+ venv_python ,
4241)
4342
4443# Fail early if mypy isn't installed
@@ -235,7 +234,7 @@ def run_mypy(
235234 * ,
236235 testing_stdlib : bool ,
237236 non_types_dependencies : bool ,
238- venv_info : VenvInfo ,
237+ venv_dir : Path | None ,
239238 mypypath : str | None = None ,
240239) -> MypyResult :
241240 env_vars = dict (os .environ )
@@ -279,7 +278,8 @@ def run_mypy(
279278 flags .append ("--no-site-packages" )
280279
281280 mypy_args = [* flags , * map (str , files )]
282- mypy_command = [venv_info .python_exe , "-m" , "mypy" , * mypy_args ]
281+ python_path = sys .executable if venv_dir is None else str (venv_python (venv_dir ))
282+ mypy_command = [python_path , "-m" , "mypy" , * mypy_args ]
283283 if args .verbose :
284284 print (colored (f"running { ' ' .join (mypy_command )} " , "blue" ))
285285 result = subprocess .run (mypy_command , capture_output = True , text = True , env = env_vars )
@@ -291,7 +291,7 @@ def run_mypy(
291291 print_error (result .stderr )
292292 if non_types_dependencies and args .verbose :
293293 print ("Ran with the following environment:" )
294- subprocess .run ([venv_info . pip_exe , "freeze " , "--all" ] )
294+ subprocess .run (["uv" , "pip " , "freeze" ], env = { ** os . environ , "VIRTUAL_ENV" : str ( venv_dir )} )
295295 print ()
296296 else :
297297 print_success_msg ()
@@ -324,7 +324,7 @@ class TestResult(NamedTuple):
324324
325325
326326def test_third_party_distribution (
327- distribution : str , args : TestConfig , venv_info : VenvInfo , * , non_types_dependencies : bool
327+ distribution : str , args : TestConfig , venv_dir : Path | None , * , non_types_dependencies : bool
328328) -> TestResult :
329329 """Test the stubs of a third-party distribution.
330330
@@ -353,7 +353,7 @@ def test_third_party_distribution(
353353 args ,
354354 configurations ,
355355 files ,
356- venv_info = venv_info ,
356+ venv_dir = venv_dir ,
357357 mypypath = mypypath ,
358358 testing_stdlib = False ,
359359 non_types_dependencies = non_types_dependencies ,
@@ -377,9 +377,8 @@ def test_stdlib(args: TestConfig) -> TestResult:
377377 return TestResult (MypyResult .SUCCESS , 0 )
378378
379379 print (f"Testing stdlib ({ len (files )} files)... " , end = "" , flush = True )
380- # We don't actually need pip for the stdlib testing
381- venv_info = VenvInfo (pip_exe = "" , python_exe = sys .executable )
382- result = run_mypy (args , [], files , venv_info = venv_info , testing_stdlib = True , non_types_dependencies = False )
380+ # We don't actually need to install anything for the stdlib testing
381+ result = run_mypy (args , [], files , venv_dir = None , testing_stdlib = True , non_types_dependencies = False )
383382 return TestResult (result , len (files ))
384383
385384
@@ -409,22 +408,30 @@ def merge(self, other: TestSummary) -> None:
409408
410409
411410_PRINT_LOCK = Lock ()
412- _DISTRIBUTION_TO_VENV_MAPPING : dict [str , VenvInfo ] = {}
411+ _DISTRIBUTION_TO_VENV_MAPPING : dict [str , Path | None ] = {}
413412
414413
415- def setup_venv_for_external_requirements_set (requirements_set : frozenset [str ], tempdir : Path ) -> tuple [frozenset [str ], VenvInfo ]:
414+ def setup_venv_for_external_requirements_set (
415+ requirements_set : frozenset [str ], tempdir : Path , args : TestConfig
416+ ) -> tuple [frozenset [str ], Path ]:
416417 venv_dir = tempdir / f".venv-{ hash (requirements_set )} "
417- return requirements_set , make_venv (venv_dir )
418+ uv_command = ["uv" , "venv" , str (venv_dir )]
419+ if not args .verbose :
420+ uv_command .append ("--quiet" )
421+ subprocess .run (uv_command , check = True )
422+ return requirements_set , venv_dir
418423
419424
420- def install_requirements_for_venv (venv_info : VenvInfo , args : TestConfig , external_requirements : frozenset [str ]) -> None :
425+ def install_requirements_for_venv (venv_dir : Path , args : TestConfig , external_requirements : frozenset [str ]) -> None :
421426 # Use --no-cache-dir to avoid issues with concurrent read/writes to the cache
422- pip_command = [venv_info . pip_exe , "install" , get_mypy_req (), * sorted (external_requirements ), "--no-cache-dir" ]
427+ uv_command = ["uv" , "pip" , "install" , get_mypy_req (), * sorted (external_requirements ), "--no-cache-dir" ]
423428 if args .verbose :
424429 with _PRINT_LOCK :
425- print (colored (f"Running { pip_command } " , "blue" ))
430+ print (colored (f"Running { uv_command } " , "blue" ))
431+ else :
432+ uv_command .append ("--quiet" )
426433 try :
427- subprocess .run (pip_command , check = True , capture_output = True , text = True )
434+ subprocess .run (uv_command , check = True , text = True , env = { ** os . environ , "VIRTUAL_ENV" : str ( venv_dir )} )
428435 except subprocess .CalledProcessError as e :
429436 print (e .stderr )
430437 raise
@@ -437,9 +444,6 @@ def setup_virtual_environments(distributions: dict[str, PackageDependencies], ar
437444
438445 # STAGE 1: Determine which (if any) stubs packages require virtual environments.
439446 # Group stubs packages according to their external-requirements sets
440-
441- # We don't actually need pip if there aren't any external dependencies
442- no_external_dependencies_venv = VenvInfo (pip_exe = "" , python_exe = sys .executable )
443447 external_requirements_to_distributions : defaultdict [frozenset [str ], list [str ]] = defaultdict (list )
444448 num_pkgs_with_external_reqs = 0
445449
@@ -449,7 +453,7 @@ def setup_virtual_environments(distributions: dict[str, PackageDependencies], ar
449453 external_requirements = frozenset (requirements .external_pkgs )
450454 external_requirements_to_distributions [external_requirements ].append (distribution_name )
451455 else :
452- _DISTRIBUTION_TO_VENV_MAPPING [distribution_name ] = no_external_dependencies_venv
456+ _DISTRIBUTION_TO_VENV_MAPPING [distribution_name ] = None
453457
454458 # Exit early if there are no stubs packages that have non-types dependencies
455459 if num_pkgs_with_external_reqs == 0 :
@@ -458,7 +462,7 @@ def setup_virtual_environments(distributions: dict[str, PackageDependencies], ar
458462 return
459463
460464 # STAGE 2: Setup a virtual environment for each unique set of external requirements
461- requirements_sets_to_venvs : dict [frozenset [str ], VenvInfo ] = {}
465+ requirements_sets_to_venvs : dict [frozenset [str ], Path ] = {}
462466
463467 if args .verbose :
464468 num_venvs = len (external_requirements_to_distributions )
@@ -472,13 +476,13 @@ def setup_virtual_environments(distributions: dict[str, PackageDependencies], ar
472476 venv_start_time = time .perf_counter ()
473477
474478 with concurrent .futures .ProcessPoolExecutor () as executor :
475- venv_info_futures = [
476- executor .submit (setup_venv_for_external_requirements_set , requirements_set , tempdir )
479+ venv_futures = [
480+ executor .submit (setup_venv_for_external_requirements_set , requirements_set , tempdir , args )
477481 for requirements_set in external_requirements_to_distributions
478482 ]
479- for venv_info_future in concurrent .futures .as_completed (venv_info_futures ):
480- requirements_set , venv_info = venv_info_future .result ()
481- requirements_sets_to_venvs [requirements_set ] = venv_info
483+ for venv_future in concurrent .futures .as_completed (venv_futures ):
484+ requirements_set , venv_dir = venv_future .result ()
485+ requirements_sets_to_venvs [requirements_set ] = venv_dir
482486
483487 venv_elapsed_time = time .perf_counter () - venv_start_time
484488
@@ -492,8 +496,8 @@ def setup_virtual_environments(distributions: dict[str, PackageDependencies], ar
492496 # Limit workers to 10 at a time, since this makes network requests
493497 with concurrent .futures .ThreadPoolExecutor (max_workers = 10 ) as executor :
494498 pip_install_futures = [
495- executor .submit (install_requirements_for_venv , venv_info , args , requirements_set )
496- for requirements_set , venv_info in requirements_sets_to_venvs .items ()
499+ executor .submit (install_requirements_for_venv , venv_dir , args , requirements_set )
500+ for requirements_set , venv_dir in requirements_sets_to_venvs .items ()
497501 ]
498502 concurrent .futures .wait (pip_install_futures )
499503
@@ -561,10 +565,10 @@ def test_third_party_stubs(args: TestConfig, tempdir: Path) -> TestSummary:
561565 assert _DISTRIBUTION_TO_VENV_MAPPING .keys () >= distributions_to_check .keys ()
562566
563567 for distribution in distributions_to_check :
564- venv_info = _DISTRIBUTION_TO_VENV_MAPPING [distribution ]
565- non_types_dependencies = venv_info . python_exe != sys . executable
568+ venv_dir = _DISTRIBUTION_TO_VENV_MAPPING [distribution ]
569+ non_types_dependencies = venv_dir is not None
566570 mypy_result , files_checked = test_third_party_distribution (
567- distribution , args , venv_info = venv_info , non_types_dependencies = non_types_dependencies
571+ distribution , args , venv_dir = venv_dir , non_types_dependencies = non_types_dependencies
568572 )
569573 summary .register_result (mypy_result , files_checked )
570574
0 commit comments