Skip to content

Commit

Permalink
Add support for reading PEP 735 dependency groups
Browse files Browse the repository at this point in the history
  • Loading branch information
zanieb committed Oct 10, 2024
1 parent 7d0e566 commit 26e0950
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 3 deletions.
31 changes: 31 additions & 0 deletions crates/uv-workspace/src/pyproject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ pub struct PyProjectToml {
pub project: Option<Project>,
/// Tool-specific metadata.
pub tool: Option<Tool>,
/// Non-project dependency groups, as defined in PEP 735.
pub dependency_groups: Option<BTreeMap<ExtraName, Vec<String>>>,
/// The raw unserialized document.
#[serde(skip)]
pub raw: String,
Expand Down Expand Up @@ -1053,6 +1055,8 @@ pub enum DependencyType {
Dev,
/// A dependency in `project.optional-dependencies.{0}`.
Optional(ExtraName),
/// A dependency in `project.dependency-groups.{0}`.
Group(ExtraName),
}

/// <https://github.com/serde-rs/serde/issues/1316#issue-332908452>
Expand Down Expand Up @@ -1081,3 +1085,30 @@ mod serde_from_and_to_string {
.map_err(de::Error::custom)
}
}

#[cfg(test)]
mod tests {
use std::str::FromStr;

use uv_pep508::ExtraName;

use crate::pyproject::PyProjectToml;

#[test]
fn test_read_dependency_groups() {
let toml = r#"
[dependency-groups]
test = ["a"]
"#;

let result =
PyProjectToml::from_string(toml.to_string()).expect("Deserialization should succeed");
let groups = result
.dependency_groups
.expect("`dependency-groups` should be present");
let test = groups
.get(&ExtraName::from_str("test").unwrap())
.expect("Group `test` should be present");
assert_eq!(test, &["a".to_string()]);
}
}
18 changes: 17 additions & 1 deletion crates/uv-workspace/src/pyproject_mut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -495,14 +495,30 @@ impl PyProjectTomlMut {
}
}

// Check `tool.uv.dev-dependencies`.
if let Some(groups) = self.doc.get("dependency-groups").and_then(Item::as_table) {
for (group, dependencies) in groups {
let Some(dependencies) = dependencies.as_array() else {
continue;
};
let Ok(group) = ExtraName::new(group.to_string()) else {
continue;
};

if !find_dependencies(name, marker, dependencies).is_empty() {
types.push(DependencyType::Group(group));
}
}
}

// Check `tool.uv.dev-dependencies`.
if let Some(dev_dependencies) = self
.doc
.get("tool")
.and_then(Item::as_table)
.and_then(|tool| tool.get("uv"))
.and_then(Item::as_table)
.and_then(|tool| tool.get("dev-dependencies"))
.and_then(|uv| uv.get("dev-dependencies"))
.and_then(Item::as_array)
{
if !find_dependencies(name, marker, dev_dependencies).is_empty() {
Expand Down
6 changes: 6 additions & 0 deletions crates/uv/src/commands/project/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ pub(crate) async fn add(
bail!("Project is missing a `[project]` table; add a `[project]` table to use optional dependencies, or run `{}` instead", "uv add --dev".green())
}
DependencyType::Dev => (),
DependencyType::Group(_) => (),
}
}

Expand Down Expand Up @@ -449,6 +450,7 @@ pub(crate) async fn add(
DependencyType::Optional(ref group) => {
toml.add_optional_dependency(group, &requirement, source.as_ref())?
}
DependencyType::Group(_) => todo!("adding dependencies to groups is not yet supported"),
};

// If the edit was inserted before the end of the list, update the existing edits.
Expand Down Expand Up @@ -707,6 +709,9 @@ async fn lock_and_sync(
DependencyType::Optional(ref group) => {
toml.set_optional_dependency_minimum_version(group, *index, minimum)?;
}
DependencyType::Group(_) => {
todo!("adding dependencies to groups is not yet supported")
}
}

modified = true;
Expand Down Expand Up @@ -767,6 +772,7 @@ async fn lock_and_sync(
let dev = DevMode::Exclude;
(extras, dev)
}
DependencyType::Group(_) => todo!("adding dependencies to groups is not yet supported"),
};

project::sync::do_sync(
Expand Down
6 changes: 6 additions & 0 deletions crates/uv/src/commands/project/remove.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ pub(crate) async fn remove(
);
}
}
DependencyType::Group(_) => {
todo!("removing dependencies from groups is not yet supported")
}
}
}

Expand Down Expand Up @@ -246,6 +249,9 @@ fn warn_if_present(name: &PackageName, pyproject: &PyProjectTomlMut) {
"`{name}` is an optional dependency; try calling `uv remove --optional {group}`",
);
}
DependencyType::Group(_) => {
// TODO(zanieb): Once we support `remove --group`, add a warning here.
}
}
}
}
4 changes: 2 additions & 2 deletions crates/uv/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -838,8 +838,8 @@ impl AddSettings {
python,
} = args;

let dependency_type = if let Some(group) = optional {
DependencyType::Optional(group)
let dependency_type = if let Some(extra) = optional {
DependencyType::Optional(extra)
} else if dev {
DependencyType::Dev
} else {
Expand Down

0 comments on commit 26e0950

Please sign in to comment.