Avoid erroring on omitted wheel-only packages in `pylock.toml` (#13132)

## Summary

Closes https://github.com/astral-sh/uv/issues/13127.
This commit is contained in:
Charlie Marsh 2025-04-27 11:58:20 -04:00 committed by GitHub
parent 1cafcd0ad9
commit 17b4ebed8e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 97 additions and 9 deletions

View File

@ -62,6 +62,8 @@ pub enum PylockTomlError {
"Package `{0}` must include one of: `wheels`, `directory`, `archive`, `sdist`, or `vcs`"
)]
MissingSource(PackageName),
#[error("Package `{0}` does not include a compatible wheel for the current platform")]
MissingWheel(PackageName),
#[error("`packages.wheel` entry for `{0}` must have a `path` or `url`")]
WheelMissingPathUrl(PackageName),
#[error("`packages.sdist` entry for `{0}` must have a `path` or `url`")]
@ -863,6 +865,11 @@ impl<'lock> PylockToml {
let root = graph.add_node(Node::Root);
for package in self.packages {
// Omit packages that aren't relevant to the current environment.
if !package.marker.evaluate(markers, &[]) {
continue;
}
match (
package.wheels.is_some(),
package.sdist.is_some(),
@ -901,12 +908,12 @@ impl<'lock> PylockToml {
(_, _, _, true, true) => {
return Err(PylockTomlError::VcsWithArchive(package.name.clone()));
}
(false, false, false, false, false) => {
return Err(PylockTomlError::MissingSource(package.name.clone()));
}
_ => {}
}
// Omit packages that aren't relevant to the current environment.
let install = package.marker.evaluate(markers, &[]);
// Search for a matching wheel.
let dist = if let Some(best_wheel) = package.find_best_wheel(tags) {
let hashes = HashDigests::from(best_wheel.hashes.clone());
@ -926,7 +933,7 @@ impl<'lock> PylockToml {
Node::Dist {
dist,
hashes,
install,
install: true,
}
} else if let Some(sdist) = package.sdist.as_ref() {
let hashes = HashDigests::from(sdist.hashes.clone());
@ -943,7 +950,7 @@ impl<'lock> PylockToml {
Node::Dist {
dist,
hashes,
install,
install: true,
}
} else if let Some(sdist) = package.directory.as_ref() {
let hashes = HashDigests::empty();
@ -957,7 +964,7 @@ impl<'lock> PylockToml {
Node::Dist {
dist,
hashes,
install,
install: true,
}
} else if let Some(sdist) = package.vcs.as_ref() {
let hashes = HashDigests::empty();
@ -971,7 +978,7 @@ impl<'lock> PylockToml {
Node::Dist {
dist,
hashes,
install,
install: true,
}
} else if let Some(dist) = package.archive.as_ref() {
let hashes = HashDigests::from(dist.hashes.clone());
@ -983,10 +990,16 @@ impl<'lock> PylockToml {
Node::Dist {
dist,
hashes,
install,
install: true,
}
} else {
return Err(PylockTomlError::MissingSource(package.name.clone()));
// This is only reachable if the package contains a `wheels` entry (and nothing
// else), but there are no wheels available for the current environment. (If the
// package doesn't contain _any_ of `wheels`, `sdist`, etc., then we error in the
// match above.)
//
// TODO(charlie): Include a hint, like in `uv.lock`.
return Err(PylockTomlError::MissingWheel(package.name.clone()));
};
let index = graph.add_node(dist);

View File

@ -5822,3 +5822,78 @@ fn pep_751() -> Result<()> {
Ok(())
}
/// Avoid erroring for packages that only include wheels, and _don't_ include a wheel for the
/// current platform, but are omitted by markers anyway.
///
/// See: <https://github.com/astral-sh/uv/issues/13127>
#[test]
fn pep_751_wheel_only() -> 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.0"
dependencies = ["torch"]
"#,
)?;
context
.export()
.arg("-o")
.arg("pylock.toml")
.assert()
.success();
// If there's no compatible wheel for a package we _don't_ need to install (e.g., anything
// CUDA-related), succeed.
uv_snapshot!(context.filters(), context.pip_sync()
.arg("--preview")
.arg("pylock.toml")
.arg("--dry-run")
.arg("--python-platform")
.arg("macos"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Would download 9 packages
Would install 9 packages
+ filelock==3.13.1
+ fsspec==2024.3.1
+ jinja2==3.1.3
+ markupsafe==2.1.5
+ mpmath==1.3.0
+ networkx==3.2.1
+ sympy==1.12
+ torch==2.2.1
+ typing-extensions==4.10.0
"
);
// However, if there's no compatible wheel for a package that we _do_ need to install, we should
// error
uv_snapshot!(context.filters(), context.pip_sync()
.arg("--preview")
.arg("pylock.toml")
.arg("--dry-run")
.arg("--python-platform")
.arg("macos")
.arg("--python-version")
.arg("3.8"), @r"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: Package `torch` does not include a compatible wheel for the current platform
"
);
Ok(())
}