mirror of
https://github.com/astral-sh/uv
synced 2026-01-21 13:30:11 -05:00
Rebuild dynamic distribution when version changes with --no-cache (#17387)
## Summary Well-explained in https://github.com/astral-sh/uv/issues/17370. I don't see a reason _not_ to fix this. Closes https://github.com/astral-sh/uv/issues/17370.
This commit is contained in:
@@ -126,6 +126,7 @@ impl<'a> Planner<'a> {
|
||||
dist.name(),
|
||||
installed,
|
||||
&source,
|
||||
dist.version(),
|
||||
installation,
|
||||
tags,
|
||||
config_settings,
|
||||
|
||||
@@ -15,6 +15,7 @@ use uv_distribution_types::{
|
||||
};
|
||||
use uv_git_types::{GitLfs, GitOid};
|
||||
use uv_normalize::PackageName;
|
||||
use uv_pep440::Version;
|
||||
use uv_platform_tags::{IncompatibleTag, TagCompatibility, Tags};
|
||||
use uv_pypi_types::{DirInfo, DirectUrl, VcsInfo, VcsKind};
|
||||
|
||||
@@ -36,6 +37,7 @@ impl RequirementSatisfaction {
|
||||
name: &PackageName,
|
||||
distribution: &InstalledDist,
|
||||
source: &RequirementSource,
|
||||
version: Option<&Version>,
|
||||
installation: InstallationStrategy,
|
||||
tags: &Tags,
|
||||
config_settings: &ConfigSettings,
|
||||
@@ -358,6 +360,21 @@ impl RequirementSatisfaction {
|
||||
}
|
||||
}
|
||||
|
||||
// If a resolved version is provided, check that it matches the installed version.
|
||||
// This is needed for sources that don't include explicit version specifiers (e.g.,
|
||||
// directory dependencies with dynamic versioning), where the resolver may have determined
|
||||
// a new version should be installed.
|
||||
if let Some(version) = version {
|
||||
if distribution.version() != version {
|
||||
debug!(
|
||||
"Installed version does not match resolved version for {name}: {} vs. {}",
|
||||
distribution.version(),
|
||||
version
|
||||
);
|
||||
return Self::OutOfDate;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, assume the requirement is up-to-date.
|
||||
Self::Satisfied
|
||||
}
|
||||
|
||||
@@ -485,6 +485,7 @@ impl SitePackages {
|
||||
name,
|
||||
distribution,
|
||||
&requirement.source,
|
||||
None,
|
||||
installation,
|
||||
tags,
|
||||
config_settings,
|
||||
@@ -508,6 +509,7 @@ impl SitePackages {
|
||||
name,
|
||||
distribution,
|
||||
&constraint.source,
|
||||
None,
|
||||
installation,
|
||||
tags,
|
||||
config_settings,
|
||||
|
||||
@@ -15376,3 +15376,113 @@ fn sync_fails_ambiguous_url() -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Test that when a local directory dependency's version changes, the planner reinstalls it
|
||||
/// even if the source directory content (cache info) hasn't changed.
|
||||
///
|
||||
/// Regression test for: <https://github.com/astral-sh/uv/issues/17370>
|
||||
#[test]
|
||||
fn sync_reinstalls_on_version_change() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
// Create a workspace with a local directory dependency.
|
||||
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 = ["child"]
|
||||
|
||||
[tool.uv.sources]
|
||||
child = { path = "packages/child" }
|
||||
"#,
|
||||
)?;
|
||||
|
||||
// Create the child package with version 0.1.0.
|
||||
let child = context.temp_dir.child("packages/child");
|
||||
child.create_dir_all()?;
|
||||
child.child("pyproject.toml").write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "child"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
"#,
|
||||
)?;
|
||||
child
|
||||
.child("src")
|
||||
.child("child")
|
||||
.child("__init__.py")
|
||||
.touch()?;
|
||||
|
||||
// Lock and sync (installs child v0.1.0).
|
||||
uv_snapshot!(context.filters(), context.lock(), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 2 packages in [TIME]
|
||||
");
|
||||
|
||||
uv_snapshot!(context.filters(), context.sync(), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 2 packages in [TIME]
|
||||
Prepared 1 package in [TIME]
|
||||
Installed 1 package in [TIME]
|
||||
+ child==0.1.0 (from file://[TEMP_DIR]/packages/child)
|
||||
");
|
||||
|
||||
// Now bump the child's version to 0.1.1.
|
||||
child.child("pyproject.toml").write_str(
|
||||
r#"
|
||||
[project]
|
||||
name = "child"
|
||||
version = "0.1.1"
|
||||
requires-python = ">=3.12"
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
"#,
|
||||
)?;
|
||||
|
||||
// Lock again; lockfile should show v0.1.1.
|
||||
uv_snapshot!(context.filters(), context.lock(), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 2 packages in [TIME]
|
||||
Updated child v0.1.0 -> v0.1.1
|
||||
");
|
||||
|
||||
// Sync should reinstall child with the new version. Before the fix for #17370,
|
||||
// this would incorrectly say "Audited 2 packages" and not reinstall the child package.
|
||||
uv_snapshot!(context.filters(), context.sync(), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 2 packages in [TIME]
|
||||
Prepared 1 package in [TIME]
|
||||
Uninstalled 1 package in [TIME]
|
||||
Installed 1 package in [TIME]
|
||||
- child==0.1.0 (from file://[TEMP_DIR]/packages/child)
|
||||
+ child==0.1.1 (from file://[TEMP_DIR]/packages/child)
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user