mirror of https://github.com/astral-sh/uv
Perform wheel lockfile filtering based on platform and OS intersection (#14976)
## Summary Ensures that if the user filters to macOS ARM, we don't include macOS x86_64 wheels. Closes https://github.com/astral-sh/uv/issues/14901.
This commit is contained in:
parent
6856a27711
commit
9b8ff44a04
|
|
@ -105,6 +105,11 @@ impl PlatformTag {
|
|||
}
|
||||
|
||||
impl PlatformTag {
|
||||
/// Returns `true` if the platform is "any" (i.e., not specific to a platform).
|
||||
pub fn is_any(&self) -> bool {
|
||||
matches!(self, Self::Any)
|
||||
}
|
||||
|
||||
/// Returns `true` if the platform is manylinux-only.
|
||||
pub fn is_manylinux(&self) -> bool {
|
||||
matches!(
|
||||
|
|
|
|||
|
|
@ -106,6 +106,51 @@ static X86_MARKERS: LazyLock<UniversalMarker> = LazyLock::new(|| {
|
|||
.unwrap();
|
||||
UniversalMarker::new(pep508, ConflictMarker::TRUE)
|
||||
});
|
||||
static LINUX_ARM_MARKERS: LazyLock<UniversalMarker> = LazyLock::new(|| {
|
||||
let mut marker = *LINUX_MARKERS;
|
||||
marker.and(*ARM_MARKERS);
|
||||
marker
|
||||
});
|
||||
static LINUX_X86_64_MARKERS: LazyLock<UniversalMarker> = LazyLock::new(|| {
|
||||
let mut marker = *LINUX_MARKERS;
|
||||
marker.and(*X86_64_MARKERS);
|
||||
marker
|
||||
});
|
||||
static LINUX_X86_MARKERS: LazyLock<UniversalMarker> = LazyLock::new(|| {
|
||||
let mut marker = *LINUX_MARKERS;
|
||||
marker.and(*X86_MARKERS);
|
||||
marker
|
||||
});
|
||||
static WINDOWS_ARM_MARKERS: LazyLock<UniversalMarker> = LazyLock::new(|| {
|
||||
let mut marker = *WINDOWS_MARKERS;
|
||||
marker.and(*ARM_MARKERS);
|
||||
marker
|
||||
});
|
||||
static WINDOWS_X86_64_MARKERS: LazyLock<UniversalMarker> = LazyLock::new(|| {
|
||||
let mut marker = *WINDOWS_MARKERS;
|
||||
marker.and(*X86_64_MARKERS);
|
||||
marker
|
||||
});
|
||||
static WINDOWS_X86_MARKERS: LazyLock<UniversalMarker> = LazyLock::new(|| {
|
||||
let mut marker = *WINDOWS_MARKERS;
|
||||
marker.and(*X86_MARKERS);
|
||||
marker
|
||||
});
|
||||
static MAC_ARM_MARKERS: LazyLock<UniversalMarker> = LazyLock::new(|| {
|
||||
let mut marker = *MAC_MARKERS;
|
||||
marker.and(*ARM_MARKERS);
|
||||
marker
|
||||
});
|
||||
static MAC_X86_64_MARKERS: LazyLock<UniversalMarker> = LazyLock::new(|| {
|
||||
let mut marker = *MAC_MARKERS;
|
||||
marker.and(*X86_64_MARKERS);
|
||||
marker
|
||||
});
|
||||
static MAC_X86_MARKERS: LazyLock<UniversalMarker> = LazyLock::new(|| {
|
||||
let mut marker = *MAC_MARKERS;
|
||||
marker.and(*X86_MARKERS);
|
||||
marker
|
||||
});
|
||||
|
||||
#[derive(Clone, Debug, serde::Deserialize)]
|
||||
#[serde(try_from = "LockWire")]
|
||||
|
|
@ -336,14 +381,61 @@ impl Lock {
|
|||
// a single disjointness check with the intersection is sufficient, so we have one
|
||||
// constant per platform.
|
||||
let platform_tags = wheel.filename.platform_tags();
|
||||
|
||||
if platform_tags.iter().all(PlatformTag::is_any) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if platform_tags.iter().all(PlatformTag::is_linux) {
|
||||
if graph.graph[node_index].marker().is_disjoint(*LINUX_MARKERS) {
|
||||
if platform_tags.iter().all(PlatformTag::is_arm) {
|
||||
if graph.graph[node_index]
|
||||
.marker()
|
||||
.is_disjoint(*LINUX_ARM_MARKERS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else if platform_tags.iter().all(PlatformTag::is_x86_64) {
|
||||
if graph.graph[node_index]
|
||||
.marker()
|
||||
.is_disjoint(*LINUX_X86_64_MARKERS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else if platform_tags.iter().all(PlatformTag::is_x86) {
|
||||
if graph.graph[node_index]
|
||||
.marker()
|
||||
.is_disjoint(*LINUX_X86_MARKERS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else if graph.graph[node_index].marker().is_disjoint(*LINUX_MARKERS) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if platform_tags.iter().all(PlatformTag::is_windows) {
|
||||
if graph.graph[node_index]
|
||||
if platform_tags.iter().all(PlatformTag::is_arm) {
|
||||
if graph.graph[node_index]
|
||||
.marker()
|
||||
.is_disjoint(*WINDOWS_ARM_MARKERS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else if platform_tags.iter().all(PlatformTag::is_x86_64) {
|
||||
if graph.graph[node_index]
|
||||
.marker()
|
||||
.is_disjoint(*WINDOWS_X86_64_MARKERS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else if platform_tags.iter().all(PlatformTag::is_x86) {
|
||||
if graph.graph[node_index]
|
||||
.marker()
|
||||
.is_disjoint(*WINDOWS_X86_MARKERS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else if graph.graph[node_index]
|
||||
.marker()
|
||||
.is_disjoint(*WINDOWS_MARKERS)
|
||||
{
|
||||
|
|
@ -352,7 +444,28 @@ impl Lock {
|
|||
}
|
||||
|
||||
if platform_tags.iter().all(PlatformTag::is_macos) {
|
||||
if graph.graph[node_index].marker().is_disjoint(*MAC_MARKERS) {
|
||||
if platform_tags.iter().all(PlatformTag::is_arm) {
|
||||
if graph.graph[node_index]
|
||||
.marker()
|
||||
.is_disjoint(*MAC_ARM_MARKERS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else if platform_tags.iter().all(PlatformTag::is_x86_64) {
|
||||
if graph.graph[node_index]
|
||||
.marker()
|
||||
.is_disjoint(*MAC_X86_64_MARKERS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else if platform_tags.iter().all(PlatformTag::is_x86) {
|
||||
if graph.graph[node_index]
|
||||
.marker()
|
||||
.is_disjoint(*MAC_X86_MARKERS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else if graph.graph[node_index].marker().is_disjoint(*MAC_MARKERS) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30040,3 +30040,106 @@ fn lock_circular_path_dependency_explicit_index() -> Result<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lock_required_intersection() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||
pyproject_toml.write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"numpy",
|
||||
]
|
||||
|
||||
[tool.uv]
|
||||
environments = [
|
||||
"(sys_platform=='linux' and platform_machine=='x86_64')",
|
||||
"(platform_machine=='arm64' and sys_platform=='darwin')"
|
||||
]
|
||||
"#,
|
||||
)?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.lock(), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 2 packages in [TIME]
|
||||
");
|
||||
|
||||
let lock = context.read("uv.lock");
|
||||
|
||||
insta::with_settings!({
|
||||
filters => context.filters(),
|
||||
}, {
|
||||
assert_snapshot!(
|
||||
lock, @r#"
|
||||
version = 1
|
||||
revision = 3
|
||||
requires-python = ">=3.12"
|
||||
resolution-markers = [
|
||||
"platform_machine == 'x86_64' and sys_platform == 'linux'",
|
||||
"platform_machine == 'arm64' and sys_platform == 'darwin'",
|
||||
]
|
||||
supported-markers = [
|
||||
"platform_machine == 'x86_64' and sys_platform == 'linux'",
|
||||
"platform_machine == 'arm64' and sys_platform == 'darwin'",
|
||||
]
|
||||
|
||||
[options]
|
||||
exclude-newer = "2024-03-25T00:00:00Z"
|
||||
|
||||
[[package]]
|
||||
name = "numpy"
|
||||
version = "1.26.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/75/5b/ca6c8bd14007e5ca171c7c03102d17b4f4e0ceb53957e8c44343a9546dcc/numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b", size = 13685868, upload-time = "2024-02-05T23:55:56.28Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/50/de23fde84e45f5c4fda2488c759b69990fd4512387a8632860f3ac9cd225/numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed", size = 17950613, upload-time = "2024-02-05T23:56:56.054Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/76/8c/2ba3902e1a0fc1c74962ea9bb33a534bb05984ad7ff9515bf8d07527cadd/numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0", size = 17786643, upload-time = "2024-02-05T23:57:56.585Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "numpy", marker = "(platform_machine == 'arm64' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and sys_platform == 'linux')" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [{ name = "numpy" }]
|
||||
"#
|
||||
);
|
||||
});
|
||||
|
||||
// Re-run with `--locked`.
|
||||
uv_snapshot!(context.filters(), context.lock().arg("--locked"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 2 packages in [TIME]
|
||||
");
|
||||
|
||||
// Re-run with `--offline`. We shouldn't need a network connection to validate an
|
||||
// already-correct lockfile with immutable metadata.
|
||||
uv_snapshot!(context.filters(), context.lock().arg("--locked").arg("--offline").arg("--no-cache"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 2 packages in [TIME]
|
||||
"###);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue