Skip to content

Commit

Permalink
Automatically detect workspace packages in uv add (#4557)
Browse files Browse the repository at this point in the history
## Summary

If the package _isn't_ marked as `workspace = true`, locking will fail
given:

```rust
let workspace_package_declared =
    // We require that when you use a package that's part of the workspace, ...
    !workspace.packages().contains_key(&requirement.name)
    // ... it must be declared as a workspace dependency (`workspace = true`), ...
    || matches!(
        source,
        Some(Source::Workspace {
            // By using toml, we technically support `workspace = false`.
            workspace: true,
            ..
        })
    )
    // ... except for recursive self-inclusion (extras that activate other extras), e.g.
    // `framework[machine_learning]` depends on `framework[cuda]`.
    || &requirement.name == project_name;
if !workspace_package_declared {
    return Err(LoweringError::UndeclaredWorkspacePackage);
}
```

Closes #4552.
  • Loading branch information
charliermarsh authored Jun 26, 2024
1 parent a328c7b commit 45c271d
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 23 deletions.
4 changes: 0 additions & 4 deletions crates/uv-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1749,10 +1749,6 @@ pub struct AddArgs {
#[arg(long)]
pub dev: bool,

/// Add the requirements as workspace dependencies.
#[arg(long)]
pub workspace: bool,

/// Add the requirements as editables.
#[arg(long, default_missing_value = "true", num_args(0..=1))]
pub editable: Option<bool>,
Expand Down
37 changes: 25 additions & 12 deletions crates/uv-distribution/src/pyproject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,14 +194,19 @@ pub enum Source {

#[derive(Error, Debug)]
pub enum SourceError {
#[error("Cannot resolve git reference `{0}`.")]
#[error("Cannot resolve git reference `{0}`")]
UnresolvedReference(String),
#[error("Workspace dependency must be a local path.")]
InvalidWorkspaceRequirement,
#[error("Workspace dependency `{0}` must refer to local directory, not a Git repository")]
WorkspacePackageGit(String),
#[error("Workspace dependency `{0}` must refer to local directory, not a URL")]
WorkspacePackageUrl(String),
#[error("Workspace dependency `{0}` must refer to local directory, not a file")]
WorkspacePackageFile(String),
}

impl Source {
pub fn from_requirement(
name: &PackageName,
source: RequirementSource,
workspace: bool,
editable: Option<bool>,
Expand All @@ -210,15 +215,23 @@ impl Source {
branch: Option<String>,
) -> Result<Option<Source>, SourceError> {
if workspace {
match source {
RequirementSource::Registry { .. } | RequirementSource::Directory { .. } => {}
_ => return Err(SourceError::InvalidWorkspaceRequirement),
}

return Ok(Some(Source::Workspace {
editable,
workspace: true,
}));
return match source {
RequirementSource::Registry { .. } | RequirementSource::Directory { .. } => {
Ok(Some(Source::Workspace {
editable,
workspace: true,
}))
}
RequirementSource::Url { .. } => {
Err(SourceError::WorkspacePackageUrl(name.to_string()))
}
RequirementSource::Git { .. } => {
Err(SourceError::WorkspacePackageGit(name.to_string()))
}
RequirementSource::Path { .. } => {
Err(SourceError::WorkspacePackageFile(name.to_string()))
}
};
}

let source = match source {
Expand Down
3 changes: 2 additions & 1 deletion crates/uv/src/commands/project/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ use crate::settings::ResolverInstallerSettings;
#[allow(clippy::too_many_arguments, clippy::fn_params_excessive_bools)]
pub(crate) async fn add(
requirements: Vec<RequirementsSource>,
workspace: bool,
dev: bool,
editable: Option<bool>,
raw: bool,
Expand Down Expand Up @@ -154,7 +153,9 @@ pub(crate) async fn add(
(pep508_rs::Requirement::from(req), None)
} else {
// Otherwise, try to construct the source.
let workspace = project.workspace().packages().contains_key(&req.name);
let result = Source::from_requirement(
&req.name,
req.source.clone(),
workspace,
editable,
Expand Down
1 change: 0 additions & 1 deletion crates/uv/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -719,7 +719,6 @@ async fn run() -> Result<ExitStatus> {

commands::add(
args.requirements,
args.workspace,
args.dev,
args.editable,
args.raw,
Expand Down
3 changes: 0 additions & 3 deletions crates/uv/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,6 @@ impl LockSettings {
pub(crate) struct AddSettings {
pub(crate) requirements: Vec<RequirementsSource>,
pub(crate) dev: bool,
pub(crate) workspace: bool,
pub(crate) editable: Option<bool>,
pub(crate) raw: bool,
pub(crate) rev: Option<String>,
Expand All @@ -451,7 +450,6 @@ impl AddSettings {
let AddArgs {
requirements,
dev,
workspace,
editable,
raw,
rev,
Expand All @@ -471,7 +469,6 @@ impl AddSettings {

Self {
requirements,
workspace,
dev,
editable,
raw,
Expand Down
21 changes: 19 additions & 2 deletions crates/uv/tests/edit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -735,11 +735,29 @@ fn add_remove_workspace() -> Result<()> {
dependencies = []
"#})?;

// Adding a workspace package with a mismatched source should error.
let mut add_cmd =
context.add(&["child2 @ git+https://github.com/astral-test/uv-public-pypackage"]);
add_cmd
.arg("--preview")
.arg("--package")
.arg("child1")
.current_dir(&context.temp_dir);

uv_snapshot!(context.filters(), add_cmd, @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: Workspace dependency `child2` must refer to local directory, not a Git repository
"###);

// Workspace packages should be detected automatically.
let child1 = context.temp_dir.join("child1");
let mut add_cmd = context.add(&["child2"]);
add_cmd
.arg("--preview")
.arg("--workspace")
.arg("--package")
.arg("child1")
.current_dir(&context.temp_dir);
Expand Down Expand Up @@ -921,7 +939,6 @@ fn add_workspace_editable() -> Result<()> {
let mut add_cmd = context.add(&["child2"]);
add_cmd
.arg("--editable")
.arg("--workspace")
.arg("--preview")
.current_dir(&child1);

Expand Down

0 comments on commit 45c271d

Please sign in to comment.