mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-15 04:49:41 +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()
|
.as_table_like_mut()
|
||||||
.ok_or(Error::MalformedDependencies)?;
|
.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
|
let group = dependency_groups
|
||||||
.entry(group.as_ref())
|
.entry(group.as_ref())
|
||||||
.or_insert(Item::Value(Value::Array(Array::new())))
|
.or_insert(Item::Value(Value::Array(Array::new())))
|
||||||
|
@ -459,6 +466,12 @@ impl PyProjectTomlMut {
|
||||||
let name = req.name.clone();
|
let name = req.name.clone();
|
||||||
let added = add_dependency(req, group, source.is_some())?;
|
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.
|
// If `dependency-groups` is an inline table, reformat it.
|
||||||
//
|
//
|
||||||
// Reformatting can drop comments between keys, but you can't put comments
|
// 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");
|
let pyproject_toml = context.read("pyproject.toml");
|
||||||
|
|
||||||
insta::with_settings!({
|
assert_snapshot!(pyproject_toml, @r###"
|
||||||
filters => context.filters(),
|
|
||||||
}, {
|
|
||||||
assert_snapshot!(
|
|
||||||
pyproject_toml, @r###"
|
|
||||||
[project]
|
[project]
|
||||||
name = "project"
|
name = "project"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -4774,8 +4770,7 @@ fn add_group() -> Result<()> {
|
||||||
"anyio==3.7.0",
|
"anyio==3.7.0",
|
||||||
]
|
]
|
||||||
"###
|
"###
|
||||||
);
|
);
|
||||||
});
|
|
||||||
|
|
||||||
uv_snapshot!(context.filters(), context.add().arg("requests").arg("--group").arg("test"), @r###"
|
uv_snapshot!(context.filters(), context.add().arg("requests").arg("--group").arg("test"), @r###"
|
||||||
success: true
|
success: true
|
||||||
|
@ -4794,11 +4789,7 @@ fn add_group() -> Result<()> {
|
||||||
|
|
||||||
let pyproject_toml = context.read("pyproject.toml");
|
let pyproject_toml = context.read("pyproject.toml");
|
||||||
|
|
||||||
insta::with_settings!({
|
assert_snapshot!(pyproject_toml, @r###"
|
||||||
filters => context.filters(),
|
|
||||||
}, {
|
|
||||||
assert_snapshot!(
|
|
||||||
pyproject_toml, @r###"
|
|
||||||
[project]
|
[project]
|
||||||
name = "project"
|
name = "project"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -4811,8 +4802,7 @@ fn add_group() -> Result<()> {
|
||||||
"requests>=2.31.0",
|
"requests>=2.31.0",
|
||||||
]
|
]
|
||||||
"###
|
"###
|
||||||
);
|
);
|
||||||
});
|
|
||||||
|
|
||||||
uv_snapshot!(context.filters(), context.add().arg("anyio==3.7.0").arg("--group").arg("second"), @r###"
|
uv_snapshot!(context.filters(), context.add().arg("anyio==3.7.0").arg("--group").arg("second"), @r###"
|
||||||
success: true
|
success: true
|
||||||
|
@ -4826,11 +4816,208 @@ fn add_group() -> Result<()> {
|
||||||
|
|
||||||
let pyproject_toml = context.read("pyproject.toml");
|
let pyproject_toml = context.read("pyproject.toml");
|
||||||
|
|
||||||
insta::with_settings!({
|
assert_snapshot!(pyproject_toml, @r#"
|
||||||
filters => context.filters(),
|
[project]
|
||||||
}, {
|
name = "project"
|
||||||
assert_snapshot!(
|
version = "0.1.0"
|
||||||
pyproject_toml, @r###"
|
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]
|
[project]
|
||||||
name = "project"
|
name = "project"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -4845,9 +5032,44 @@ fn add_group() -> Result<()> {
|
||||||
second = [
|
second = [
|
||||||
"anyio==3.7.0",
|
"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());
|
assert!(context.temp_dir.join("uv.lock").exists());
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue