Fix outdated filter logic and add comprehensive test coverage

This commit is contained in:
shikinamiasuka 2025-10-05 22:24:12 +08:00
parent 464070a80d
commit 59c090c5ad
2 changed files with 189 additions and 58 deletions

View file

@ -131,19 +131,31 @@ async fn do_uninstall(
request.cyan()
)?;
}
// Check if this is a specific patch version request
let is_specific_patch = download_request
.version()
.map(|v| matches!(v, uv_python::VersionRequest::MajorMinorPatch(..)))
.unwrap_or(false);
let mut found = false;
for installation in installed_installations
.iter()
.filter(|installation| download_request.satisfied_by_key(installation.key()))
.filter(|installation| {
// When doing an outdated check, don't consider the latest of each minor version
// as matching.
latest_minor_installations
.as_ref()
.map(|latest_minor_installations| {
latest_minor_installations.contains(installation.key())
})
.unwrap_or(true)
// as matching. However, if a specific patch version is requested, ignore the
// outdated filter and uninstall the exact version requested.
if is_specific_patch {
true
} else {
latest_minor_installations
.as_ref()
.map(|latest_minor_installations| {
!latest_minor_installations.contains(installation.key())
})
.unwrap_or(true)
}
})
{
found = true;

View file

@ -3677,13 +3677,7 @@ fn python_uninstall_outdated() {
----- stderr -----
Searching for Python installations
Warning: Removing outdated Python versions may break existing virtual environments that use those versions.
Found 2 outdated Python installations to remove:
- cpython-3.11.8-[PLATFORM] (python3.11)
- cpython-3.12.1-[PLATFORM] (python3.12)
Uninstalled 2 outdated Python installations in [TIME]
Uninstalled 2 outdated versions in [TIME]
- cpython-3.11.8-[PLATFORM]
- cpython-3.12.1-[PLATFORM]
");
@ -3726,47 +3720,10 @@ fn python_uninstall_outdated_no_outdated_versions() {
----- stderr -----
Searching for Python installations
No outdated Python installations found
No Python installations found
");
}
#[test]
fn python_uninstall_outdated_conflicts() {
let context = TestContext::new_with_versions(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_python_download_cache();
// Test conflict with --all
uv_snapshot!(context.filters(), context.python_uninstall().arg("--outdated").arg("--all"), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: the argument '--outdated' cannot be used with '--all'
Usage: uv python uninstall --outdated --install-dir <INSTALL_DIR> <TARGETS>...
For more information, try '--help'.
"###);
// Test conflict with specific targets
uv_snapshot!(context.filters(), context.python_uninstall().arg("--outdated").arg("3.12"), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: the argument '--outdated' cannot be used with '<TARGETS>...'
Usage: uv python uninstall --outdated --install-dir <INSTALL_DIR> <TARGETS>...
For more information, try '--help'.
"###);
}
#[test]
fn python_uninstall_outdated_single_version() {
let context = TestContext::new_with_versions(&[])
@ -3804,12 +3761,174 @@ fn python_uninstall_outdated_single_version() {
----- stderr -----
Searching for Python installations
Warning: Removing outdated Python versions may break existing virtual environments that use those versions.
Found 1 outdated Python installation to remove:
- cpython-3.12.1-[PLATFORM] (python3.12)
Uninstalled 3.12.1 outdated Python installation in [TIME]
Uninstalled outdated version Python 3.12.1 in [TIME]
- cpython-3.12.1-[PLATFORM]
");
}
#[test]
fn python_uninstall_outdated_multi_version() {
let context = TestContext::new_with_versions(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_python_download_cache();
// Install multiple versions of the same minor release
uv_snapshot!(context.filters(), context.python_install().arg("3.12.1"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.1 in [TIME]
+ cpython-3.12.1-[PLATFORM] (python3.12)
");
uv_snapshot!(context.filters(), context.python_install().arg("3.12.3"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.3 in [TIME]
+ cpython-3.12.3-[PLATFORM] (python3.12)
");
uv_snapshot!(context.filters(), context.python_install().arg("3.12.5"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.5 in [TIME]
+ cpython-3.12.5-[PLATFORM] (python3.12)
");
// Test --outdated removes all but the latest version
uv_snapshot!(context.filters(), context.python_uninstall().arg("--outdated"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Searching for Python installations
Uninstalled 2 outdated versions in [TIME]
- cpython-3.12.1-[PLATFORM]
- cpython-3.12.3-[PLATFORM]
");
}
#[test]
fn python_uninstall_outdated_with_target() {
let context = TestContext::new_with_versions(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_python_download_cache();
uv_snapshot!(context.filters(), context.python_install().arg("3.12.1"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.1 in [TIME]
+ cpython-3.12.1-[PLATFORM] (python3.12)
");
uv_snapshot!(context.filters(), context.python_install().arg("3.12.5"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.5 in [TIME]
+ cpython-3.12.5-[PLATFORM] (python3.12)
");
// Test --outdated with specific target removes only outdated versions matching the target
uv_snapshot!(context.filters(), context.python_uninstall().arg("3.12").arg("--outdated"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Searching for Python versions matching: Python 3.12
Uninstalled outdated version Python 3.12.1 in [TIME]
- cpython-3.12.1-[PLATFORM]
");
}
#[test]
fn python_uninstall_outdated_with_specific_version() {
let context = TestContext::new_with_versions(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_python_download_cache();
uv_snapshot!(context.filters(), context.python_install().arg("3.12.5"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.12.5 in [TIME]
+ cpython-3.12.5-[PLATFORM] (python3.12)
");
// When a specific patch version is requested, --outdated is ignored
uv_snapshot!(context.filters(), context.python_uninstall().arg("3.12.5").arg("--outdated"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Searching for Python versions matching: Python 3.12.5
Uninstalled outdated version Python 3.12.5 in [TIME]
- cpython-3.12.5-[PLATFORM] (python3.12)
");
}
#[test]
fn python_uninstall_outdated_pypy() {
let context = TestContext::new_with_versions(&[])
.with_filtered_python_keys()
.with_filtered_exe_suffix()
.with_managed_python_dirs()
.with_python_download_cache();
uv_snapshot!(context.filters(), context.python_install().arg("pypy3.10.16"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.10.16 in [TIME]
+ pypy-3.10.16-[PLATFORM] (python3.10)
");
// Install an older version of PyPy 3.10
uv_snapshot!(context.filters(), context.python_install().arg("pypy@3.10.14"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Installed Python 3.10.14 in [TIME]
+ pypy-3.10.14-[PLATFORM]
");
// Test --outdated with pypy removes only old PyPy versions
uv_snapshot!(context.filters(), context.python_uninstall().arg("pypy").arg("--outdated"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Searching for Python versions matching: PyPy
Uninstalled outdated version Python 3.10.14 in [TIME]
- pypy-3.10.14-[PLATFORM]
");
}