@@ -9,10 +9,12 @@ local pep440 = require "mason-core.pep440"
99local platform = require " mason-core.platform"
1010local providers = require " mason-core.providers"
1111local semver = require " mason-core.semver"
12+ local settings = require " mason.settings"
1213local spawn = require " mason-core.spawn"
1314
1415local M = {}
1516
17+ local use_uv = settings .current .pip .use_uv
1618local VENV_DIR = " venv"
1719
1820function M .venv_path (dir )
@@ -30,11 +32,20 @@ local function resolve_python3(candidates)
3032 a .scheduler ()
3133 local available_candidates = _ .filter (is_executable , candidates )
3234 for __ , candidate in ipairs (available_candidates ) do
33- --- @type string
34- local version_output = spawn [candidate ]({ " --version" }):map (_ .prop " stdout" ):get_or_else " "
35- local ok , version = pcall (semver .new , version_output :match " Python (3%.%d+.%d+)" )
36- if ok then
37- return { executable = candidate , version = version }
35+ if use_uv and candidate == " uv" then
36+ --- @type string
37+ local version_output = spawn [candidate ]({ " --version" }):map (_ .prop " stdout" ):get_or_else " "
38+ local ok , version = pcall (semver .new , version_output :match " uv (%d+.%d+.%d+).*" )
39+ if ok then
40+ return { executable = candidate , version = version }
41+ end
42+ elseif not use_uv then
43+ --- @type string
44+ local version_output = spawn [candidate ]({ " --version" }):map (_ .prop " stdout" ):get_or_else " "
45+ local ok , version = pcall (semver .new , version_output :match " Python (3%.%d+.%d+)" )
46+ if ok then
47+ return { executable = candidate , version = version }
48+ end
3849 end
3950 end
4051 return nil
@@ -84,14 +95,14 @@ local function create_venv(pkg)
8495 local supported_python_versions = providers .pypi .get_supported_python_versions (pkg .name , pkg .version ):get_or_nil ()
8596
8697 -- 1. Resolve stock python3 installation.
87- local stock_candidates = platform .is .win and { " python" , " python3" } or { " python3" , " python" }
98+ local stock_candidates = platform .is .win and { " python" , " python3" , " uv " } or { " python3" , " python" , " uv " }
8899 local stock_target = resolve_python3 (stock_candidates )
89100 if stock_target then
90101 log .fmt_debug (" Resolved stock python3 installation version %s" , stock_target .version )
91102 end
92103
93104 -- 2. Resolve suitable versioned python3 installation (python3.12, python3.11, etc.).
94- local versioned_candidates = {}
105+ local versioned_candidates = { " uv " }
95106 if supported_python_versions ~= nil then
96107 if stock_target and not pep440_check_version (tostring (stock_target .version ), supported_python_versions ) then
97108 log .fmt_debug (" Finding versioned candidates for %s" , supported_python_versions )
@@ -111,7 +122,8 @@ local function create_venv(pkg)
111122 -- 3. If a versioned python3 installation was not found, warn the user if the stock python3 installation is outside
112123 -- the supported version range.
113124 if
114- target == stock_target
125+ use_uv == false
126+ and target == stock_target
115127 and supported_python_versions ~= nil
116128 and not pep440_check_version (tostring (target .version ), supported_python_versions )
117129 then
@@ -133,9 +145,14 @@ local function create_venv(pkg)
133145 end
134146 end
135147
136- log .fmt_debug (" Found python3 installation version=%s, executable=%s" , target .version , target .executable )
137148 ctx .stdio_sink :stdout " Creating virtual environment…\n "
138- return ctx .spawn [target .executable ] { " -m" , " venv" , " --system-site-packages" , VENV_DIR }
149+ if use_uv then
150+ log .fmt_debug (" Found uv installation version=%s, executable=%s" , target .version , target .executable )
151+ return ctx .spawn [target .executable ] { " venv" , VENV_DIR }
152+ else
153+ log .fmt_debug (" Found python3 installation version=%s, executable=%s" , target .version , target .executable )
154+ return ctx .spawn [target .executable ] { " -m" , " venv" , " --system-site-packages" , VENV_DIR }
155+ end
139156end
140157
141158--- @param ctx InstallContext
161178--- @param args SpawnArgs
162179local function venv_python (args )
163180 local ctx = installer .context ()
181+ if use_uv then
182+ return ctx .spawn [" uv" ](args )
183+ end
164184 return find_venv_executable (ctx , " python" ):and_then (function (python_path )
165185 return ctx .spawn [path .concat { ctx .cwd :get (), python_path }](args )
166186 end )
@@ -170,15 +190,27 @@ end
170190--- @param pkgs string[]
171191--- @param extra_args ? string[]
172192local function pip_install (pkgs , extra_args )
173- return venv_python {
174- " -m" ,
175- " pip" ,
176- " --disable-pip-version-check" ,
177- " install" ,
178- " --ignore-installed" ,
179- extra_args or vim .NIL ,
180- pkgs ,
181- }
193+ if use_uv then
194+ return venv_python {
195+ " pip" ,
196+ " install" ,
197+ " --directory" ,
198+ " venv" ,
199+ " -U" ,
200+ extra_args or vim .NIL ,
201+ pkgs ,
202+ }
203+ else
204+ return venv_python {
205+ " -m" ,
206+ " pip" ,
207+ " --disable-pip-version-check" ,
208+ " install" ,
209+ " --ignore-installed" ,
210+ extra_args or vim .NIL ,
211+ pkgs ,
212+ }
213+ end
182214end
183215
184216--- @async
@@ -192,7 +224,7 @@ function M.init(opts)
192224 ctx :promote_cwd ()
193225 try (create_venv (opts .package ))
194226
195- if opts .upgrade_pip then
227+ if opts .upgrade_pip and not use_uv then
196228 ctx .stdio_sink :stdout " Upgrading pip inside the virtual environment…\n "
197229 try (pip_install ({ " pip" }, opts .install_extra_args ))
198230 end
0 commit comments