1616
1717from pathlib import Path
1818from platform import python_implementation
19- from typing import TYPE_CHECKING , Any , cast
19+ from typing import TYPE_CHECKING , Any , Literal , Optional , Type , cast
2020
2121from tox .execute .local_sub_process import LocalSubProcessExecutor
2222from tox .execute .request import StdinSource
2323from tox .tox_env .errors import Skip
2424from tox .tox_env .python .api import Python , PythonInfo , VersionInfo
25+
26+ if sys .version_info >= (3 , 10 ): # pragma: no cover (py310+)
27+ from typing import TypeAlias
28+ else : # pragma: no cover (<py310)
29+ from typing_extensions import TypeAlias
30+
2531from uv import find_uv_bin
2632from virtualenv import app_data
2733from virtualenv .discovery import cached_py_info
3541 from tox .tox_env .installer import Installer
3642
3743
44+ PythonPreference : TypeAlias = Literal ["only-managed" , "installed" , "managed" , "system" , "only-system" ]
45+
46+
3847class UvVenv (Python , ABC ):
3948 def __init__ (self , create_args : ToxEnvCreateArgs ) -> None :
4049 self ._executor : Execute | None = None
@@ -44,12 +53,31 @@ def __init__(self, create_args: ToxEnvCreateArgs) -> None:
4453
4554 def register_config (self ) -> None :
4655 super ().register_config ()
47- desc = "add seed packages to the created venv"
48- self .conf .add_config (keys = ["uv_seed" ], of_type = bool , default = False , desc = desc )
56+ self .conf .add_config (
57+ keys = ["uv_seed" ],
58+ of_type = bool ,
59+ default = False ,
60+ desc = "add seed packages to the created venv" ,
61+ )
62+ # The cast(...) might seems superfluous but removing it
63+ # makes mypy crash. The problem is probably on tox's typing side
64+ self .conf .add_config (
65+ keys = ["uv_python_preference" ],
66+ of_type = cast (Type [Optional [PythonPreference ]], Optional [PythonPreference ]),
67+ default = None ,
68+ desc = (
69+ "Whether to prefer using Python installations that are already"
70+ " present on the system, or those that are downloaded and"
71+ " installed by uv [possible values: only-managed, installed,"
72+ " managed, system, only-system]. Use none to use uv's"
73+ " default."
74+ ),
75+ )
4976
5077 def python_cache (self ) -> dict [str , Any ]:
5178 result = super ().python_cache ()
5279 result ["seed" ] = self .conf ["uv_seed" ]
80+ result ["python_preference" ] = self .conf ["uv_python_preference" ]
5381 result ["venv" ] = str (self .venv_dir .relative_to (self .env_dir ))
5482 return result
5583
@@ -158,6 +186,8 @@ def create_python_env(self) -> None:
158186 cmd .append ("-v" )
159187 if self .conf ["uv_seed" ]:
160188 cmd .append ("--seed" )
189+ if self .conf ["uv_python_preference" ]:
190+ cmd .extend (["--python-preference" , self .conf ["uv_python_preference" ]])
161191 cmd .append (str (self .venv_dir ))
162192 outcome = self .execute (cmd , stdin = StdinSource .OFF , run_id = "venv" , show = None )
163193
0 commit comments