mirror of
https://github.com/astral-sh/uv.git
synced 2025-09-15 06:55:14 +00:00
Collapse extras on dev dependencies (#6383)
## Summary It turns out we weren't applying the collapse logic here, so dev deps with extras were repeated. This was generally ok... unless we ended up _dropping_ an extra, in which case, you now have a duplicate. Closes https://github.com/astral-sh/uv/issues/6380.
This commit is contained in:
parent
7d90c29552
commit
19a7f3ec07
4 changed files with 133 additions and 15 deletions
|
@ -1154,10 +1154,15 @@ impl Package {
|
|||
annotated_dist: &AnnotatedDist,
|
||||
marker: MarkerTree,
|
||||
) {
|
||||
self.optional_dependencies
|
||||
.entry(extra)
|
||||
.or_default()
|
||||
.push(Dependency::from_annotated_dist(annotated_dist, marker));
|
||||
let dep = Dependency::from_annotated_dist(annotated_dist, marker);
|
||||
let optional_deps = self.optional_dependencies.entry(extra).or_default();
|
||||
for existing_dep in &mut *optional_deps {
|
||||
if existing_dep.package_id == dep.package_id && existing_dep.marker == dep.marker {
|
||||
existing_dep.extra.extend(dep.extra);
|
||||
return;
|
||||
}
|
||||
}
|
||||
optional_deps.push(dep);
|
||||
}
|
||||
|
||||
/// Add the [`AnnotatedDist`] as a development dependency of the [`Package`].
|
||||
|
@ -1167,10 +1172,15 @@ impl Package {
|
|||
annotated_dist: &AnnotatedDist,
|
||||
marker: MarkerTree,
|
||||
) {
|
||||
self.dev_dependencies
|
||||
.entry(dev)
|
||||
.or_default()
|
||||
.push(Dependency::from_annotated_dist(annotated_dist, marker));
|
||||
let dep = Dependency::from_annotated_dist(annotated_dist, marker);
|
||||
let dev_deps = self.dev_dependencies.entry(dev).or_default();
|
||||
for existing_dep in &mut *dev_deps {
|
||||
if existing_dep.package_id == dep.package_id && existing_dep.marker == dep.marker {
|
||||
existing_dep.extra.extend(dep.extra);
|
||||
return;
|
||||
}
|
||||
}
|
||||
dev_deps.push(dep);
|
||||
}
|
||||
|
||||
/// Convert the [`Package`] to a [`Dist`] that can be used in installation.
|
||||
|
|
|
@ -7890,7 +7890,6 @@ fn lock_transitive_extra() -> Result<()> {
|
|||
|
||||
[package.optional-dependencies]
|
||||
async = [
|
||||
{ name = "leaf" },
|
||||
{ name = "leaf", extra = ["async"] },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
|
@ -10306,3 +10305,118 @@ fn lock_virtual() -> Result<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// `coverage` defines a `toml` extra, but it doesn't enable any dependencies after Python 3.11.
|
||||
#[test]
|
||||
fn lock_dropped_dev_extra() -> 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"
|
||||
|
||||
[tool.uv]
|
||||
dev-dependencies = [
|
||||
"coverage[toml]"
|
||||
]
|
||||
"#,
|
||||
)?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.lock(), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 2 packages in [TIME]
|
||||
"###);
|
||||
|
||||
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();
|
||||
|
||||
insta::with_settings!({
|
||||
filters => context.filters(),
|
||||
}, {
|
||||
assert_snapshot!(
|
||||
lock, @r###"
|
||||
version = 1
|
||||
requires-python = ">=3.12"
|
||||
|
||||
[options]
|
||||
exclude-newer = "2024-03-25T00:00:00Z"
|
||||
|
||||
[[package]]
|
||||
name = "coverage"
|
||||
version = "7.4.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/bf/d5/f809d8b630cf4c11fe490e20037a343d12a74ec2783c6cdb5aee725e7137/coverage-7.4.4.tar.gz", hash = "sha256:c901df83d097649e257e803be22592aedfd5182f07b3cc87d640bbb9afd50f49", size = 783727 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a0/de/a54b245e781bfd6f3fd7ce5566a695686b5c25ee7c743f514e7634428972/coverage-7.4.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:201bef2eea65e0e9c56343115ba3814e896afe6d36ffd37bab783261db430f76", size = 206409 },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/92/07f9c593cd27e3c595b8cb83b95adad8c9ba3d611debceed097a5fd6be4b/coverage-7.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41c9c5f3de16b903b610d09650e5e27adbfa7f500302718c9ffd1c12cf9d6818", size = 206568 },
|
||||
{ url = "https://files.pythonhosted.org/packages/41/6d/e142c823e5d4b24481f990da4cf9d2d577a6f4e1fb6faf39d9a4e42b1d43/coverage-7.4.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d898fe162d26929b5960e4e138651f7427048e72c853607f2b200909794ed978", size = 238920 },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/1a/105f0139df6a2adbcaa0c110711a46dbd9f59e93a09ca15a97d59c2564f2/coverage-7.4.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ea79bb50e805cd6ac058dfa3b5c8f6c040cb87fe83de10845857f5535d1db70", size = 236288 },
|
||||
{ url = "https://files.pythonhosted.org/packages/98/79/185cb42910b6a2b2851980407c8445ac0da0750dff65e420e86f973c8396/coverage-7.4.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce4b94265ca988c3f8e479e741693d143026632672e3ff924f25fab50518dd51", size = 238223 },
|
||||
{ url = "https://files.pythonhosted.org/packages/92/12/2303d1c543a11ea060dbc7144ed3174fc09107b5dd333649415c95ede58b/coverage-7.4.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:00838a35b882694afda09f85e469c96367daa3f3f2b097d846a7216993d37f4c", size = 245161 },
|
||||
{ url = "https://files.pythonhosted.org/packages/96/5a/7d0e945c4759fe9d19aad1679dd3096aeb4cb9fcf0062fe24554dc4787b8/coverage-7.4.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fdfafb32984684eb03c2d83e1e51f64f0906b11e64482df3c5db936ce3839d48", size = 243066 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/1b/79cdb7b11bbbd6540a536ac79412904b5c1f8903d5c1330084212afa8ceb/coverage-7.4.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:69eb372f7e2ece89f14751fbcbe470295d73ed41ecd37ca36ed2eb47512a6ab9", size = 244805 },
|
||||
{ url = "https://files.pythonhosted.org/packages/af/7f/54dc676e7e63549838a3a7b95a8e11df80441bf7d64c6ce8f1cdbc0d1ff0/coverage-7.4.4-cp312-cp312-win32.whl", hash = "sha256:137eb07173141545e07403cca94ab625cc1cc6bc4c1e97b6e3846270e7e1fea0", size = 208590 },
|
||||
{ url = "https://files.pythonhosted.org/packages/46/c4/1dfe76d96034a347d717a2392b004d42d45934cb94efa362ad41ca871f6e/coverage-7.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:d71eec7d83298f1af3326ce0ff1d0ea83c7cb98f72b577097f9083b20bdaf05e", size = 209415 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
source = { editable = "." }
|
||||
|
||||
[package.dev-dependencies]
|
||||
dev = [
|
||||
{ name = "coverage" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
|
||||
[package.metadata.requires-dev]
|
||||
dev = [{ name = "coverage", extras = ["toml"] }]
|
||||
"###
|
||||
);
|
||||
});
|
||||
|
||||
// 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]
|
||||
"###);
|
||||
|
||||
// Install from the lockfile.
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--frozen"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Prepared 2 packages in [TIME]
|
||||
Installed 2 packages in [TIME]
|
||||
+ coverage==7.4.4
|
||||
+ project==0.1.0 (from file://[TEMP_DIR]/)
|
||||
"###);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -5443,7 +5443,6 @@ all = [
|
|||
{ name = "pillow" },
|
||||
{ name = "protobuf" },
|
||||
{ name = "pyctcdecode" },
|
||||
{ name = "ray" },
|
||||
{ name = "ray", extra = ["tune"] },
|
||||
{ name = "sentencepiece" },
|
||||
{ name = "sigopt" },
|
||||
|
@ -5542,7 +5541,6 @@ dev-dependencies = [
|
|||
{ name = "pytest" },
|
||||
{ name = "pytest-timeout" },
|
||||
{ name = "pytest-xdist" },
|
||||
{ name = "ray" },
|
||||
{ name = "ray", extra = ["tune"] },
|
||||
{ name = "rhoknp" },
|
||||
{ name = "rjieba" },
|
||||
|
@ -5592,7 +5590,6 @@ docs = [
|
|||
{ name = "pillow" },
|
||||
{ name = "protobuf" },
|
||||
{ name = "pyctcdecode" },
|
||||
{ name = "ray" },
|
||||
{ name = "ray", extra = ["tune"] },
|
||||
{ name = "sentencepiece" },
|
||||
{ name = "sigopt" },
|
||||
|
@ -5628,7 +5625,6 @@ ftfy = [
|
|||
]
|
||||
integrations = [
|
||||
{ name = "optuna" },
|
||||
{ name = "ray" },
|
||||
{ name = "ray", extra = ["tune"] },
|
||||
{ name = "sigopt" },
|
||||
]
|
||||
|
@ -5668,7 +5664,6 @@ quality = [
|
|||
{ name = "urllib3" },
|
||||
]
|
||||
ray = [
|
||||
{ name = "ray" },
|
||||
{ name = "ray", extra = ["tune"] },
|
||||
]
|
||||
retrieval = [
|
||||
|
|
|
@ -491,7 +491,6 @@ wheels = [
|
|||
[package.optional-dependencies]
|
||||
sqs = [
|
||||
{ name = "boto3" },
|
||||
{ name = "kombu" },
|
||||
{ name = "kombu", extra = ["sqs"] },
|
||||
{ name = "pycurl", marker = "platform_python_implementation == 'CPython' and sys_platform != 'win32'" },
|
||||
{ name = "urllib3" },
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue