@@ -9,11 +9,18 @@ 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
16- local VENV_DIR = " venv"
17+ local use_uv = settings .current .pip .use_uv
18+ local VENV_DIR
19+ if use_uv then
20+ VENV_DIR = " .venv"
21+ else
22+ VENV_DIR = " venv"
23+ end
1724
1825--- @async
1926--- @param candidates string[]
@@ -22,11 +29,20 @@ local function resolve_python3(candidates)
2229 a .scheduler ()
2330 local available_candidates = _ .filter (is_executable , candidates )
2431 for __ , candidate in ipairs (available_candidates ) do
25- --- @type string
26- local version_output = spawn [candidate ]({ " --version" }):map (_ .prop " stdout" ):get_or_else " "
27- local ok , version = pcall (semver .new , version_output :match " Python (3%.%d+.%d+)" )
28- if ok then
29- return { executable = candidate , version = version }
32+ if use_uv and candidate == " uv" then
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 " uv (%d+.%d+.%d+).*" )
36+ if ok then
37+ return { executable = candidate , version = version }
38+ end
39+ elseif not use_uv then
40+ --- @type string
41+ local version_output = spawn [candidate ]({ " --version" }):map (_ .prop " stdout" ):get_or_else " "
42+ local ok , version = pcall (semver .new , version_output :match " Python (3%.%d+.%d+)" )
43+ if ok then
44+ return { executable = candidate , version = version }
45+ end
3046 end
3147 end
3248 return nil
@@ -76,14 +92,14 @@ local function create_venv(pkg)
7692 local supported_python_versions = providers .pypi .get_supported_python_versions (pkg .name , pkg .version ):get_or_nil ()
7793
7894 -- 1. Resolve stock python3 installation.
79- local stock_candidates = platform .is .win and { " python" , " python3" } or { " python3" , " python" }
95+ local stock_candidates = platform .is .win and { " python" , " python3" , " uv " } or { " python3" , " python" , " uv " }
8096 local stock_target = resolve_python3 (stock_candidates )
8197 if stock_target then
8298 log .fmt_debug (" Resolved stock python3 installation version %s" , stock_target .version )
8399 end
84100
85101 -- 2. Resolve suitable versioned python3 installation (python3.12, python3.11, etc.).
86- local versioned_candidates = {}
102+ local versioned_candidates = { " uv " }
87103 if supported_python_versions ~= nil then
88104 if stock_target and not pep440_check_version (tostring (stock_target .version ), supported_python_versions ) then
89105 log .fmt_debug (" Finding versioned candidates for %s" , supported_python_versions )
@@ -103,7 +119,8 @@ local function create_venv(pkg)
103119 -- 3. If a versioned python3 installation was not found, warn the user if the stock python3 installation is outside
104120 -- the supported version range.
105121 if
106- target == stock_target
122+ use_uv == false
123+ and target == stock_target
107124 and supported_python_versions ~= nil
108125 and not pep440_check_version (tostring (target .version ), supported_python_versions )
109126 then
@@ -125,9 +142,14 @@ local function create_venv(pkg)
125142 end
126143 end
127144
128- log .fmt_debug (" Found python3 installation version=%s, executable=%s" , target .version , target .executable )
129145 ctx .stdio_sink .stdout " Creating virtual environment…\n "
130- return ctx .spawn [target .executable ] { " -m" , " venv" , " --system-site-packages" , VENV_DIR }
146+ if use_uv then
147+ log .fmt_debug (" Found uv installation version=%s, executable=%s" , target .version , target .executable )
148+ return ctx .spawn [target .executable ] { " venv" , VENV_DIR }
149+ else
150+ log .fmt_debug (" Found python3 installation version=%s, executable=%s" , target .version , target .executable )
151+ return ctx .spawn [target .executable ] { " -m" , " venv" , " --system-site-packages" , VENV_DIR }
152+ end
131153end
132154
133155--- @param ctx InstallContext
153175--- @param args SpawnArgs
154176local function venv_python (args )
155177 local ctx = installer .context ()
178+ if use_uv then
179+ return ctx .spawn [{ " uv" , " venv" }](args )
180+ end
156181 return find_venv_executable (ctx , " python" ):and_then (function (python_path )
157182 return ctx .spawn [path .concat { ctx .cwd :get (), python_path }](args )
158183 end )
@@ -162,16 +187,29 @@ end
162187--- @param pkgs string[]
163188--- @param extra_args ? string[]
164189local function pip_install (pkgs , extra_args )
165- return venv_python {
166- " -m" ,
167- " pip" ,
168- " --disable-pip-version-check" ,
169- " install" ,
170- " --ignore-installed" ,
171- " -U" ,
172- extra_args or vim .NIL ,
173- pkgs ,
174- }
190+ if use_uv then
191+ local ctx = installer .context ()
192+
193+ local task = ctx .spawn [" uv" ] {
194+ " pip" ,
195+ " install" ,
196+ " -U" ,
197+ extra_args or vim .NIL ,
198+ pkgs ,
199+ }
200+ return task
201+ else
202+ return venv_python {
203+ " -m" ,
204+ " pip" ,
205+ " --disable-pip-version-check" ,
206+ " install" ,
207+ " --ignore-installed" ,
208+ " -U" ,
209+ extra_args or vim .NIL ,
210+ pkgs ,
211+ }
212+ end
175213end
176214
177215--- @async
@@ -185,7 +223,7 @@ function M.init(opts)
185223 ctx :promote_cwd ()
186224 try (create_venv (opts .package ))
187225
188- if opts .upgrade_pip then
226+ if opts .upgrade_pip and not use_uv then
189227 ctx .stdio_sink .stdout " Upgrading pip inside the virtual environment…\n "
190228 try (pip_install ({ " pip" }, opts .install_extra_args ))
191229 end
0 commit comments