mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-10 02:22:08 +00:00
Include wheel hashes from local Simple indexes (#14993)
## Summary This just looks like an oversight. We weren't including hashes from local Simple API indexes if a package had both a wheel and a source distribution. Closes https://github.com/astral-sh/uv/issues/14883
This commit is contained in:
parent
538ebe6fcf
commit
fa24d9a5e2
4 changed files with 66 additions and 69 deletions
|
@ -4396,27 +4396,12 @@ impl Wheel {
|
|||
}
|
||||
|
||||
fn from_registry_wheel(wheel: &RegistryBuiltWheel) -> Result<Wheel, LockError> {
|
||||
let filename = wheel.filename.clone();
|
||||
match &wheel.index {
|
||||
let url = match &wheel.index {
|
||||
IndexUrl::Pypi(_) | IndexUrl::Url(_) => {
|
||||
let url = normalize_file_location(&wheel.file.url)
|
||||
.map_err(LockErrorKind::InvalidUrl)
|
||||
.map_err(LockError::from)?;
|
||||
let hash = wheel.file.hashes.iter().max().cloned().map(Hash::from);
|
||||
let size = wheel.file.size;
|
||||
let upload_time = wheel
|
||||
.file
|
||||
.upload_time_utc_ms
|
||||
.map(Timestamp::from_millisecond)
|
||||
.transpose()
|
||||
.map_err(LockErrorKind::InvalidTimestamp)?;
|
||||
Ok(Wheel {
|
||||
url: WheelWireSource::Url { url },
|
||||
hash,
|
||||
size,
|
||||
filename,
|
||||
upload_time,
|
||||
})
|
||||
WheelWireSource::Url { url }
|
||||
}
|
||||
IndexUrl::Path(path) => {
|
||||
let index_path = path
|
||||
|
@ -4432,35 +4417,31 @@ impl Wheel {
|
|||
.or_else(|_| std::path::absolute(&wheel_path))
|
||||
.map_err(LockErrorKind::DistributionRelativePath)?
|
||||
.into_boxed_path();
|
||||
Ok(Wheel {
|
||||
url: WheelWireSource::Path { path },
|
||||
hash: None,
|
||||
size: None,
|
||||
upload_time: None,
|
||||
filename,
|
||||
})
|
||||
WheelWireSource::Path { path }
|
||||
} else {
|
||||
let url = normalize_file_location(&wheel.file.url)
|
||||
.map_err(LockErrorKind::InvalidUrl)
|
||||
.map_err(LockError::from)?;
|
||||
let hash = wheel.file.hashes.iter().max().cloned().map(Hash::from);
|
||||
let size = wheel.file.size;
|
||||
let upload_time = wheel
|
||||
.file
|
||||
.upload_time_utc_ms
|
||||
.map(Timestamp::from_millisecond)
|
||||
.transpose()
|
||||
.map_err(LockErrorKind::InvalidTimestamp)?;
|
||||
Ok(Wheel {
|
||||
url: WheelWireSource::Url { url },
|
||||
hash,
|
||||
size,
|
||||
filename,
|
||||
upload_time,
|
||||
})
|
||||
WheelWireSource::Url { url }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
let filename = wheel.filename.clone();
|
||||
let hash = wheel.file.hashes.iter().max().cloned().map(Hash::from);
|
||||
let size = wheel.file.size;
|
||||
let upload_time = wheel
|
||||
.file
|
||||
.upload_time_utc_ms
|
||||
.map(Timestamp::from_millisecond)
|
||||
.transpose()
|
||||
.map_err(LockErrorKind::InvalidTimestamp)?;
|
||||
Ok(Wheel {
|
||||
url,
|
||||
hash,
|
||||
size,
|
||||
upload_time,
|
||||
filename,
|
||||
})
|
||||
}
|
||||
|
||||
fn from_direct_dist(direct_dist: &DirectUrlBuiltDist, hashes: &[HashDigest]) -> Wheel {
|
||||
|
|
|
@ -10434,23 +10434,31 @@ fn lock_find_links_lower_priority_index() -> Result<()> {
|
|||
/// Lock against a local directory laid out as a PEP 503-compatible index.
|
||||
#[test]
|
||||
fn lock_local_index() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
let context = TestContext::new("3.13");
|
||||
|
||||
let root = context.temp_dir.child("simple-html");
|
||||
fs_err::create_dir_all(&root)?;
|
||||
|
||||
let tqdm = root.child("tqdm");
|
||||
fs_err::create_dir_all(&tqdm)?;
|
||||
let basic_package = root.child("basic-package");
|
||||
fs_err::create_dir_all(&basic_package)?;
|
||||
|
||||
let wheel = tqdm.child("tqdm-1000.0.0-py3-none-any.whl");
|
||||
let sdist = basic_package.child("basic_package-0.1.0.tar.gz");
|
||||
fs_err::copy(
|
||||
context
|
||||
.workspace_root
|
||||
.join("scripts/links/tqdm-1000.0.0-py3-none-any.whl"),
|
||||
.join("scripts/links/basic_package-0.1.0.tar.gz"),
|
||||
&sdist,
|
||||
)?;
|
||||
|
||||
let wheel = basic_package.child("basic_package-0.1.0-py3-none-any.whl");
|
||||
fs_err::copy(
|
||||
context
|
||||
.workspace_root
|
||||
.join("scripts/links/basic_package-0.1.0-py3-none-any.whl"),
|
||||
&wheel,
|
||||
)?;
|
||||
|
||||
let index = tqdm.child("index.html");
|
||||
let index = basic_package.child("index.html");
|
||||
index.write_str(&formatdoc! {r#"
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
@ -10458,26 +10466,33 @@ fn lock_local_index() -> Result<()> {
|
|||
<meta name="pypi:repository-version" content="1.1" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Links for tqdm</h1>
|
||||
<h1>Links for basic-package</h1>
|
||||
<a
|
||||
href="{}"
|
||||
data-requires-python=">=3.8"
|
||||
href="{}#sha256=7b6229db79b5800e4e98a351b5628c1c8a944533a2d428aeeaa7275a30d4ea82"
|
||||
data-requires-python=">=3.13"
|
||||
>
|
||||
tqdm-1000.0.0-py3-none-any.whl
|
||||
basic_package-0.1.0-py3-none-any.whl
|
||||
</a>
|
||||
<a
|
||||
href="{}#sha256=af478ff91ec60856c99a540b8df13d756513bebb65bc301fb27e0d1f974532b4"
|
||||
data-requires-python=">=3.13"
|
||||
>
|
||||
basic_package-0.1.0.tar.gz
|
||||
</a>
|
||||
</body>
|
||||
</html>
|
||||
"#, Url::from_file_path(wheel).unwrap().as_str()})?;
|
||||
|
||||
let context = TestContext::new("3.12");
|
||||
"#,
|
||||
Url::from_file_path(wheel).unwrap().as_str(),
|
||||
Url::from_file_path(sdist).unwrap().as_str(),
|
||||
})?;
|
||||
|
||||
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||
pyproject_toml.write_str(&formatdoc! { r#"
|
||||
[project]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = ["tqdm"]
|
||||
requires-python = ">=3.13"
|
||||
dependencies = ["basic-package"]
|
||||
|
||||
[tool.uv]
|
||||
extra-index-url = ["{}"]
|
||||
|
@ -10509,26 +10524,27 @@ fn lock_local_index() -> Result<()> {
|
|||
lock, @r#"
|
||||
version = 1
|
||||
revision = 3
|
||||
requires-python = ">=3.12"
|
||||
requires-python = ">=3.13"
|
||||
|
||||
[[package]]
|
||||
name = "basic-package"
|
||||
version = "0.1.0"
|
||||
source = { registry = "simple-html" }
|
||||
sdist = { path = "basic-package/basic_package-0.1.0.tar.gz", hash = "sha256:af478ff91ec60856c99a540b8df13d756513bebb65bc301fb27e0d1f974532b4" }
|
||||
wheels = [
|
||||
{ path = "basic-package/basic_package-0.1.0-py3-none-any.whl", hash = "sha256:7b6229db79b5800e4e98a351b5628c1c8a944533a2d428aeeaa7275a30d4ea82" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "tqdm" },
|
||||
{ name = "basic-package" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [{ name = "tqdm" }]
|
||||
|
||||
[[package]]
|
||||
name = "tqdm"
|
||||
version = "1000.0.0"
|
||||
source = { registry = "../../[TMP]/simple-html" }
|
||||
wheels = [
|
||||
{ path = "tqdm/tqdm-1000.0.0-py3-none-any.whl" },
|
||||
]
|
||||
requires-dist = [{ name = "basic-package" }]
|
||||
"#
|
||||
);
|
||||
});
|
||||
|
@ -10544,7 +10560,7 @@ fn lock_local_index() -> Result<()> {
|
|||
"###);
|
||||
|
||||
// Install from the lockfile.
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--frozen").env_remove(EnvVars::UV_EXCLUDE_NEWER), @r###"
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--frozen").env_remove(EnvVars::UV_EXCLUDE_NEWER), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
@ -10552,8 +10568,8 @@ fn lock_local_index() -> Result<()> {
|
|||
----- stderr -----
|
||||
Prepared 1 package in [TIME]
|
||||
Installed 1 package in [TIME]
|
||||
+ tqdm==1000.0.0
|
||||
"###);
|
||||
+ basic-package==0.1.0
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
BIN
scripts/links/basic_package-0.1.0-py3-none-any.whl
Normal file
BIN
scripts/links/basic_package-0.1.0-py3-none-any.whl
Normal file
Binary file not shown.
BIN
scripts/links/basic_package-0.1.0.tar.gz
Normal file
BIN
scripts/links/basic_package-0.1.0.tar.gz
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue