Default to `--workspace` when adding subdirectories (#14529)

If `--workspace` is provided, we add all paths as workspace members.

If `--no-workspace` is provided, we add all paths as direct path
dependencies.

If neither is provided, then we add any paths that are under the
workspace root as workspace members, and the rest as direct path
dependencies.

Closes #14524.
This commit is contained in:
Charlie Marsh 2025-07-10 22:05:49 -04:00 committed by Zanie Blue
parent e4c04af32d
commit c3d7d3899c
5 changed files with 522 additions and 42 deletions

View File

@ -3726,10 +3726,19 @@ pub struct AddArgs {
/// Add the dependency as a workspace member. /// Add the dependency as a workspace member.
/// ///
/// When used with a path dependency, the package will be added to the workspace's `members` /// By default, uv will add path dependencies that are within the workspace directory
/// list in the root `pyproject.toml` file. /// as workspace members. When used with a path dependency, the package will be added
#[arg(long)] /// to the workspace's `members` list in the root `pyproject.toml` file.
#[arg(long, overrides_with = "no_workspace")]
pub workspace: bool, pub workspace: bool,
/// Don't add the dependency as a workspace member.
///
/// By default, when adding a dependency that's a local path and is within the workspace
/// directory, uv will add it as a workspace member; pass `--no-workspace` to add the package
/// as direct path dependency instead.
#[arg(long, overrides_with = "workspace")]
pub no_workspace: bool,
} }
#[derive(Args)] #[derive(Args)]

View File

@ -83,7 +83,7 @@ pub(crate) async fn add(
extras_of_dependency: Vec<ExtraName>, extras_of_dependency: Vec<ExtraName>,
package: Option<PackageName>, package: Option<PackageName>,
python: Option<String>, python: Option<String>,
workspace: bool, workspace: Option<bool>,
install_mirrors: PythonInstallMirrors, install_mirrors: PythonInstallMirrors,
settings: ResolverInstallerSettings, settings: ResolverInstallerSettings,
network_settings: NetworkSettings, network_settings: NetworkSettings,
@ -497,16 +497,41 @@ pub(crate) async fn add(
// Track modification status, for reverts. // Track modification status, for reverts.
let mut modified = false; let mut modified = false;
// If `--workspace` is provided, add any members to the `workspace` section of the // Determine whether to use workspace mode.
let use_workspace = match workspace {
Some(workspace) => workspace,
None => {
// Check if we're in a project (not a script), and if any requirements are path
// dependencies within the workspace.
if let AddTarget::Project(ref project, _) = target {
let workspace_root = project.workspace().install_path();
requirements.iter().any(|req| {
if let RequirementSource::Directory { install_path, .. } = &req.source {
let absolute_path = if install_path.is_absolute() {
install_path.to_path_buf()
} else {
project.root().join(install_path)
};
absolute_path.starts_with(workspace_root)
} else {
false
}
})
} else {
false
}
}
};
// If workspace mode is enabled, add any members to the `workspace` section of the
// `pyproject.toml` file. // `pyproject.toml` file.
if workspace { if use_workspace {
let AddTarget::Project(project, python_target) = target else { let AddTarget::Project(project, python_target) = target else {
unreachable!("`--workspace` and `--script` are conflicting options"); unreachable!("`--workspace` and `--script` are conflicting options");
}; };
let workspace = project.workspace();
let mut toml = PyProjectTomlMut::from_toml( let mut toml = PyProjectTomlMut::from_toml(
&workspace.pyproject_toml().raw, &project.workspace().pyproject_toml().raw,
DependencyTarget::PyProjectToml, DependencyTarget::PyProjectToml,
)?; )?;
@ -519,10 +544,22 @@ pub(crate) async fn add(
project.root().join(install_path) project.root().join(install_path)
}; };
// Check if the path is not already included in the workspace. // Either `--workspace` was provided explicitly, or it was omitted but the path is
if !workspace.includes(&absolute_path)? { // within the workspace root.
let use_workspace = workspace.unwrap_or_else(|| {
absolute_path.starts_with(project.workspace().install_path())
});
if !use_workspace {
continue;
}
// If the project is already a member of the workspace, skip it.
if project.workspace().includes(&absolute_path)? {
continue;
}
let relative_path = absolute_path let relative_path = absolute_path
.strip_prefix(workspace.install_path()) .strip_prefix(project.workspace().install_path())
.unwrap_or(&absolute_path); .unwrap_or(&absolute_path);
toml.add_workspace(relative_path)?; toml.add_workspace(relative_path)?;
@ -535,14 +572,13 @@ pub(crate) async fn add(
)?; )?;
} }
} }
}
// If we modified the workspace root, we need to reload it entirely, since this can impact // If we modified the workspace root, we need to reload it entirely, since this can impact
// the discovered members, etc. // the discovered members, etc.
target = if modified { target = if modified {
let workspace_content = toml.to_string(); let workspace_content = toml.to_string();
fs_err::write( fs_err::write(
workspace.install_path().join("pyproject.toml"), project.workspace().install_path().join("pyproject.toml"),
&workspace_content, &workspace_content,
)?; )?;
@ -747,13 +783,13 @@ fn edits(
.and_then(|tool| tool.uv.as_ref()) .and_then(|tool| tool.uv.as_ref())
.and_then(|uv| uv.sources.as_ref()) .and_then(|uv| uv.sources.as_ref())
.map(ToolUvSources::inner); .map(ToolUvSources::inner);
let workspace = project let is_workspace_member = project
.workspace() .workspace()
.packages() .packages()
.contains_key(&requirement.name); .contains_key(&requirement.name);
resolve_requirement( resolve_requirement(
requirement, requirement,
workspace, is_workspace_member,
editable, editable,
index.cloned(), index.cloned(),
rev.map(ToString::to_string), rev.map(ToString::to_string),

View File

@ -1351,7 +1351,7 @@ pub(crate) struct AddSettings {
pub(crate) package: Option<PackageName>, pub(crate) package: Option<PackageName>,
pub(crate) script: Option<PathBuf>, pub(crate) script: Option<PathBuf>,
pub(crate) python: Option<String>, pub(crate) python: Option<String>,
pub(crate) workspace: bool, pub(crate) workspace: Option<bool>,
pub(crate) install_mirrors: PythonInstallMirrors, pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) refresh: Refresh, pub(crate) refresh: Refresh,
pub(crate) indexes: Vec<Index>, pub(crate) indexes: Vec<Index>,
@ -1390,6 +1390,7 @@ impl AddSettings {
script, script,
python, python,
workspace, workspace,
no_workspace,
} = args; } = args;
let dependency_type = if let Some(extra) = optional { let dependency_type = if let Some(extra) = optional {
@ -1490,7 +1491,7 @@ impl AddSettings {
package, package,
script, script,
python: python.and_then(Maybe::into_option), python: python.and_then(Maybe::into_option),
workspace, workspace: flag(workspace, no_workspace, "workspace"),
editable: flag(editable, no_editable, "editable"), editable: flag(editable, no_editable, "editable"),
extras: extra.unwrap_or_default(), extras: extra.unwrap_or_default(),
refresh: Refresh::from(refresh), refresh: Refresh::from(refresh),

View File

@ -2491,9 +2491,9 @@ fn add_workspace_path() -> Result<()> {
Ok(()) Ok(())
} }
/// Add a path dependency. /// Add a path dependency, which should be implicitly added to the workspace.
#[test] #[test]
fn add_path() -> Result<()> { fn add_path_implicit_workspace() -> Result<()> {
let context = TestContext::new("3.12"); let context = TestContext::new("3.12");
let workspace = context.temp_dir.child("workspace"); let workspace = context.temp_dir.child("workspace");
@ -2533,6 +2533,7 @@ fn add_path() -> Result<()> {
----- stderr ----- ----- stderr -----
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12] Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
Creating virtual environment at: .venv Creating virtual environment at: .venv
Added `packages/child` to workspace members
Resolved 2 packages in [TIME] Resolved 2 packages in [TIME]
Prepared 1 package in [TIME] Prepared 1 package in [TIME]
Installed 1 package in [TIME] Installed 1 package in [TIME]
@ -2545,7 +2546,134 @@ fn add_path() -> Result<()> {
filters => context.filters(), filters => context.filters(),
}, { }, {
assert_snapshot!( assert_snapshot!(
pyproject_toml, @r###" pyproject_toml, @r#"
[project]
name = "parent"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
"child",
]
[tool.uv.workspace]
members = [
"packages/child",
]
[tool.uv.sources]
child = { workspace = true }
"#
);
});
// `uv add` implies a full lock and sync, including development dependencies.
let lock = fs_err::read_to_string(workspace.join("uv.lock"))?;
insta::with_settings!({
filters => context.filters(),
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 2
requires-python = ">=3.12"
[options]
exclude-newer = "2024-03-25T00:00:00Z"
[manifest]
members = [
"child",
"parent",
]
[[package]]
name = "child"
version = "0.1.0"
source = { editable = "packages/child" }
[[package]]
name = "parent"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "child" },
]
[package.metadata]
requires-dist = [{ name = "child", editable = "packages/child" }]
"#
);
});
// Install from the lockfile.
uv_snapshot!(context.filters(), context.sync().arg("--frozen").current_dir(workspace.path()), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Audited 1 package in [TIME]
");
Ok(())
}
/// Add a path dependency with `--no-workspace`, which should not be added to the workspace.
#[test]
fn add_path_no_workspace() -> Result<()> {
let context = TestContext::new("3.12");
let workspace = context.temp_dir.child("workspace");
workspace.child("pyproject.toml").write_str(indoc! {r#"
[project]
name = "parent"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
"#})?;
let child = workspace.child("packages").child("child");
child.child("pyproject.toml").write_str(indoc! {r#"
[project]
name = "child"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
"#})?;
workspace
.child("packages")
.child("child")
.child("src")
.child("child")
.child("__init__.py")
.touch()?;
uv_snapshot!(context.filters(), context.add().arg(Path::new("packages").join("child")).current_dir(workspace.path()).arg("--no-workspace"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
Creating virtual environment at: .venv
Resolved 2 packages in [TIME]
Prepared 1 package in [TIME]
Installed 1 package in [TIME]
+ child==0.1.0 (from file://[TEMP_DIR]/workspace/packages/child)
");
let pyproject_toml = fs_err::read_to_string(workspace.join("pyproject.toml"))?;
insta::with_settings!({
filters => context.filters(),
}, {
assert_snapshot!(
pyproject_toml, @r#"
[project] [project]
name = "parent" name = "parent"
version = "0.1.0" version = "0.1.0"
@ -2556,7 +2684,7 @@ fn add_path() -> Result<()> {
[tool.uv.sources] [tool.uv.sources]
child = { path = "packages/child" } child = { path = "packages/child" }
"### "#
); );
}); });
@ -2607,6 +2735,110 @@ fn add_path() -> Result<()> {
Ok(()) Ok(())
} }
/// Add a path dependency in an adjacent directory, which should not be added to the workspace.
#[test]
fn add_path_adjacent_directory() -> Result<()> {
let context = TestContext::new("3.12");
let project = context.temp_dir.child("project");
project.child("pyproject.toml").write_str(indoc! {r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
"#})?;
let dependency = context.temp_dir.child("dependency");
dependency.child("pyproject.toml").write_str(indoc! {r#"
[project]
name = "dependency"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
"#})?;
dependency
.child("src")
.child("dependency")
.child("__init__.py")
.touch()?;
uv_snapshot!(context.filters(), context.add().arg(dependency.path()).current_dir(project.path()), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
Creating virtual environment at: .venv
Resolved 2 packages in [TIME]
Prepared 1 package in [TIME]
Installed 1 package in [TIME]
+ dependency==0.1.0 (from file://[TEMP_DIR]/dependency)
");
let pyproject_toml = fs_err::read_to_string(project.join("pyproject.toml"))?;
insta::with_settings!({
filters => context.filters(),
}, {
assert_snapshot!(
pyproject_toml, @r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
"dependency",
]
[tool.uv.sources]
dependency = { path = "../dependency" }
"#
);
});
// `uv add` implies a full lock and sync, including development dependencies.
let lock = fs_err::read_to_string(project.join("uv.lock"))?;
insta::with_settings!({
filters => context.filters(),
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 2
requires-python = ">=3.12"
[options]
exclude-newer = "2024-03-25T00:00:00Z"
[[package]]
name = "dependency"
version = "0.1.0"
source = { directory = "../dependency" }
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "dependency" },
]
[package.metadata]
requires-dist = [{ name = "dependency", directory = "../dependency" }]
"#
);
});
Ok(())
}
/// Update a requirement, modifying the source and extras. /// Update a requirement, modifying the source and extras.
#[test] #[test]
#[cfg(feature = "git")] #[cfg(feature = "git")]
@ -7249,7 +7481,7 @@ fn fail_to_add_revert_project() -> Result<()> {
.child("setup.py") .child("setup.py")
.write_str("1/0")?; .write_str("1/0")?;
uv_snapshot!(context.filters(), context.add().arg("./child"), @r#" uv_snapshot!(context.filters(), context.add().arg("./child").arg("--no-workspace"), @r#"
success: false success: false
exit_code: 1 exit_code: 1
----- stdout ----- ----- stdout -----
@ -7351,7 +7583,7 @@ fn fail_to_edit_revert_project() -> Result<()> {
.child("setup.py") .child("setup.py")
.write_str("1/0")?; .write_str("1/0")?;
uv_snapshot!(context.filters(), context.add().arg("./child"), @r#" uv_snapshot!(context.filters(), context.add().arg("./child").arg("--no-workspace"), @r#"
success: false success: false
exit_code: 1 exit_code: 1
----- stdout ----- ----- stdout -----
@ -7460,7 +7692,7 @@ fn fail_to_add_revert_workspace_root() -> Result<()> {
.child("setup.py") .child("setup.py")
.write_str("1/0")?; .write_str("1/0")?;
uv_snapshot!(context.filters(), context.add().arg("--workspace").arg("./broken"), @r#" uv_snapshot!(context.filters(), context.add().arg("./broken"), @r#"
success: false success: false
exit_code: 1 exit_code: 1
----- stdout ----- ----- stdout -----
@ -7575,7 +7807,7 @@ fn fail_to_add_revert_workspace_member() -> Result<()> {
.child("setup.py") .child("setup.py")
.write_str("1/0")?; .write_str("1/0")?;
uv_snapshot!(context.filters(), context.add().current_dir(&project).arg("--workspace").arg("../broken"), @r#" uv_snapshot!(context.filters(), context.add().current_dir(&project).arg("../broken"), @r#"
success: false success: false
exit_code: 1 exit_code: 1
----- stdout ----- ----- stdout -----
@ -12928,12 +13160,12 @@ fn add_path_with_existing_workspace() -> Result<()> {
dependencies = [] dependencies = []
"#})?; "#})?;
// Add the dependency with `--workspace` flag from the project directory. // Add the dependency from the project directory. It should automatically be added as a
// workspace member, since it's in the same directory as the workspace.
uv_snapshot!(context.filters(), context uv_snapshot!(context.filters(), context
.add() .add()
.current_dir(&project_dir) .current_dir(&project_dir)
.arg("../dep") .arg("../dep"), @r"
.arg("--workspace"), @r"
success: true success: true
exit_code: 0 exit_code: 0
----- stdout ----- ----- stdout -----
@ -13044,3 +13276,203 @@ fn add_path_with_workspace() -> Result<()> {
Ok(()) Ok(())
} }
/// Add a path dependency within the workspace directory without --workspace flag.
/// It should automatically be added as a workspace member.
#[test]
fn add_path_within_workspace_defaults_to_workspace() -> Result<()> {
let context = TestContext::new("3.12");
let workspace_toml = context.temp_dir.child("pyproject.toml");
workspace_toml.write_str(indoc! {r#"
[project]
name = "parent"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
[tool.uv.workspace]
members = []
"#})?;
let dep_dir = context.temp_dir.child("dep");
dep_dir.child("pyproject.toml").write_str(indoc! {r#"
[project]
name = "dep"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
"#})?;
// Add the dependency without --workspace flag - it should still be added as workspace member
// since it's within the workspace directory.
uv_snapshot!(context.filters(), context
.add()
.arg("./dep"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Added `dep` to workspace members
Resolved 2 packages in [TIME]
Audited in [TIME]
");
let pyproject_toml = context.read("pyproject.toml");
assert_snapshot!(
pyproject_toml, @r#"
[project]
name = "parent"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
"dep",
]
[tool.uv.workspace]
members = [
"dep",
]
[tool.uv.sources]
dep = { workspace = true }
"#
);
Ok(())
}
/// Add a path dependency within the workspace directory with --no-workspace flag.
/// It should be added as a direct path dependency.
#[test]
fn add_path_with_no_workspace() -> Result<()> {
let context = TestContext::new("3.12");
let workspace_toml = context.temp_dir.child("pyproject.toml");
workspace_toml.write_str(indoc! {r#"
[project]
name = "parent"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
[tool.uv.workspace]
members = []
"#})?;
let dep_dir = context.temp_dir.child("dep");
dep_dir.child("pyproject.toml").write_str(indoc! {r#"
[project]
name = "dep"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
"#})?;
// Add the dependency with --no-workspace flag - it should be added as direct path dependency.
uv_snapshot!(context.filters(), context
.add()
.arg("./dep")
.arg("--no-workspace"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 2 packages in [TIME]
Audited in [TIME]
");
let pyproject_toml = context.read("pyproject.toml");
assert_snapshot!(
pyproject_toml, @r#"
[project]
name = "parent"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
"dep",
]
[tool.uv.workspace]
members = []
[tool.uv.sources]
dep = { path = "dep" }
"#
);
Ok(())
}
/// Add a path dependency outside the workspace directory.
/// It should be added as a direct path dependency, not a workspace member.
#[test]
fn add_path_outside_workspace_no_default() -> Result<()> {
let context = TestContext::new("3.12");
// Create a workspace directory
let workspace_dir = context.temp_dir.child("workspace");
workspace_dir.create_dir_all()?;
let workspace_toml = workspace_dir.child("pyproject.toml");
workspace_toml.write_str(indoc! {r#"
[project]
name = "parent"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
[tool.uv.workspace]
members = []
"#})?;
// Create a dependency outside the workspace
let dep_dir = context.temp_dir.child("external_dep");
dep_dir.child("pyproject.toml").write_str(indoc! {r#"
[project]
name = "dep"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
"#})?;
// Add the dependency without --workspace flag - it should be a direct path dependency
// since it's outside the workspace directory.
uv_snapshot!(context.filters(), context
.add()
.current_dir(&workspace_dir)
.arg("../external_dep"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
Creating virtual environment at: .venv
Resolved 2 packages in [TIME]
Audited in [TIME]
");
let pyproject_toml = fs_err::read_to_string(workspace_toml)?;
assert_snapshot!(
pyproject_toml, @r#"
[project]
name = "parent"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
"dep",
]
[tool.uv.workspace]
members = []
[tool.uv.sources]
dep = { path = "../external_dep" }
"#
);
Ok(())
}

View File

@ -535,7 +535,9 @@ uv add [OPTIONS] <PACKAGES|--requirements <REQUIREMENTS>>
<p>May also be set with the <code>UV_NO_PROGRESS</code> environment variable.</p></dd><dt id="uv-add--no-python-downloads"><a href="#uv-add--no-python-downloads"><code>--no-python-downloads</code></a></dt><dd><p>Disable automatic downloads of Python.</p> <p>May also be set with the <code>UV_NO_PROGRESS</code> environment variable.</p></dd><dt id="uv-add--no-python-downloads"><a href="#uv-add--no-python-downloads"><code>--no-python-downloads</code></a></dt><dd><p>Disable automatic downloads of Python.</p>
</dd><dt id="uv-add--no-sources"><a href="#uv-add--no-sources"><code>--no-sources</code></a></dt><dd><p>Ignore the <code>tool.uv.sources</code> table when resolving dependencies. Used to lock against the standards-compliant, publishable package metadata, as opposed to using any workspace, Git, URL, or local path sources</p> </dd><dt id="uv-add--no-sources"><a href="#uv-add--no-sources"><code>--no-sources</code></a></dt><dd><p>Ignore the <code>tool.uv.sources</code> table when resolving dependencies. Used to lock against the standards-compliant, publishable package metadata, as opposed to using any workspace, Git, URL, or local path sources</p>
</dd><dt id="uv-add--no-sync"><a href="#uv-add--no-sync"><code>--no-sync</code></a></dt><dd><p>Avoid syncing the virtual environment</p> </dd><dt id="uv-add--no-sync"><a href="#uv-add--no-sync"><code>--no-sync</code></a></dt><dd><p>Avoid syncing the virtual environment</p>
<p>May also be set with the <code>UV_NO_SYNC</code> environment variable.</p></dd><dt id="uv-add--offline"><a href="#uv-add--offline"><code>--offline</code></a></dt><dd><p>Disable network access.</p> <p>May also be set with the <code>UV_NO_SYNC</code> environment variable.</p></dd><dt id="uv-add--no-workspace"><a href="#uv-add--no-workspace"><code>--no-workspace</code></a></dt><dd><p>Don't add the dependency as a workspace member.</p>
<p>By default, when adding a dependency that's a local path and is within the workspace directory, uv will add it as a workspace member; pass <code>--no-workspace</code> to add the package as direct path dependency instead.</p>
</dd><dt id="uv-add--offline"><a href="#uv-add--offline"><code>--offline</code></a></dt><dd><p>Disable network access.</p>
<p>When disabled, uv will only use locally cached data and locally available files.</p> <p>When disabled, uv will only use locally cached data and locally available files.</p>
<p>May also be set with the <code>UV_OFFLINE</code> environment variable.</p></dd><dt id="uv-add--optional"><a href="#uv-add--optional"><code>--optional</code></a> <i>optional</i></dt><dd><p>Add the requirements to the package's optional dependencies for the specified extra.</p> <p>May also be set with the <code>UV_OFFLINE</code> environment variable.</p></dd><dt id="uv-add--optional"><a href="#uv-add--optional"><code>--optional</code></a> <i>optional</i></dt><dd><p>Add the requirements to the package's optional dependencies for the specified extra.</p>
<p>The group may then be activated when installing the project with the <code>--extra</code> flag.</p> <p>The group may then be activated when installing the project with the <code>--extra</code> flag.</p>
@ -583,7 +585,7 @@ uv add [OPTIONS] <PACKAGES|--requirements <REQUIREMENTS>>
</dd><dt id="uv-add--verbose"><a href="#uv-add--verbose"><code>--verbose</code></a>, <code>-v</code></dt><dd><p>Use verbose output.</p> </dd><dt id="uv-add--verbose"><a href="#uv-add--verbose"><code>--verbose</code></a>, <code>-v</code></dt><dd><p>Use verbose output.</p>
<p>You can configure fine-grained logging using the <code>RUST_LOG</code> environment variable. (<a href="https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives">https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives</a>)</p> <p>You can configure fine-grained logging using the <code>RUST_LOG</code> environment variable. (<a href="https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives">https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives</a>)</p>
</dd><dt id="uv-add--workspace"><a href="#uv-add--workspace"><code>--workspace</code></a></dt><dd><p>Add the dependency as a workspace member.</p> </dd><dt id="uv-add--workspace"><a href="#uv-add--workspace"><code>--workspace</code></a></dt><dd><p>Add the dependency as a workspace member.</p>
<p>When used with a path dependency, the package will be added to the workspace's <code>members</code> list in the root <code>pyproject.toml</code> file.</p> <p>By default, uv will add path dependencies that are within the workspace directory as workspace members. When used with a path dependency, the package will be added to the workspace's <code>members</code> list in the root <code>pyproject.toml</code> file.</p>
</dd></dl> </dd></dl>
## uv remove ## uv remove
@ -1154,10 +1156,10 @@ environment in the project.</p>
<li><code>macos</code>: An alias for <code>aarch64-apple-darwin</code>, the default target for macOS</li> <li><code>macos</code>: An alias for <code>aarch64-apple-darwin</code>, the default target for macOS</li>
<li><code>x86_64-pc-windows-msvc</code>: A 64-bit x86 Windows target</li> <li><code>x86_64-pc-windows-msvc</code>: A 64-bit x86 Windows target</li>
<li><code>i686-pc-windows-msvc</code>: A 32-bit x86 Windows target</li> <li><code>i686-pc-windows-msvc</code>: A 32-bit x86 Windows target</li>
<li><code>x86_64-unknown-linux-gnu</code>: An x86 Linux target. Equivalent to <code>x86_64-manylinux_2_17</code></li> <li><code>x86_64-unknown-linux-gnu</code>: An x86 Linux target. Equivalent to <code>x86_64-manylinux_2_28</code></li>
<li><code>aarch64-apple-darwin</code>: An ARM-based macOS target, as seen on Apple Silicon devices</li> <li><code>aarch64-apple-darwin</code>: An ARM-based macOS target, as seen on Apple Silicon devices</li>
<li><code>x86_64-apple-darwin</code>: An x86 macOS target</li> <li><code>x86_64-apple-darwin</code>: An x86 macOS target</li>
<li><code>aarch64-unknown-linux-gnu</code>: An ARM64 Linux target. Equivalent to <code>aarch64-manylinux_2_17</code></li> <li><code>aarch64-unknown-linux-gnu</code>: An ARM64 Linux target. Equivalent to <code>aarch64-manylinux_2_28</code></li>
<li><code>aarch64-unknown-linux-musl</code>: An ARM64 Linux target</li> <li><code>aarch64-unknown-linux-musl</code>: An ARM64 Linux target</li>
<li><code>x86_64-unknown-linux-musl</code>: An <code>x86_64</code> Linux target</li> <li><code>x86_64-unknown-linux-musl</code>: An <code>x86_64</code> Linux target</li>
<li><code>x86_64-manylinux2014</code>: An <code>x86_64</code> target for the <code>manylinux2014</code> platform. Equivalent to <code>x86_64-manylinux_2_17</code></li> <li><code>x86_64-manylinux2014</code>: An <code>x86_64</code> target for the <code>manylinux2014</code> platform. Equivalent to <code>x86_64-manylinux_2_17</code></li>