Avoid reading stale .egg-info from mutable sources (#6714)

## Summary

In theory this problem already existed for `PKG-INFO`, but `egg-info`
would be more common, I think, since it's built in the source tree.

Closes https://github.com/astral-sh/uv/issues/6712.
This commit is contained in:
Charlie Marsh 2024-08-27 15:23:26 -04:00 committed by GitHub
parent a999303d2f
commit 14074f8775
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 88 additions and 0 deletions

View file

@ -56,6 +56,14 @@ impl BuildableSource<'_> {
Self::Url(url) => url.is_editable(), Self::Url(url) => url.is_editable(),
} }
} }
/// Return true if the source refers to a local source tree (i.e., a directory).
pub fn is_source_tree(&self) -> bool {
match self {
Self::Dist(dist) => matches!(dist, SourceDist::Directory(_)),
Self::Url(url) => matches!(url, SourceUrl::Directory(_)),
}
}
} }
impl std::fmt::Display for BuildableSource<'_> { impl std::fmt::Display for BuildableSource<'_> {
@ -94,6 +102,11 @@ impl<'a> SourceUrl<'a> {
Self::Directory(DirectorySourceUrl { editable: true, .. }) Self::Directory(DirectorySourceUrl { editable: true, .. })
) )
} }
/// Return true if the source refers to a local file or directory.
pub fn is_local(&self) -> bool {
matches!(self, Self::Path(_) | Self::Directory(_))
}
} }
impl std::fmt::Display for SourceUrl<'_> { impl std::fmt::Display for SourceUrl<'_> {

View file

@ -1529,6 +1529,12 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
Err(err) => return Err(err), Err(err) => return Err(err),
} }
// If the source distribution is a source tree, avoid reading `PKG-INFO` or `egg-info`,
// since they could be out-of-date.
if source.is_source_tree() {
return Ok(None);
}
// Attempt to read static metadata from the `PKG-INFO` file. // Attempt to read static metadata from the `PKG-INFO` file.
match read_pkg_info(source_root, subdirectory).await { match read_pkg_info(source_root, subdirectory).await {
Ok(metadata) => { Ok(metadata) => {

View file

@ -6386,3 +6386,72 @@ fn switch_platform() -> Result<()> {
Ok(()) Ok(())
} }
/// See: <https://github.com/astral-sh/uv/pull/6714>
#[test]
fn stale_egg_info() -> Result<()> {
let context = TestContext::new("3.12");
// Create a project with dynamic metadata (version).
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(indoc! {r#"
[project]
name = "project"
dynamic = ["version"]
dependencies = ["iniconfig"]
"#
})?;
uv_snapshot!(context.filters(), context.pip_install()
.arg("-e")
.arg("."), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 2 packages in [TIME]
Prepared 2 packages in [TIME]
Installed 2 packages in [TIME]
+ iniconfig==2.0.0
+ project==0.0.0 (from file://[TEMP_DIR]/)
"###
);
// Ensure that `.egg-info` exists.
let egg_info = context.temp_dir.child("project.egg-info");
egg_info.assert(predicates::path::is_dir());
// Change the metadata.
pyproject_toml.write_str(indoc! {r#"
[project]
name = "project"
dynamic = ["version"]
dependencies = ["anyio"]
"#
})?;
// Reinstall. Ensure that the metadata is updated.
uv_snapshot!(context.filters(), context.pip_install()
.arg("-e")
.arg("."), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 4 packages in [TIME]
Prepared 4 packages in [TIME]
Uninstalled 1 package in [TIME]
Installed 4 packages in [TIME]
+ anyio==4.3.0
+ idna==3.6
~ project==0.0.0 (from file://[TEMP_DIR]/)
+ sniffio==1.3.1
"###
);
Ok(())
}