Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/uv/tests/it/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,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.54";
pub const DEFAULT_PYTHON_VERSION: &str = "3.12";

/// Using a find links url allows using `--index-url` instead of `--extra-index-url` in tests
Expand Down
169 changes: 168 additions & 1 deletion crates/uv/tests/it/lock_scenarios.rs
Original file line number Diff line number Diff line change
@@ -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.54/scenarios>
//!
#![cfg(all(feature = "python", feature = "pypi"))]
#![allow(clippy::needless_raw_string_hashes)]
Expand Down Expand Up @@ -5347,6 +5347,173 @@ fn virtual_package_extra_priorities() -> Result<()> {
Ok(())
}

/// A package is first used under a marker that is a subset of the required environments that it fulfills, and then under a marker that is a subset it doesn't fulfill.
///
/// `a` has a wheel only supports Windows, and the required platforms are Linux and Windows. The first time we encounter `a`, it's used with a Windows-only marker, so it doesn't violate. Afterwards, we select `b`, and while it doesn't change the version for `a`, it requires it universally. Now the resolution needs to fail, as `a` is now missing the Linux wheel.
///
/// See <https://github.com/astral-sh/uv/pull/16824#discussion_r2556176057>
///
/// ```text
/// markers-change-after-selection
/// ├── environment
/// │ └── python3.12
/// ├── root
/// │ ├── requires a; sys_platform == "win32"
/// │ │ └── satisfied by a-1.0.0
/// │ └── requires b
/// │ └── satisfied by b-1.0.0
/// ├── a
/// │ └── a-1.0.0
/// └── b
/// └── b-1.0.0
/// └── requires a; sys_platform == "linux"
/// └── satisfied by a-1.0.0
/// ```
#[test]
fn markers_change_after_selection() -> Result<()> {
let context = TestContext::new("3.12");

// In addition to the standard filters, swap out package names for shorter messages
let mut filters = context.filters();
filters.push((r"markers-change-after-selection-", "package-"));

let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r###"
[project]
name = "project"
version = "0.1.0"
dependencies = [
'''markers-change-after-selection-a; sys_platform == "win32"''',
'''markers-change-after-selection-b''',
]
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, @r"
success: false
exit_code: 1
----- stdout -----

----- stderr -----
× No solution found when resolving dependencies for split (markers: sys_platform == 'linux'):
╰─▶ Because only package-a{sys_platform == 'win32'}==1.0.0 is available and package-a==1.0.0 has no Linux-compatible wheels, we can conclude that all versions of package-a{sys_platform == 'win32'} cannot be used.
And because your project depends on package-a{sys_platform == 'win32'}, we can conclude that your project's requirements are unsatisfiable.
"
);

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 = TestContext::new("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, @r"
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
Expand Down
2 changes: 1 addition & 1 deletion crates/uv/tests/it/pip_compile_scenarios.rs
Original file line number Diff line number Diff line change
@@ -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.54/scenarios>
//!
#![cfg(all(feature = "python", feature = "pypi", unix))]

Expand Down
2 changes: 1 addition & 1 deletion crates/uv/tests/it/pip_install_scenarios.rs
Original file line number Diff line number Diff line change
@@ -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.54/scenarios>
//!
#![cfg(all(feature = "python", feature = "pypi", unix))]

Expand Down
6 changes: 3 additions & 3 deletions scripts/scenarios/pylock.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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.54"
sdist = { url = "https://files.pythonhosted.org/packages/a3/e2/9ba11ffac2cb2719ace80731bec4c0c54b6b74c25f1675f45082e40dcd6f/packse-0.3.54.tar.gz", upload-time = 2025-11-27T14:41:23Z, size = 5879759, hashes = { sha256 = "1ef801475423f51724efaa20577ad708c29a89499001fae387b7ac2b5cfaf534" } }
wheels = [{ url = "https://files.pythonhosted.org/packages/5b/31/7d1e18a74e14a8d33aab5d24abdd19e47210d55846502380481384a33478/packse-0.3.54-py3-none-any.whl", upload-time = 2025-11-27T14:41:25Z, size = 34098, hashes = { sha256 = "bdb86af409a0c622f3a4374700b4bbb94fabc3d0e4d4d42b37e7aab3d863ff96" } }]

[[packages]]
name = "pathspec"
Expand Down
2 changes: 1 addition & 1 deletion scripts/scenarios/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[dependency-groups]
packse = [
"chevron-blue",
"packse>=0.3.53"
"packse>=0.3.54"
]
Loading