mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-14 12:29:04 +00:00
Sort dependency group keys when adding new group (#11591)
This change keeps dependency group keys sorted when adding new ones. If earlier dependency group keys were not sorted, we just append the new group key to avoid churn in `pyproject.toml`. See discussion on #11447. I've added a new snapshot test to capture this case. Closes #11447.
This commit is contained in:
parent
555bf89b38
commit
b086437bff
2 changed files with 256 additions and 21 deletions
|
@ -450,6 +450,13 @@ impl PyProjectTomlMut {
|
|||
.as_table_like_mut()
|
||||
.ok_or(Error::MalformedDependencies)?;
|
||||
|
||||
let was_sorted = dependency_groups
|
||||
.get_values()
|
||||
.iter()
|
||||
.filter_map(|(dotted_ks, _)| dotted_ks.first())
|
||||
.map(|k| k.get())
|
||||
.is_sorted();
|
||||
|
||||
let group = dependency_groups
|
||||
.entry(group.as_ref())
|
||||
.or_insert(Item::Value(Value::Array(Array::new())))
|
||||
|
@ -459,6 +466,12 @@ impl PyProjectTomlMut {
|
|||
let name = req.name.clone();
|
||||
let added = add_dependency(req, group, source.is_some())?;
|
||||
|
||||
// To avoid churn in pyproject.toml, we only sort new group keys if the
|
||||
// existing keys were sorted.
|
||||
if was_sorted {
|
||||
dependency_groups.sort_values();
|
||||
}
|
||||
|
||||
// If `dependency-groups` is an inline table, reformat it.
|
||||
//
|
||||
// Reformatting can drop comments between keys, but you can't put comments
|
||||
|
|
|
@ -4758,11 +4758,7 @@ fn add_group() -> Result<()> {
|
|||
|
||||
let pyproject_toml = context.read("pyproject.toml");
|
||||
|
||||
insta::with_settings!({
|
||||
filters => context.filters(),
|
||||
}, {
|
||||
assert_snapshot!(
|
||||
pyproject_toml, @r###"
|
||||
assert_snapshot!(pyproject_toml, @r###"
|
||||
[project]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
|
@ -4774,8 +4770,7 @@ fn add_group() -> Result<()> {
|
|||
"anyio==3.7.0",
|
||||
]
|
||||
"###
|
||||
);
|
||||
});
|
||||
);
|
||||
|
||||
uv_snapshot!(context.filters(), context.add().arg("requests").arg("--group").arg("test"), @r###"
|
||||
success: true
|
||||
|
@ -4794,11 +4789,7 @@ fn add_group() -> Result<()> {
|
|||
|
||||
let pyproject_toml = context.read("pyproject.toml");
|
||||
|
||||
insta::with_settings!({
|
||||
filters => context.filters(),
|
||||
}, {
|
||||
assert_snapshot!(
|
||||
pyproject_toml, @r###"
|
||||
assert_snapshot!(pyproject_toml, @r###"
|
||||
[project]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
|
@ -4811,8 +4802,7 @@ fn add_group() -> Result<()> {
|
|||
"requests>=2.31.0",
|
||||
]
|
||||
"###
|
||||
);
|
||||
});
|
||||
);
|
||||
|
||||
uv_snapshot!(context.filters(), context.add().arg("anyio==3.7.0").arg("--group").arg("second"), @r###"
|
||||
success: true
|
||||
|
@ -4826,11 +4816,208 @@ fn add_group() -> Result<()> {
|
|||
|
||||
let pyproject_toml = context.read("pyproject.toml");
|
||||
|
||||
insta::with_settings!({
|
||||
filters => context.filters(),
|
||||
}, {
|
||||
assert_snapshot!(
|
||||
pyproject_toml, @r###"
|
||||
assert_snapshot!(pyproject_toml, @r#"
|
||||
[project]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = []
|
||||
|
||||
[dependency-groups]
|
||||
second = [
|
||||
"anyio==3.7.0",
|
||||
]
|
||||
test = [
|
||||
"anyio==3.7.0",
|
||||
"requests>=2.31.0",
|
||||
]
|
||||
"#
|
||||
);
|
||||
|
||||
uv_snapshot!(context.filters(), context.add().arg("anyio==3.7.0").arg("--group").arg("alpha"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 8 packages in [TIME]
|
||||
Audited 3 packages in [TIME]
|
||||
"###);
|
||||
|
||||
let pyproject_toml = context.read("pyproject.toml");
|
||||
|
||||
assert_snapshot!(pyproject_toml, @r#"
|
||||
[project]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = []
|
||||
|
||||
[dependency-groups]
|
||||
alpha = [
|
||||
"anyio==3.7.0",
|
||||
]
|
||||
second = [
|
||||
"anyio==3.7.0",
|
||||
]
|
||||
test = [
|
||||
"anyio==3.7.0",
|
||||
"requests>=2.31.0",
|
||||
]
|
||||
"#
|
||||
);
|
||||
|
||||
assert!(context.temp_dir.join("uv.lock").exists());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Add a requirement to a dependency group (sorted before the other groups).
|
||||
#[test]
|
||||
fn add_group_before_commented_groups() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||
pyproject_toml.write_str(indoc! {r#"
|
||||
[project]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = []
|
||||
|
||||
[dependency-groups]
|
||||
# This is our dev group
|
||||
dev = [
|
||||
"anyio==3.7.0",
|
||||
]
|
||||
# This is our test group
|
||||
test = [
|
||||
"anyio==3.7.0",
|
||||
"requests>=2.31.0",
|
||||
]
|
||||
"#})?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.add().arg("anyio==3.7.0").arg("--group").arg("alpha"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 8 packages in [TIME]
|
||||
Prepared 3 packages in [TIME]
|
||||
Installed 3 packages in [TIME]
|
||||
+ anyio==3.7.0
|
||||
+ idna==3.6
|
||||
+ sniffio==1.3.1
|
||||
");
|
||||
|
||||
let pyproject_toml = context.read("pyproject.toml");
|
||||
|
||||
assert!(context.temp_dir.join("uv.lock").exists());
|
||||
|
||||
assert_snapshot!(pyproject_toml, @r#"
|
||||
[project]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = []
|
||||
|
||||
[dependency-groups]
|
||||
alpha = [
|
||||
"anyio==3.7.0",
|
||||
]
|
||||
# This is our dev group
|
||||
dev = [
|
||||
"anyio==3.7.0",
|
||||
]
|
||||
# This is our test group
|
||||
test = [
|
||||
"anyio==3.7.0",
|
||||
"requests>=2.31.0",
|
||||
]
|
||||
"#
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Add a requirement to dependency group (sorted between the other groups).
|
||||
#[test]
|
||||
fn add_group_between_commented_groups() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||
pyproject_toml.write_str(indoc! {r#"
|
||||
[project]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = []
|
||||
|
||||
[dependency-groups]
|
||||
# This is our dev group
|
||||
dev = [
|
||||
"anyio==3.7.0",
|
||||
]
|
||||
# This is our test group
|
||||
test = [
|
||||
"anyio==3.7.0",
|
||||
"requests>=2.31.0",
|
||||
]
|
||||
"#})?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.add().arg("anyio==3.7.0").arg("--group").arg("eta"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 8 packages in [TIME]
|
||||
Prepared 3 packages in [TIME]
|
||||
Installed 3 packages in [TIME]
|
||||
+ anyio==3.7.0
|
||||
+ idna==3.6
|
||||
+ sniffio==1.3.1
|
||||
");
|
||||
|
||||
let pyproject_toml = context.read("pyproject.toml");
|
||||
|
||||
assert!(context.temp_dir.join("uv.lock").exists());
|
||||
|
||||
assert_snapshot!(pyproject_toml, @r#"
|
||||
[project]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = []
|
||||
|
||||
[dependency-groups]
|
||||
# This is our dev group
|
||||
dev = [
|
||||
"anyio==3.7.0",
|
||||
]
|
||||
eta = [
|
||||
"anyio==3.7.0",
|
||||
]
|
||||
# This is our test group
|
||||
test = [
|
||||
"anyio==3.7.0",
|
||||
"requests>=2.31.0",
|
||||
]
|
||||
"#
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Add a requirement to a dependency group when existing dependency group
|
||||
/// keys are not sorted.
|
||||
#[test]
|
||||
fn add_group_to_unsorted() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||
pyproject_toml.write_str(indoc! {r#"
|
||||
[project]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
|
@ -4845,9 +5032,44 @@ fn add_group() -> Result<()> {
|
|||
second = [
|
||||
"anyio==3.7.0",
|
||||
]
|
||||
"#})?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.add().arg("anyio==3.7.0").arg("--group").arg("alpha"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 8 packages in [TIME]
|
||||
Prepared 3 packages in [TIME]
|
||||
Installed 3 packages in [TIME]
|
||||
+ anyio==3.7.0
|
||||
+ idna==3.6
|
||||
+ sniffio==1.3.1
|
||||
"###);
|
||||
|
||||
let pyproject_toml = context.read("pyproject.toml");
|
||||
|
||||
assert_snapshot!(pyproject_toml, @r###"
|
||||
[project]
|
||||
name = "project"
|
||||
version = "0.1.0"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = []
|
||||
|
||||
[dependency-groups]
|
||||
test = [
|
||||
"anyio==3.7.0",
|
||||
"requests>=2.31.0",
|
||||
]
|
||||
second = [
|
||||
"anyio==3.7.0",
|
||||
]
|
||||
alpha = [
|
||||
"anyio==3.7.0",
|
||||
]
|
||||
"###
|
||||
);
|
||||
});
|
||||
);
|
||||
|
||||
assert!(context.temp_dir.join("uv.lock").exists());
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue