Skip to content

Commit 2981c8d

Browse files
committed
Add uv python install --default
1 parent 8e382ef commit 2981c8d

File tree

2 files changed

+77
-39
lines changed

2 files changed

+77
-39
lines changed

crates/uv/src/commands/python/install.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,14 @@ pub(crate) async fn install(
276276
continue;
277277
}
278278

279-
let targets = if default {
279+
let bin = bin
280+
.as_ref()
281+
.expect("We should have a bin directory with preview enabled")
282+
.as_path();
283+
284+
let targets = if (default || is_default_install)
285+
&& first_request.matches_installation(installation)
286+
{
280287
vec![
281288
installation.key().executable_name_minor(),
282289
installation.key().executable_name_major(),
@@ -286,11 +293,6 @@ pub(crate) async fn install(
286293
vec![installation.key().executable_name_minor()]
287294
};
288295

289-
let bin = bin
290-
.as_ref()
291-
.expect("We should have a bin directory with preview enabled")
292-
.as_path();
293-
294296
for target in targets {
295297
let target = bin.join(target);
296298
match installation.create_bin_link(&target) {

crates/uv/tests/it/python_install.rs

+69-33
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::process::Command;
22

33
use assert_fs::{assert::PathAssert, prelude::PathChild};
44
use predicates::prelude::predicate;
5+
use same_file::is_same_file;
56

67
use crate::common::{uv_snapshot, TestContext};
78

@@ -290,6 +291,21 @@ fn python_install_invalid_request() {
290291
fn python_install_default() {
291292
let context: TestContext = TestContext::new_with_versions(&[]).with_filtered_python_keys();
292293

294+
let bin_python_minor = context
295+
.temp_dir
296+
.child("bin")
297+
.child(format!("python3.13{}", std::env::consts::EXE_SUFFIX));
298+
299+
let bin_python_major = context
300+
.temp_dir
301+
.child("bin")
302+
.child(format!("python3{}", std::env::consts::EXE_SUFFIX));
303+
304+
let bin_python_default = context
305+
.temp_dir
306+
.child("bin")
307+
.child(format!("python{}", std::env::consts::EXE_SUFFIX));
308+
293309
// `--preview` is required for `--default`
294310
uv_snapshot!(context.filters(), context.python_install().arg("--default"), @r###"
295311
success: false
@@ -300,51 +316,69 @@ fn python_install_default() {
300316
The `--default` flag is only available in preview mode; add the `--preview` flag to use `--default.
301317
"###);
302318

303-
// Install the latest version
304-
uv_snapshot!(context.filters(), context.python_install().arg("--preview"), @r###"
319+
// Install a specific version
320+
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.13"), @r###"
305321
success: true
306322
exit_code: 0
307323
----- stdout -----
308324
309325
----- stderr -----
310-
Searching for Python installations
311326
Installed Python 3.13.0 in [TIME]
312327
+ cpython-3.13.[X]-[PLATFORM]
313328
warning: `[TEMP_DIR]/bin` is not on your PATH. To use the installed Python executable, run `export PATH="[TEMP_DIR]/bin:$PATH"`.
314329
"###);
315330

316-
let bin_python_minor = context
317-
.temp_dir
318-
.child("bin")
319-
.child(format!("python3.13{}", std::env::consts::EXE_SUFFIX));
331+
// Only the minor versioned executable should be installed
332+
bin_python_minor.assert(predicate::path::exists());
333+
bin_python_major.assert(predicate::path::missing());
334+
bin_python_default.assert(predicate::path::missing());
320335

321-
let bin_python_major = context
322-
.temp_dir
323-
.child("bin")
324-
.child(format!("python3{}", std::env::consts::EXE_SUFFIX));
336+
// Install again, with `--default`
337+
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("--default").arg("3.13"), @r###"
338+
success: true
339+
exit_code: 0
340+
----- stdout -----
325341
326-
let bin_python_default = context
327-
.temp_dir
328-
.child("bin")
329-
.child(format!("python{}", std::env::consts::EXE_SUFFIX));
342+
----- stderr -----
343+
Installed Python 3.13.0 in [TIME]
344+
+ cpython-3.13.[X]-[PLATFORM]
345+
warning: `[TEMP_DIR]/bin` is not on your PATH. To use the installed Python executable, run `export PATH="[TEMP_DIR]/bin:$PATH"`.
346+
"###);
330347

331-
// The minor-versioend executable should be installed in the bin directory
348+
// Now all the executables should be installed
332349
bin_python_minor.assert(predicate::path::exists());
333-
// But the others should not
350+
bin_python_major.assert(predicate::path::exists());
351+
bin_python_default.assert(predicate::path::exists());
352+
353+
uv_snapshot!(context.filters(), context.python_uninstall().arg("--all"), @r###"
354+
success: true
355+
exit_code: 0
356+
----- stdout -----
357+
358+
----- stderr -----
359+
Searching for Python installations
360+
Uninstalled Python 3.13.0 in [TIME]
361+
- cpython-3.13.[X]-[PLATFORM]
362+
"###);
363+
364+
// The executables should be removed
365+
bin_python_minor.assert(predicate::path::missing());
334366
bin_python_major.assert(predicate::path::missing());
335367
bin_python_default.assert(predicate::path::missing());
336368

337-
// TODO(zanieb): We should add the executables without the `--reinstall` flag
338-
uv_snapshot!(context.filters(), context.python_install().arg("--default").arg("--reinstall"), @r###"
339-
success: false
340-
exit_code: 1
369+
// Install the latest version
370+
uv_snapshot!(context.filters(), context.python_install().arg("--preview"), @r###"
371+
success: true
372+
exit_code: 0
341373
----- stdout -----
342374
343375
----- stderr -----
344-
The `--default` flag is only available in preview mode; add the `--preview` flag to use `--default.
376+
Installed Python 3.13.0 in [TIME]
377+
+ cpython-3.13.[X]-[PLATFORM]
378+
warning: `[TEMP_DIR]/bin` is not on your PATH. To use the installed Python executable, run `export PATH="[TEMP_DIR]/bin:$PATH"`.
345379
"###);
346380

347-
// Now we should have an unversioned and major-versioned executable
381+
// Since it's a bare install, we should include all of the executables
348382
bin_python_minor.assert(predicate::path::exists());
349383
bin_python_major.assert(predicate::path::exists());
350384
bin_python_default.assert(predicate::path::exists());
@@ -366,26 +400,28 @@ fn python_install_default() {
366400
bin_python_default.assert(predicate::path::missing());
367401

368402
// Install multiple versions
369-
uv_snapshot!(context.filters(), context.python_install().arg("3.12").arg("3.13").arg("--default"), @r###"
370-
success: false
371-
exit_code: 1
403+
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("3.12").arg("3.13").arg("--default"), @r###"
404+
success: true
405+
exit_code: 0
372406
----- stdout -----
373407
374408
----- stderr -----
375-
Searching for Python versions matching: Python 3.12
376-
Searching for Python versions matching: Python 3.13
377409
Installed 2 versions in [TIME]
378410
+ cpython-3.12.[X]-[PLATFORM]
379411
+ cpython-3.13.[X]-[PLATFORM]
380412
warning: `[TEMP_DIR]/bin` is not on your PATH. To use the installed Python executable, run `export PATH="[TEMP_DIR]/bin:$PATH"`.
381-
error: Failed to install cpython-3.12.[X]-[PLATFORM]
382-
Caused by: Executable already exists at `bin/python3`. Use `--reinstall` to force replacement.
383-
error: Failed to install cpython-3.12.[X]-[PLATFORM]
384-
Caused by: Executable already exists at `bin/python`. Use `--reinstall` to force replacement.
385413
"###);
386414

387415
bin_python_minor.assert(predicate::path::exists());
388416
bin_python_major.assert(predicate::path::exists());
389417
bin_python_default.assert(predicate::path::exists());
390-
// TODO(zanieb): Assert that 3.12 is the default version
418+
419+
let bin_python_minor_12 = context
420+
.temp_dir
421+
.child("bin")
422+
.child(format!("python3.12{}", std::env::consts::EXE_SUFFIX));
423+
424+
bin_python_minor_12.assert(predicate::path::exists());
425+
assert!(is_same_file(&bin_python_minor_12, &bin_python_major).unwrap());
426+
assert!(is_same_file(&bin_python_minor_12, &bin_python_default).unwrap());
391427
}

0 commit comments

Comments
 (0)