Update packse and remove Python 3.9.20 from test requirements (#17881)

Requires the packse PR to land first.
This commit is contained in:
konsti
2026-02-18 19:35:30 +01:00
committed by GitHub
parent 4cf70d6d87
commit 585dac12a9
10 changed files with 255 additions and 43 deletions
-2
View File
@@ -15,8 +15,6 @@
3.10.16
3.9.21
3.8.20
# The following are required for packse scenarios
3.9.20
# The following is needed for `==3.13` request tests
3.13.0
# A pre-release version required for testing
+1 -1
View File
@@ -36,7 +36,7 @@ use uv_static::EnvVars;
// Exclude any packages uploaded after this date.
static EXCLUDE_NEWER: &str = "2024-03-25T00:00:00Z";
pub const PACKSE_VERSION: &str = "0.3.53";
pub const PACKSE_VERSION: &str = "0.3.59";
pub const DEFAULT_PYTHON_VERSION: &str = "3.12";
// The expected latest patch version for each Python minor version.
+101 -1
View File
@@ -1,7 +1,7 @@
//! DO NOT EDIT
//!
//! Generated with `./scripts/sync_scenarios.sh`
//! Scenarios from <https://github.com/astral-sh/packse/tree/0.3.53/scenarios>
//! Scenarios from <https://github.com/astral-sh/packse/tree/0.3.59/scenarios>
//!
#![cfg(all(feature = "test-python", feature = "test-pypi"))]
#![allow(clippy::needless_raw_string_hashes)]
@@ -5347,6 +5347,106 @@ fn virtual_package_extra_priorities() -> Result<()> {
Ok(())
}
/// While both Linux and Windows are required and `win-only` has only a Windows wheel, `win-only` is also used only on Windows.
///
/// ```text
/// requires-python-subset
/// ├── environment
/// │ └── python3.12
/// ├── root
/// │ └── requires win-only; sys_platform == "win32"
/// │ └── satisfied by win-only-1.0.0
/// └── win-only
/// └── win-only-1.0.0
/// ```
#[test]
fn requires_python_subset() -> Result<()> {
let context = uv_test::test_context!("3.12");
// In addition to the standard filters, swap out package names for shorter messages
let mut filters = context.filters();
filters.push((r"requires-python-subset-", "package-"));
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''requires-python-subset-win-only; sys_platform == "win32"''',
]
requires-python = ">=3.12"
[tool.uv]
required-environments = [
'''sys_platform == "linux"''',
'''sys_platform == "win32"''',
]
"###,
)?;
let mut cmd = context.lock();
cmd.env_remove(EnvVars::UV_EXCLUDE_NEWER);
cmd.arg("--index-url").arg(packse_index_url());
uv_snapshot!(filters, cmd, @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 2 packages in [TIME]
"
);
let lock = context.read("uv.lock");
insta::with_settings!({
filters => filters,
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 3
requires-python = ">=3.12"
required-markers = [
"sys_platform == 'linux'",
"sys_platform == 'win32'",
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "package-win-only", marker = "sys_platform == 'win32'" },
]
[package.metadata]
requires-dist = [{ name = "package-win-only", marker = "sys_platform == 'win32'" }]
[[package]]
name = "package-win-only"
version = "1.0.0"
source = { registry = "https://astral-sh.github.io/packse/PACKSE_VERSION/simple-html/" }
wheels = [
{ url = "https://astral-sh.github.io/packse/PACKSE_VERSION/files/requires_python_subset_win_only-1.0.0-cp312-abi3-win_amd64.whl", hash = "sha256:91d59021b1c4aad7449e315ae1248c5c588a7e84cb7592671a41453012302711" },
]
"#
);
});
// Assert the idempotence of `uv lock` when resolving from the lockfile (`--locked`).
context
.lock()
.arg("--locked")
.env_remove(EnvVars::UV_EXCLUDE_NEWER)
.arg("--index-url")
.arg(packse_index_url())
.assert()
.success();
Ok(())
}
/// When a dependency is only required on a specific platform (like x86_64), omit wheels that target other platforms (like aarch64).
///
/// ```text
+28 -27
View File
@@ -1,10 +1,11 @@
//! DO NOT EDIT
//!
//! Generated with `./scripts/sync_scenarios.sh`
//! Scenarios from <https://github.com/astral-sh/packse/tree/0.3.53/scenarios>
//! Scenarios from <https://github.com/astral-sh/packse/tree/0.3.59/scenarios>
//!
#![cfg(all(feature = "test-python", feature = "test-pypi", unix))]
use std::env;
use std::process::Command;
use anyhow::Result;
@@ -352,7 +353,7 @@ fn incompatible_python_compatible_override() -> Result<()> {
/// ```text
/// python-patch-override-no-patch
/// ├── environment
/// │ └── python3.9.20
/// │ └── python3.9.21
/// ├── root
/// │ └── requires a==1.0.0
/// │ └── satisfied by a-1.0.0
@@ -363,7 +364,7 @@ fn incompatible_python_compatible_override() -> Result<()> {
#[cfg(feature = "test-python-patch")]
#[test]
fn python_patch_override_no_patch() -> Result<()> {
let context = uv_test::test_context!("3.9.20");
let context = uv_test::test_context!("3.9.21");
let python_versions = &[];
// In addition to the standard filters, swap out package names for shorter messages
@@ -376,18 +377,18 @@ fn python_patch_override_no_patch() -> Result<()> {
// Since the resolver is asked to solve with 3.9, the minimum compatible Python requirement is treated as 3.9.0.
let output = uv_snapshot!(filters, command(&context, python_versions)
.arg("--python-version=3.9")
, @r"
success: false
exit_code: 1
----- stdout -----
, @"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because the requested Python version (>=3.9) does not satisfy Python>=3.9.4 and package-a==1.0.0 depends on Python>=3.9.4, we can conclude that package-a==1.0.0 cannot be used.
And because you require package-a==1.0.0, we can conclude that your requirements are unsatisfiable.
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because the requested Python version (>=3.9) does not satisfy Python>=3.9.4 and package-a==1.0.0 depends on Python>=3.9.4, we can conclude that package-a==1.0.0 cannot be used.
And because you require package-a==1.0.0, we can conclude that your requirements are unsatisfiable.
hint: The `--python-version` value (>=3.9) includes Python versions that are not supported by your dependencies (e.g., package-a==1.0.0 only supports >=3.9.4). Consider using a higher `--python-version` value.
"
hint: The `--python-version` value (>=3.9) includes Python versions that are not supported by your dependencies (e.g., package-a==1.0.0 only supports >=3.9.4). Consider using a higher `--python-version` value.
"
);
output.assert().failure();
@@ -400,7 +401,7 @@ fn python_patch_override_no_patch() -> Result<()> {
/// ```text
/// python-patch-override-patch-compatible
/// ├── environment
/// │ └── python3.9.20
/// │ └── python3.9.21
/// ├── root
/// │ └── requires a==1.0.0
/// │ └── satisfied by a-1.0.0
@@ -411,7 +412,7 @@ fn python_patch_override_no_patch() -> Result<()> {
#[cfg(feature = "test-python-patch")]
#[test]
fn python_patch_override_patch_compatible() -> Result<()> {
let context = uv_test::test_context!("3.9.20");
let context = uv_test::test_context!("3.9.21");
let python_versions = &[];
// In addition to the standard filters, swap out package names for shorter messages
@@ -423,19 +424,19 @@ fn python_patch_override_patch_compatible() -> Result<()> {
let output = uv_snapshot!(filters, command(&context, python_versions)
.arg("--python-version=3.9.0")
, @r"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile requirements.in --cache-dir [CACHE_DIR] --python-version=3.9.0
package-a==1.0.0
# via -r requirements.in
, @"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile requirements.in --cache-dir [CACHE_DIR] --python-version=3.9.0
package-a==1.0.0
# via -r requirements.in
----- stderr -----
warning: The requested Python version 3.9.0 is not available; 3.9.20 will be used to build dependencies instead.
Resolved 1 package in [TIME]
"
----- stderr -----
warning: The requested Python version 3.9.0 is not available; 3.9.21 will be used to build dependencies instead.
Resolved 1 package in [TIME]
"
);
output.assert().success().stdout(predicate::str::contains(
+115 -2
View File
@@ -1,7 +1,7 @@
//! DO NOT EDIT
//!
//! Generated with `./scripts/sync_scenarios.sh`
//! Scenarios from <https://github.com/astral-sh/packse/tree/0.3.53/scenarios>
//! Scenarios from <https://github.com/astral-sh/packse/tree/0.3.59/scenarios>
//!
#![cfg(all(feature = "test-python", feature = "test-pypi", unix))]
@@ -23,6 +23,119 @@ fn command(context: &TestContext) -> Command {
command
}
/// There are two packages, `a` and `b`. All versions of `b` require a specific
/// version of `a`, but that version requires a package `c` that does not exist. The resolver
/// must backtrack through all versions of `b` and eventually fail because no solution exists.
///
/// ```text
/// backtrack-to-missing-package
/// ├── environment
/// │ └── python3.12
/// ├── root
/// │ ├── requires a
/// │ │ ├── satisfied by a-2.0.0
/// │ │ └── satisfied by a-1.0.0
/// │ └── requires b
/// │ ├── satisfied by b-1.0.0
/// │ ├── satisfied by b-2.0.0
/// │ └── satisfied by b-3.0.0
/// ├── a
/// │ ├── a-2.0.0
/// │ └── a-1.0.0
/// │ └── requires c
/// │ └── unsatisfied: no versions for package
/// └── b
/// ├── b-1.0.0
/// │ └── requires a==1.0.0
/// │ └── satisfied by a-1.0.0
/// ├── b-2.0.0
/// │ └── requires a==1.0.0
/// │ └── satisfied by a-1.0.0
/// └── b-3.0.0
/// └── requires a==1.0.0
/// └── satisfied by a-1.0.0
/// ```
#[test]
fn backtrack_to_missing_package() {
let context = uv_test::test_context!("3.12");
// In addition to the standard filters, swap out package names for shorter messages
let mut filters = context.filters();
filters.push((r"backtrack-to-missing-package-", "package-"));
uv_snapshot!(filters, command(&context)
.arg("backtrack-to-missing-package-a")
.arg("backtrack-to-missing-package-b")
, @"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
× No solution found when resolving dependencies:
╰─▶ Because package-c was not found in the package registry and package-a==1.0.0 depends on package-c, we can conclude that package-a==1.0.0 cannot be used.
And because all versions of package-b depend on package-a==1.0.0 and you require package-b, we can conclude that your requirements are unsatisfiable.
");
context.assert_not_installed("backtrack_to_missing_package_a");
context.assert_not_installed("backtrack_to_missing_package_b");
}
/// There are two packages, `a` and `b`. The latest version of `b` requires
/// a specific version of `a`. The older version of `b` requires a package `c` that does not
/// exist. The resolver should backtrack on `a` (not `b`) to find a solution without needing
/// to try `b==1.0.0` which would fail due to the missing package.
///
/// ```text
/// backtrack-with-missing-package
/// ├── environment
/// │ └── python3.12
/// ├── root
/// │ ├── requires a
/// │ │ ├── satisfied by a-1.0.0
/// │ │ └── satisfied by a-2.0.0
/// │ └── requires b
/// │ ├── satisfied by b-1.0.0
/// │ └── satisfied by b-2.0.0
/// ├── a
/// │ ├── a-1.0.0
/// │ └── a-2.0.0
/// └── b
/// ├── b-1.0.0
/// │ └── requires c
/// │ └── unsatisfied: no versions for package
/// └── b-2.0.0
/// └── requires a==1.0.0
/// └── satisfied by a-1.0.0
/// ```
#[test]
fn backtrack_with_missing_package() {
let context = uv_test::test_context!("3.12");
// In addition to the standard filters, swap out package names for shorter messages
let mut filters = context.filters();
filters.push((r"backtrack-with-missing-package-", "package-"));
uv_snapshot!(filters, command(&context)
.arg("backtrack-with-missing-package-a")
.arg("backtrack-with-missing-package-b")
, @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 2 packages in [TIME]
Prepared 2 packages in [TIME]
Installed 2 packages in [TIME]
+ package-a==1.0.0
+ package-b==2.0.0
");
context.assert_installed("backtrack_with_missing_package_a", "1.0.0");
context.assert_installed("backtrack_with_missing_package_b", "2.0.0");
}
/// The user requires an exact version of package `a` but only other versions exist
///
/// ```text
@@ -3408,7 +3521,7 @@ fn python_greater_than_current_patch() {
uv_snapshot!(filters, command(&context)
.arg("python-greater-than-current-patch-a==1.0.0")
, @r"
, @"
success: false
exit_code: 1
----- stdout -----
+3 -3
View File
@@ -51,7 +51,7 @@ PACKSE = TOOL_ROOT / "packse-scenarios"
REQUIREMENTS = TOOL_ROOT / "pylock.toml"
PROJECT_ROOT = TOOL_ROOT.parent.parent
TESTS = PROJECT_ROOT / "crates" / "uv" / "tests" / "it"
TESTS_COMMON_MOD_RS = TESTS / "common" / "mod.rs"
TESTS_COMMON_MOD_RS = PROJECT_ROOT / "crates" / "uv-test" / "src" / "lib.rs"
try:
import packse
@@ -185,7 +185,7 @@ def main(
resolver_options = scenario["resolver_options"] or {}
# Avoid writing the empty `required-environments = []`
resolver_options["has_required_environments"] = bool(
resolver_options["required_environments"]
resolver_options.get("required_environments", [])
)
if resolver_options.get("universal"):
lock_scenarios.append(scenario)
@@ -259,7 +259,7 @@ def main(
"insta",
"test",
"--features",
"pypi,python,python-patch",
"test-pypi,test-python,test-python-patch",
"--accept",
"--test-runner",
"nextest",
+3 -3
View File
@@ -66,9 +66,9 @@ wheels = [{ url = "https://files.pythonhosted.org/packages/20/12/38679034af33278
[[packages]]
name = "packse"
version = "0.3.53"
sdist = { url = "https://files.pythonhosted.org/packages/52/58/373b6281bb741e875893dc351ac5f180c3fdce18a3b889f773725ff964b2/packse-0.3.53.tar.gz", upload-time = 2025-09-16T09:37:55Z, size = 5879063, hashes = { sha256 = "fcdbbb60f8ad4af94901891699a95ade4f15b9e769b4d8f443a2f3ef7aa74067" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/fc/86/d5482bb2933fe47d282b1dae74cc9084b094f28229848ba8ea01a77fe0da/packse-0.3.53-py3-none-any.whl", upload-time = 2025-09-16T09:37:53Z, size = 34039, hashes = { sha256 = "78cf05f5e0b916f4070a66f04f3b371e2d4ac0c3917f38cb692a33fa6e9d764b" } }]
version = "0.3.59"
sdist = { url = "https://files.pythonhosted.org/packages/16/90/51404d8933506bd9554f607f5054f4715e0a5e1d34e4c6542580553e8b75/packse-0.3.59.tar.gz", upload-time = 2026-02-18T17:44:17Z, size = 5880109, hashes = { sha256 = "718bcca5dd1e9321f5c2918d5975ffd772f0c3b150cf29b03979677a003d73d2" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/8d/95/b4a997b57a1f46f0f7575c1c021ee15e8fc1470b6ce74010239079d1d9aa/packse-0.3.59-py3-none-any.whl", upload-time = 2026-02-18T17:44:16Z, size = 34107, hashes = { sha256 = "10a3689ce0c00805cd7f1589862ab2d8f9fd4ab38c117342c351bfb13daa5c69" } }]
[[packages]]
name = "pathspec"
+1 -1
View File
@@ -1,5 +1,5 @@
[dependency-groups]
packse = [
"chevron-blue",
"packse>=0.3.53"
"packse>=0.3.59"
]
+1 -1
View File
@@ -24,7 +24,7 @@ use uv_test::{
fn command(context: &TestContext, python_versions: &[&str]) -> Command {
let python_path = python_path_with_versions(&context.temp_dir, python_versions)
.expect("Failed to create Python test path");
let mut command = Command::new(get_bin());
let mut command = Command::new(get_bin!());
command
.arg("pip")
.arg("compile")
+2 -2
View File
@@ -2,7 +2,7 @@
This script reads the download-metadata.json file and extracts the latest
patch version for each minor version (3.15, 3.14, 3.13, 3.12, 3.11, 3.10).
It then updates the LATEST_PYTHON_X_Y constants in crates/uv/tests/it/common/mod.rs.
It then updates the LATEST_PYTHON_X_Y constants in crates/uv-test/src/lib.rs.
For minor versions with stable releases, it uses the latest stable version.
For minor versions with only prereleases, it uses the latest prerelease.
@@ -70,7 +70,7 @@ def main() -> None:
if minor not in latest_versions:
latest_versions[minor] = prerelease_versions[minor]
# Update the constants in common/mod.rs
# Update the constants in uv-test/src/lib.rs
lib_path = ROOT / "crates" / "uv-test" / "src" / "lib.rs"
content = lib_path.read_text()