Skip to content

Commit

Permalink
Add --package argument to uv add and uv remove (#4556)
Browse files Browse the repository at this point in the history
## Summary

Closes #4550.
  • Loading branch information
charliermarsh committed Jun 26, 2024
1 parent 1ee201d commit 963a7b2
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 20 deletions.
16 changes: 12 additions & 4 deletions crates/uv-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1639,6 +1639,10 @@ pub struct RunArgs {
#[command(flatten)]
pub refresh: RefreshArgs,

/// Run the command in a specific package in the workspace.
#[arg(long, conflicts_with = "isolated")]
pub package: Option<PackageName>,

/// The Python interpreter to use to build the run environment.
///
/// By default, `uv` uses the virtual environment in the current working directory or any parent
Expand All @@ -1652,10 +1656,6 @@ pub struct RunArgs {
/// - `/home/ferris/.local/bin/python3.10` uses the exact Python at the given path.
#[arg(long, short, env = "UV_PYTHON", verbatim_doc_comment)]
pub python: Option<String>,

/// Run the command in a different package in the workspace.
#[arg(long, conflicts_with = "isolated")]
pub package: Option<PackageName>,
}

#[derive(Args)]
Expand Down Expand Up @@ -1784,6 +1784,10 @@ pub struct AddArgs {
#[command(flatten)]
pub refresh: RefreshArgs,

/// Add the dependency to a specific package in the workspace.
#[arg(long, conflicts_with = "isolated")]
pub package: Option<PackageName>,

/// The Python interpreter into which packages should be installed.
///
/// By default, `uv` installs into the virtual environment in the current working directory or
Expand Down Expand Up @@ -1811,6 +1815,10 @@ pub struct RemoveArgs {
#[arg(long)]
pub dev: bool,

/// Remove the dependency from a specific package in the workspace.
#[arg(long, conflicts_with = "isolated")]
pub package: Option<PackageName>,

/// The Python interpreter into which packages should be installed.
///
/// By default, `uv` installs into the virtual environment in the current working directory or
Expand Down
17 changes: 13 additions & 4 deletions crates/uv/src/commands/project/add.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use anyhow::Result;
use anyhow::{Context, Result};
use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_dispatch::BuildDispatch;
use uv_distribution::pyproject::{Source, SourceError};
Expand All @@ -11,7 +11,8 @@ use uv_types::{BuildIsolation, HashStrategy, InFlight};

use uv_cache::Cache;
use uv_configuration::{Concurrency, ExtrasSpecification, PreviewMode, SetupPyStrategy};
use uv_distribution::{DistributionDatabase, ProjectWorkspace};
use uv_distribution::{DistributionDatabase, ProjectWorkspace, Workspace};
use uv_normalize::PackageName;
use uv_warnings::warn_user;

use crate::commands::pip::operations::Modifications;
Expand All @@ -32,6 +33,7 @@ pub(crate) async fn add(
rev: Option<String>,
tag: Option<String>,
branch: Option<String>,
package: Option<PackageName>,
python: Option<String>,
settings: ResolverInstallerSettings,
toolchain_preference: ToolchainPreference,
Expand All @@ -46,8 +48,15 @@ pub(crate) async fn add(
warn_user!("`uv add` is experimental and may change without warning.");
}

// Find the project requirements.
let project = ProjectWorkspace::discover(&std::env::current_dir()?, None).await?;
// Find the project in the workspace.
let project = if let Some(package) = package {
Workspace::discover(&std::env::current_dir()?, None)
.await?
.with_current_project(package.clone())
.with_context(|| format!("Package `{package}` not found in workspace"))?
} else {
ProjectWorkspace::discover(&std::env::current_dir()?, None).await?
};

// Discover or create the virtual environment.
let venv = project::init_environment(
Expand Down
22 changes: 14 additions & 8 deletions crates/uv/src/commands/project/remove.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use anyhow::Result;
use anyhow::{Context, Result};

use pep508_rs::PackageName;
use uv_cache::Cache;
use uv_client::Connectivity;
use uv_configuration::{Concurrency, ExtrasSpecification, PreviewMode};
use uv_distribution::pyproject_mut::PyProjectTomlMut;
use uv_distribution::ProjectWorkspace;
use uv_distribution::{ProjectWorkspace, Workspace};
use uv_toolchain::{ToolchainPreference, ToolchainRequest};
use uv_warnings::warn_user;

Expand All @@ -19,6 +19,7 @@ use crate::settings::{InstallerSettings, ResolverSettings};
pub(crate) async fn remove(
requirements: Vec<PackageName>,
dev: bool,
package: Option<PackageName>,
python: Option<String>,
toolchain_preference: ToolchainPreference,
preview: PreviewMode,
Expand All @@ -32,8 +33,15 @@ pub(crate) async fn remove(
warn_user!("`uv remove` is experimental and may change without warning.");
}

// Find the project requirements.
let project = ProjectWorkspace::discover(&std::env::current_dir()?, None).await?;
// Find the project in the workspace.
let project = if let Some(package) = package {
Workspace::discover(&std::env::current_dir()?, None)
.await?
.with_current_project(package.clone())
.with_context(|| format!("Package `{package}` not found in workspace"))?
} else {
ProjectWorkspace::discover(&std::env::current_dir()?, None).await?
};

let mut pyproject = PyProjectTomlMut::from_toml(project.current_project().pyproject_toml())?;
for req in requirements {
Expand All @@ -47,7 +55,7 @@ pub(crate) async fn remove(
.filter(|deps| !deps.is_empty())
.is_some()
{
uv_warnings::warn_user!("`{req}` is not a development dependency; try calling `uv remove` without the `--dev` flag");
warn_user!("`{req}` is not a development dependency; try calling `uv remove` without the `--dev` flag");
}

anyhow::bail!("The dependency `{req}` could not be found in `dev-dependencies`");
Expand All @@ -65,9 +73,7 @@ pub(crate) async fn remove(
.filter(|deps| !deps.is_empty())
.is_some()
{
uv_warnings::warn_user!(
"`{req}` is a development dependency; try calling `uv remove --dev`"
);
warn_user!("`{req}` is a development dependency; try calling `uv remove --dev`");
}

anyhow::bail!("The dependency `{req}` could not be found in `dependencies`");
Expand Down
2 changes: 2 additions & 0 deletions crates/uv/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,7 @@ async fn run() -> Result<ExitStatus> {
args.rev,
args.tag,
args.branch,
args.package,
args.python,
args.settings,
globals.toolchain_preference,
Expand All @@ -749,6 +750,7 @@ async fn run() -> Result<ExitStatus> {
commands::remove(
args.requirements,
args.dev,
args.package,
args.python,
globals.toolchain_preference,
globals.preview,
Expand Down
12 changes: 9 additions & 3 deletions crates/uv/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@ pub(crate) struct RunSettings {
pub(crate) dev: bool,
pub(crate) command: ExternalCommand,
pub(crate) with: Vec<String>,
pub(crate) python: Option<String>,
pub(crate) package: Option<PackageName>,
pub(crate) python: Option<String>,
pub(crate) refresh: Refresh,
pub(crate) settings: ResolverInstallerSettings,
}
Expand All @@ -168,8 +168,8 @@ impl RunSettings {
installer,
build,
refresh,
python,
package,
python,
} = args;

Self {
Expand All @@ -180,8 +180,8 @@ impl RunSettings {
dev: flag(dev, no_dev).unwrap_or(true),
command,
with,
python,
package,
python,
refresh: Refresh::from(refresh),
settings: ResolverInstallerSettings::combine(
resolver_installer_options(installer, build),
Expand Down Expand Up @@ -438,6 +438,7 @@ pub(crate) struct AddSettings {
pub(crate) rev: Option<String>,
pub(crate) tag: Option<String>,
pub(crate) branch: Option<String>,
pub(crate) package: Option<PackageName>,
pub(crate) python: Option<String>,
pub(crate) refresh: Refresh,
pub(crate) settings: ResolverInstallerSettings,
Expand All @@ -459,6 +460,7 @@ impl AddSettings {
installer,
build,
refresh,
package,
python,
} = args;

Expand All @@ -476,6 +478,7 @@ impl AddSettings {
rev,
tag,
branch,
package,
python,
refresh: Refresh::from(refresh),
settings: ResolverInstallerSettings::combine(
Expand All @@ -492,6 +495,7 @@ impl AddSettings {
pub(crate) struct RemoveSettings {
pub(crate) requirements: Vec<PackageName>,
pub(crate) dev: bool,
pub(crate) package: Option<PackageName>,
pub(crate) python: Option<String>,
}

Expand All @@ -502,12 +506,14 @@ impl RemoveSettings {
let RemoveArgs {
dev,
requirements,
package,
python,
} = args;

Self {
requirements,
dev,
package,
python,
}
}
Expand Down
4 changes: 3 additions & 1 deletion crates/uv/tests/edit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,9 @@ fn add_remove_workspace() -> Result<()> {
add_cmd
.arg("--preview")
.arg("--workspace")
.current_dir(&child1);
.arg("--package")
.arg("child1")
.current_dir(&context.temp_dir);

uv_snapshot!(context.filters(), add_cmd, @r###"
success: true
Expand Down

0 comments on commit 963a7b2

Please sign in to comment.