diff --git a/crates/uv/src/cli.rs b/crates/uv/src/cli.rs index 4a3372c05..82f8eafb9 100644 --- a/crates/uv/src/cli.rs +++ b/crates/uv/src/cli.rs @@ -1332,6 +1332,9 @@ pub(crate) struct PipInstallArgs { #[arg(long, hide = true)] pub(crate) unstable_uv_lock_file: Option, + + #[command(flatten)] + pub(crate) compat_args: compat::PipInstallCompatArgs, } #[derive(Args)] diff --git a/crates/uv/src/compat/mod.rs b/crates/uv/src/compat/mod.rs index ecda08d1a..128dd57c3 100644 --- a/crates/uv/src/compat/mod.rs +++ b/crates/uv/src/compat/mod.rs @@ -352,3 +352,29 @@ impl CompatArgs for VenvCompatArgs { Ok(()) } } + +/// Arguments for `pip install` compatibility. +/// +/// These represent a subset of the `pip install` interface that uv supports by default. +#[derive(Args)] +#[allow(clippy::struct_excessive_bools)] +pub(crate) struct PipInstallCompatArgs { + #[clap(long, hide = false)] + user: bool, +} + +impl CompatArgs for PipInstallCompatArgs { + /// Validate the arguments passed for `pip install` compatibility. + /// + /// This method will warn when an argument is passed that has no effect but matches uv's + /// behavior. If an argument is passed that does _not_ match uv's behavior, this method will + /// return an error. + fn validate(&self) -> Result<()> { + if self.user { + return Err(anyhow!( + "pip install's `--user` is unsupported (use a virtual environment instead)." + )); + } + Ok(()) + } +} diff --git a/crates/uv/src/main.rs b/crates/uv/src/main.rs index 68bd09d18..ace68713c 100644 --- a/crates/uv/src/main.rs +++ b/crates/uv/src/main.rs @@ -285,6 +285,7 @@ async fn run() -> Result { Commands::Pip(PipNamespace { command: PipCommand::Install(args), }) => { + args.compat_args.validate()?; // Resolve the settings from the command-line arguments and workspace configuration. let args = PipInstallSettings::resolve(args, workspace); diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs index 4a771b0ae..1c8e4714a 100644 --- a/crates/uv/src/settings.rs +++ b/crates/uv/src/settings.rs @@ -456,6 +456,7 @@ impl PipInstallSettings { exclude_newer, dry_run, unstable_uv_lock_file, + compat_args: _, } = args; Self {