mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 21:35:00 +00:00
Workaround for panic due to missing global validation in clap (#14368)
Clap does not perform global validation, so flag that are declared as overriding can be set at the same time: https://github.com/clap-rs/clap/issues/6049. This would previously cause a panic. We work around this by choosing the yes-value always and writing a warning. An alternative would be erroring when both are set, but it's unclear to me if this may break things we want to support. (`UV_OFFLINE=1 cargo run -q pip --no-offline install tqdm --no-cache` is already banned). Fixes https://github.com/astral-sh/uv/pull/14299 **Test Plan** ``` $ cargo run -q pip --offline install --no-offline tqdm --no-cache warning: Boolean flags on different levels are not correctly supported (https://github.com/clap-rs/clap/issues/6049) × No solution found when resolving dependencies: ╰─▶ Because tqdm was not found in the cache and you require tqdm, we can conclude that your requirements are unsatisfiable. hint: Packages were unavailable because the network was disabled. When the network is disabled, registry packages may only be read from the cache. ```
This commit is contained in:
parent
29fcd6faee
commit
06df95adbf
3 changed files with 170 additions and 97 deletions
|
@ -1,7 +1,10 @@
|
||||||
|
use anstream::eprintln;
|
||||||
|
|
||||||
use uv_cache::Refresh;
|
use uv_cache::Refresh;
|
||||||
use uv_configuration::ConfigSettings;
|
use uv_configuration::ConfigSettings;
|
||||||
use uv_resolver::PrereleaseMode;
|
use uv_resolver::PrereleaseMode;
|
||||||
use uv_settings::{Combine, PipOptions, ResolverInstallerOptions, ResolverOptions};
|
use uv_settings::{Combine, PipOptions, ResolverInstallerOptions, ResolverOptions};
|
||||||
|
use uv_warnings::owo_colors::OwoColorize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
BuildOptionsArgs, FetchArgs, IndexArgs, InstallerArgs, Maybe, RefreshArgs, ResolverArgs,
|
BuildOptionsArgs, FetchArgs, IndexArgs, InstallerArgs, Maybe, RefreshArgs, ResolverArgs,
|
||||||
|
@ -9,12 +12,27 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Given a boolean flag pair (like `--upgrade` and `--no-upgrade`), resolve the value of the flag.
|
/// Given a boolean flag pair (like `--upgrade` and `--no-upgrade`), resolve the value of the flag.
|
||||||
pub fn flag(yes: bool, no: bool) -> Option<bool> {
|
pub fn flag(yes: bool, no: bool, name: &str) -> Option<bool> {
|
||||||
match (yes, no) {
|
match (yes, no) {
|
||||||
(true, false) => Some(true),
|
(true, false) => Some(true),
|
||||||
(false, true) => Some(false),
|
(false, true) => Some(false),
|
||||||
(false, false) => None,
|
(false, false) => None,
|
||||||
(..) => unreachable!("Clap should make this impossible"),
|
(..) => {
|
||||||
|
eprintln!(
|
||||||
|
"{}{} `{}` and `{}` cannot be used together. \
|
||||||
|
Boolean flags on different levels are currently not supported \
|
||||||
|
(https://github.com/clap-rs/clap/issues/6049)",
|
||||||
|
"error".bold().red(),
|
||||||
|
":".bold(),
|
||||||
|
format!("--{name}").green(),
|
||||||
|
format!("--no-{name}").green(),
|
||||||
|
);
|
||||||
|
// No error forwarding since should eventually be solved on the clap side.
|
||||||
|
#[allow(clippy::exit)]
|
||||||
|
{
|
||||||
|
std::process::exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +44,7 @@ impl From<RefreshArgs> for Refresh {
|
||||||
refresh_package,
|
refresh_package,
|
||||||
} = value;
|
} = value;
|
||||||
|
|
||||||
Self::from_args(flag(refresh, no_refresh), refresh_package)
|
Self::from_args(flag(refresh, no_refresh, "no-refresh"), refresh_package)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +71,7 @@ impl From<ResolverArgs> for PipOptions {
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
upgrade: flag(upgrade, no_upgrade),
|
upgrade: flag(upgrade, no_upgrade, "no-upgrade"),
|
||||||
upgrade_package: Some(upgrade_package),
|
upgrade_package: Some(upgrade_package),
|
||||||
index_strategy,
|
index_strategy,
|
||||||
keyring_provider,
|
keyring_provider,
|
||||||
|
@ -66,7 +84,7 @@ impl From<ResolverArgs> for PipOptions {
|
||||||
},
|
},
|
||||||
config_settings: config_setting
|
config_settings: config_setting
|
||||||
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
|
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
|
||||||
no_build_isolation: flag(no_build_isolation, build_isolation),
|
no_build_isolation: flag(no_build_isolation, build_isolation, "build-isolation"),
|
||||||
no_build_isolation_package: Some(no_build_isolation_package),
|
no_build_isolation_package: Some(no_build_isolation_package),
|
||||||
exclude_newer,
|
exclude_newer,
|
||||||
link_mode,
|
link_mode,
|
||||||
|
@ -96,16 +114,16 @@ impl From<InstallerArgs> for PipOptions {
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
reinstall: flag(reinstall, no_reinstall),
|
reinstall: flag(reinstall, no_reinstall, "reinstall"),
|
||||||
reinstall_package: Some(reinstall_package),
|
reinstall_package: Some(reinstall_package),
|
||||||
index_strategy,
|
index_strategy,
|
||||||
keyring_provider,
|
keyring_provider,
|
||||||
config_settings: config_setting
|
config_settings: config_setting
|
||||||
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
|
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
|
||||||
no_build_isolation: flag(no_build_isolation, build_isolation),
|
no_build_isolation: flag(no_build_isolation, build_isolation, "build-isolation"),
|
||||||
exclude_newer,
|
exclude_newer,
|
||||||
link_mode,
|
link_mode,
|
||||||
compile_bytecode: flag(compile_bytecode, no_compile_bytecode),
|
compile_bytecode: flag(compile_bytecode, no_compile_bytecode, "compile-bytecode"),
|
||||||
no_sources: if no_sources { Some(true) } else { None },
|
no_sources: if no_sources { Some(true) } else { None },
|
||||||
..PipOptions::from(index_args)
|
..PipOptions::from(index_args)
|
||||||
}
|
}
|
||||||
|
@ -140,9 +158,9 @@ impl From<ResolverInstallerArgs> for PipOptions {
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
upgrade: flag(upgrade, no_upgrade),
|
upgrade: flag(upgrade, no_upgrade, "upgrade"),
|
||||||
upgrade_package: Some(upgrade_package),
|
upgrade_package: Some(upgrade_package),
|
||||||
reinstall: flag(reinstall, no_reinstall),
|
reinstall: flag(reinstall, no_reinstall, "reinstall"),
|
||||||
reinstall_package: Some(reinstall_package),
|
reinstall_package: Some(reinstall_package),
|
||||||
index_strategy,
|
index_strategy,
|
||||||
keyring_provider,
|
keyring_provider,
|
||||||
|
@ -155,11 +173,11 @@ impl From<ResolverInstallerArgs> for PipOptions {
|
||||||
fork_strategy,
|
fork_strategy,
|
||||||
config_settings: config_setting
|
config_settings: config_setting
|
||||||
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
|
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
|
||||||
no_build_isolation: flag(no_build_isolation, build_isolation),
|
no_build_isolation: flag(no_build_isolation, build_isolation, "build-isolation"),
|
||||||
no_build_isolation_package: Some(no_build_isolation_package),
|
no_build_isolation_package: Some(no_build_isolation_package),
|
||||||
exclude_newer,
|
exclude_newer,
|
||||||
link_mode,
|
link_mode,
|
||||||
compile_bytecode: flag(compile_bytecode, no_compile_bytecode),
|
compile_bytecode: flag(compile_bytecode, no_compile_bytecode, "compile-bytecode"),
|
||||||
no_sources: if no_sources { Some(true) } else { None },
|
no_sources: if no_sources { Some(true) } else { None },
|
||||||
..PipOptions::from(index_args)
|
..PipOptions::from(index_args)
|
||||||
}
|
}
|
||||||
|
@ -289,7 +307,7 @@ pub fn resolver_options(
|
||||||
.filter_map(Maybe::into_option)
|
.filter_map(Maybe::into_option)
|
||||||
.collect()
|
.collect()
|
||||||
}),
|
}),
|
||||||
upgrade: flag(upgrade, no_upgrade),
|
upgrade: flag(upgrade, no_upgrade, "no-upgrade"),
|
||||||
upgrade_package: Some(upgrade_package),
|
upgrade_package: Some(upgrade_package),
|
||||||
index_strategy,
|
index_strategy,
|
||||||
keyring_provider,
|
keyring_provider,
|
||||||
|
@ -303,13 +321,13 @@ pub fn resolver_options(
|
||||||
dependency_metadata: None,
|
dependency_metadata: None,
|
||||||
config_settings: config_setting
|
config_settings: config_setting
|
||||||
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
|
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
|
||||||
no_build_isolation: flag(no_build_isolation, build_isolation),
|
no_build_isolation: flag(no_build_isolation, build_isolation, "build-isolation"),
|
||||||
no_build_isolation_package: Some(no_build_isolation_package),
|
no_build_isolation_package: Some(no_build_isolation_package),
|
||||||
exclude_newer,
|
exclude_newer,
|
||||||
link_mode,
|
link_mode,
|
||||||
no_build: flag(no_build, build),
|
no_build: flag(no_build, build, "build"),
|
||||||
no_build_package: Some(no_build_package),
|
no_build_package: Some(no_build_package),
|
||||||
no_binary: flag(no_binary, binary),
|
no_binary: flag(no_binary, binary, "binary"),
|
||||||
no_binary_package: Some(no_binary_package),
|
no_binary_package: Some(no_binary_package),
|
||||||
no_sources: if no_sources { Some(true) } else { None },
|
no_sources: if no_sources { Some(true) } else { None },
|
||||||
}
|
}
|
||||||
|
@ -386,13 +404,13 @@ pub fn resolver_installer_options(
|
||||||
.filter_map(Maybe::into_option)
|
.filter_map(Maybe::into_option)
|
||||||
.collect()
|
.collect()
|
||||||
}),
|
}),
|
||||||
upgrade: flag(upgrade, no_upgrade),
|
upgrade: flag(upgrade, no_upgrade, "upgrade"),
|
||||||
upgrade_package: if upgrade_package.is_empty() {
|
upgrade_package: if upgrade_package.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(upgrade_package)
|
Some(upgrade_package)
|
||||||
},
|
},
|
||||||
reinstall: flag(reinstall, no_reinstall),
|
reinstall: flag(reinstall, no_reinstall, "reinstall"),
|
||||||
reinstall_package: if reinstall_package.is_empty() {
|
reinstall_package: if reinstall_package.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
@ -410,7 +428,7 @@ pub fn resolver_installer_options(
|
||||||
dependency_metadata: None,
|
dependency_metadata: None,
|
||||||
config_settings: config_setting
|
config_settings: config_setting
|
||||||
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
|
.map(|config_settings| config_settings.into_iter().collect::<ConfigSettings>()),
|
||||||
no_build_isolation: flag(no_build_isolation, build_isolation),
|
no_build_isolation: flag(no_build_isolation, build_isolation, "build-isolation"),
|
||||||
no_build_isolation_package: if no_build_isolation_package.is_empty() {
|
no_build_isolation_package: if no_build_isolation_package.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
@ -418,14 +436,14 @@ pub fn resolver_installer_options(
|
||||||
},
|
},
|
||||||
exclude_newer,
|
exclude_newer,
|
||||||
link_mode,
|
link_mode,
|
||||||
compile_bytecode: flag(compile_bytecode, no_compile_bytecode),
|
compile_bytecode: flag(compile_bytecode, no_compile_bytecode, "compile-bytecode"),
|
||||||
no_build: flag(no_build, build),
|
no_build: flag(no_build, build, "build"),
|
||||||
no_build_package: if no_build_package.is_empty() {
|
no_build_package: if no_build_package.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(no_build_package)
|
Some(no_build_package)
|
||||||
},
|
},
|
||||||
no_binary: flag(no_binary, binary),
|
no_binary: flag(no_binary, binary, "binary"),
|
||||||
no_binary_package: if no_binary_package.is_empty() {
|
no_binary_package: if no_binary_package.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -118,16 +118,20 @@ impl GlobalSettings {
|
||||||
},
|
},
|
||||||
show_settings: args.show_settings,
|
show_settings: args.show_settings,
|
||||||
preview: PreviewMode::from(
|
preview: PreviewMode::from(
|
||||||
flag(args.preview, args.no_preview)
|
flag(args.preview, args.no_preview, "preview")
|
||||||
.combine(workspace.and_then(|workspace| workspace.globals.preview))
|
.combine(workspace.and_then(|workspace| workspace.globals.preview))
|
||||||
.unwrap_or(false),
|
.unwrap_or(false),
|
||||||
),
|
),
|
||||||
python_preference,
|
python_preference,
|
||||||
python_downloads: flag(args.allow_python_downloads, args.no_python_downloads)
|
python_downloads: flag(
|
||||||
.map(PythonDownloads::from)
|
args.allow_python_downloads,
|
||||||
.combine(env(env::UV_PYTHON_DOWNLOADS))
|
args.no_python_downloads,
|
||||||
.combine(workspace.and_then(|workspace| workspace.globals.python_downloads))
|
"python-downloads",
|
||||||
.unwrap_or_default(),
|
)
|
||||||
|
.map(PythonDownloads::from)
|
||||||
|
.combine(env(env::UV_PYTHON_DOWNLOADS))
|
||||||
|
.combine(workspace.and_then(|workspace| workspace.globals.python_downloads))
|
||||||
|
.unwrap_or_default(),
|
||||||
// Disable the progress bar with `RUST_LOG` to avoid progress fragments interleaving
|
// Disable the progress bar with `RUST_LOG` to avoid progress fragments interleaving
|
||||||
// with log messages.
|
// with log messages.
|
||||||
no_progress: args.no_progress || std::env::var_os(EnvVars::RUST_LOG).is_some(),
|
no_progress: args.no_progress || std::env::var_os(EnvVars::RUST_LOG).is_some(),
|
||||||
|
@ -161,7 +165,7 @@ pub(crate) struct NetworkSettings {
|
||||||
|
|
||||||
impl NetworkSettings {
|
impl NetworkSettings {
|
||||||
pub(crate) fn resolve(args: &GlobalArgs, workspace: Option<&FilesystemOptions>) -> Self {
|
pub(crate) fn resolve(args: &GlobalArgs, workspace: Option<&FilesystemOptions>) -> Self {
|
||||||
let connectivity = if flag(args.offline, args.no_offline)
|
let connectivity = if flag(args.offline, args.no_offline, "offline")
|
||||||
.combine(workspace.and_then(|workspace| workspace.globals.offline))
|
.combine(workspace.and_then(|workspace| workspace.globals.offline))
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
|
@ -169,7 +173,7 @@ impl NetworkSettings {
|
||||||
} else {
|
} else {
|
||||||
Connectivity::Online
|
Connectivity::Online
|
||||||
};
|
};
|
||||||
let native_tls = flag(args.native_tls, args.no_native_tls)
|
let native_tls = flag(args.native_tls, args.no_native_tls, "native-tls")
|
||||||
.combine(workspace.and_then(|workspace| workspace.globals.native_tls))
|
.combine(workspace.and_then(|workspace| workspace.globals.native_tls))
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
let allow_insecure_host = args
|
let allow_insecure_host = args
|
||||||
|
@ -274,8 +278,12 @@ impl InitSettings {
|
||||||
(_, _, _) => unreachable!("`app`, `lib`, and `script` are mutually exclusive"),
|
(_, _, _) => unreachable!("`app`, `lib`, and `script` are mutually exclusive"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let package = flag(package || build_backend.is_some(), no_package || r#virtual)
|
let package = flag(
|
||||||
.unwrap_or(kind.packaged_by_default());
|
package || build_backend.is_some(),
|
||||||
|
no_package || r#virtual,
|
||||||
|
"virtual",
|
||||||
|
)
|
||||||
|
.unwrap_or(kind.packaged_by_default());
|
||||||
|
|
||||||
let install_mirrors = filesystem
|
let install_mirrors = filesystem
|
||||||
.map(|fs| fs.install_mirrors.clone())
|
.map(|fs| fs.install_mirrors.clone())
|
||||||
|
@ -295,7 +303,7 @@ impl InitSettings {
|
||||||
build_backend,
|
build_backend,
|
||||||
no_readme: no_readme || bare,
|
no_readme: no_readme || bare,
|
||||||
author_from,
|
author_from,
|
||||||
pin_python: flag(pin_python, no_pin_python).unwrap_or(!bare),
|
pin_python: flag(pin_python, no_pin_python, "pin-python").unwrap_or(!bare),
|
||||||
no_workspace,
|
no_workspace,
|
||||||
python: python.and_then(Maybe::into_option),
|
python: python.and_then(Maybe::into_option),
|
||||||
install_mirrors,
|
install_mirrors,
|
||||||
|
@ -398,7 +406,7 @@ impl RunSettings {
|
||||||
false,
|
false,
|
||||||
// TODO(blueraft): support only_extra
|
// TODO(blueraft): support only_extra
|
||||||
vec![],
|
vec![],
|
||||||
flag(all_extras, no_all_extras).unwrap_or_default(),
|
flag(all_extras, no_all_extras, "all-extras").unwrap_or_default(),
|
||||||
),
|
),
|
||||||
groups: DependencyGroups::from_args(
|
groups: DependencyGroups::from_args(
|
||||||
dev,
|
dev,
|
||||||
|
@ -411,7 +419,7 @@ impl RunSettings {
|
||||||
all_groups,
|
all_groups,
|
||||||
),
|
),
|
||||||
editable: EditableMode::from_args(no_editable),
|
editable: EditableMode::from_args(no_editable),
|
||||||
modifications: if flag(exact, inexact).unwrap_or(false) {
|
modifications: if flag(exact, inexact, "inexact").unwrap_or(false) {
|
||||||
Modifications::Exact
|
Modifications::Exact
|
||||||
} else {
|
} else {
|
||||||
Modifications::Sufficient
|
Modifications::Sufficient
|
||||||
|
@ -434,7 +442,7 @@ impl RunSettings {
|
||||||
package,
|
package,
|
||||||
no_project,
|
no_project,
|
||||||
no_sync,
|
no_sync,
|
||||||
active: flag(active, no_active),
|
active: flag(active, no_active, "active"),
|
||||||
python: python.and_then(Maybe::into_option),
|
python: python.and_then(Maybe::into_option),
|
||||||
refresh: Refresh::from(refresh),
|
refresh: Refresh::from(refresh),
|
||||||
settings: ResolverInstallerSettings::combine(
|
settings: ResolverInstallerSettings::combine(
|
||||||
|
@ -1081,7 +1089,7 @@ impl PythonFindSettings {
|
||||||
request,
|
request,
|
||||||
show_version,
|
show_version,
|
||||||
no_project,
|
no_project,
|
||||||
system: flag(system, no_system).unwrap_or_default(),
|
system: flag(system, no_system, "system").unwrap_or_default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1116,7 +1124,7 @@ impl PythonPinSettings {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
request,
|
request,
|
||||||
resolved: flag(resolved, no_resolved).unwrap_or(false),
|
resolved: flag(resolved, no_resolved, "resolved").unwrap_or(false),
|
||||||
no_project,
|
no_project,
|
||||||
global,
|
global,
|
||||||
rm,
|
rm,
|
||||||
|
@ -1195,7 +1203,7 @@ impl SyncSettings {
|
||||||
filesystem,
|
filesystem,
|
||||||
);
|
);
|
||||||
|
|
||||||
let check = flag(check, no_check).unwrap_or_default();
|
let check = flag(check, no_check, "check").unwrap_or_default();
|
||||||
let dry_run = if check {
|
let dry_run = if check {
|
||||||
DryRun::Check
|
DryRun::Check
|
||||||
} else {
|
} else {
|
||||||
|
@ -1207,7 +1215,7 @@ impl SyncSettings {
|
||||||
frozen,
|
frozen,
|
||||||
dry_run,
|
dry_run,
|
||||||
script,
|
script,
|
||||||
active: flag(active, no_active),
|
active: flag(active, no_active, "active"),
|
||||||
extras: ExtrasSpecification::from_args(
|
extras: ExtrasSpecification::from_args(
|
||||||
extra.unwrap_or_default(),
|
extra.unwrap_or_default(),
|
||||||
no_extra,
|
no_extra,
|
||||||
|
@ -1215,7 +1223,7 @@ impl SyncSettings {
|
||||||
false,
|
false,
|
||||||
// TODO(blueraft): support only_extra
|
// TODO(blueraft): support only_extra
|
||||||
vec![],
|
vec![],
|
||||||
flag(all_extras, no_all_extras).unwrap_or_default(),
|
flag(all_extras, no_all_extras, "all-extras").unwrap_or_default(),
|
||||||
),
|
),
|
||||||
groups: DependencyGroups::from_args(
|
groups: DependencyGroups::from_args(
|
||||||
dev,
|
dev,
|
||||||
|
@ -1233,7 +1241,7 @@ impl SyncSettings {
|
||||||
no_install_workspace,
|
no_install_workspace,
|
||||||
no_install_package,
|
no_install_package,
|
||||||
),
|
),
|
||||||
modifications: if flag(exact, inexact).unwrap_or(true) {
|
modifications: if flag(exact, inexact, "inexact").unwrap_or(true) {
|
||||||
Modifications::Exact
|
Modifications::Exact
|
||||||
} else {
|
} else {
|
||||||
Modifications::Sufficient
|
Modifications::Sufficient
|
||||||
|
@ -1437,7 +1445,7 @@ impl AddSettings {
|
||||||
Self {
|
Self {
|
||||||
locked,
|
locked,
|
||||||
frozen,
|
frozen,
|
||||||
active: flag(active, no_active),
|
active: flag(active, no_active, "active"),
|
||||||
no_sync,
|
no_sync,
|
||||||
packages,
|
packages,
|
||||||
requirements,
|
requirements,
|
||||||
|
@ -1455,7 +1463,7 @@ impl AddSettings {
|
||||||
package,
|
package,
|
||||||
script,
|
script,
|
||||||
python: python.and_then(Maybe::into_option),
|
python: python.and_then(Maybe::into_option),
|
||||||
editable: flag(editable, no_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),
|
||||||
indexes,
|
indexes,
|
||||||
|
@ -1531,7 +1539,7 @@ impl RemoveSettings {
|
||||||
Self {
|
Self {
|
||||||
locked,
|
locked,
|
||||||
frozen,
|
frozen,
|
||||||
active: flag(active, no_active),
|
active: flag(active, no_active, "active"),
|
||||||
no_sync,
|
no_sync,
|
||||||
packages,
|
packages,
|
||||||
dependency_type,
|
dependency_type,
|
||||||
|
@ -1603,7 +1611,7 @@ impl VersionSettings {
|
||||||
dry_run,
|
dry_run,
|
||||||
locked,
|
locked,
|
||||||
frozen,
|
frozen,
|
||||||
active: flag(active, no_active),
|
active: flag(active, no_active, "active"),
|
||||||
no_sync,
|
no_sync,
|
||||||
package,
|
package,
|
||||||
python: python.and_then(Maybe::into_option),
|
python: python.and_then(Maybe::into_option),
|
||||||
|
@ -1779,7 +1787,7 @@ impl ExportSettings {
|
||||||
false,
|
false,
|
||||||
// TODO(blueraft): support only_extra
|
// TODO(blueraft): support only_extra
|
||||||
vec![],
|
vec![],
|
||||||
flag(all_extras, no_all_extras).unwrap_or_default(),
|
flag(all_extras, no_all_extras, "all-extras").unwrap_or_default(),
|
||||||
),
|
),
|
||||||
groups: DependencyGroups::from_args(
|
groups: DependencyGroups::from_args(
|
||||||
dev,
|
dev,
|
||||||
|
@ -1792,7 +1800,7 @@ impl ExportSettings {
|
||||||
all_groups,
|
all_groups,
|
||||||
),
|
),
|
||||||
editable: EditableMode::from_args(no_editable),
|
editable: EditableMode::from_args(no_editable),
|
||||||
hashes: flag(hashes, no_hashes).unwrap_or(true),
|
hashes: flag(hashes, no_hashes, "hashes").unwrap_or(true),
|
||||||
install_options: InstallOptions::new(
|
install_options: InstallOptions::new(
|
||||||
no_emit_project,
|
no_emit_project,
|
||||||
no_emit_workspace,
|
no_emit_workspace,
|
||||||
|
@ -1801,8 +1809,8 @@ impl ExportSettings {
|
||||||
output_file,
|
output_file,
|
||||||
locked,
|
locked,
|
||||||
frozen,
|
frozen,
|
||||||
include_annotations: flag(annotate, no_annotate).unwrap_or(true),
|
include_annotations: flag(annotate, no_annotate, "annotate").unwrap_or(true),
|
||||||
include_header: flag(header, no_header).unwrap_or(true),
|
include_header: flag(header, no_header, "header").unwrap_or(true),
|
||||||
script,
|
script,
|
||||||
python: python.and_then(Maybe::into_option),
|
python: python.and_then(Maybe::into_option),
|
||||||
refresh: Refresh::from(refresh),
|
refresh: Refresh::from(refresh),
|
||||||
|
@ -1955,30 +1963,42 @@ impl PipCompileSettings {
|
||||||
settings: PipSettings::combine(
|
settings: PipSettings::combine(
|
||||||
PipOptions {
|
PipOptions {
|
||||||
python: python.and_then(Maybe::into_option),
|
python: python.and_then(Maybe::into_option),
|
||||||
system: flag(system, no_system),
|
system: flag(system, no_system, "system"),
|
||||||
no_build: flag(no_build, build),
|
no_build: flag(no_build, build, "build"),
|
||||||
no_binary,
|
no_binary,
|
||||||
only_binary,
|
only_binary,
|
||||||
extra,
|
extra,
|
||||||
all_extras: flag(all_extras, no_all_extras),
|
all_extras: flag(all_extras, no_all_extras, "all-extras"),
|
||||||
no_deps: flag(no_deps, deps),
|
no_deps: flag(no_deps, deps, "deps"),
|
||||||
group: Some(group),
|
group: Some(group),
|
||||||
output_file,
|
output_file,
|
||||||
no_strip_extras: flag(no_strip_extras, strip_extras),
|
no_strip_extras: flag(no_strip_extras, strip_extras, "strip-extras"),
|
||||||
no_strip_markers: flag(no_strip_markers, strip_markers),
|
no_strip_markers: flag(no_strip_markers, strip_markers, "strip-markers"),
|
||||||
no_annotate: flag(no_annotate, annotate),
|
no_annotate: flag(no_annotate, annotate, "annotate"),
|
||||||
no_header: flag(no_header, header),
|
no_header: flag(no_header, header, "header"),
|
||||||
custom_compile_command,
|
custom_compile_command,
|
||||||
generate_hashes: flag(generate_hashes, no_generate_hashes),
|
generate_hashes: flag(generate_hashes, no_generate_hashes, "generate-hashes"),
|
||||||
python_version,
|
python_version,
|
||||||
python_platform,
|
python_platform,
|
||||||
universal: flag(universal, no_universal),
|
universal: flag(universal, no_universal, "universal"),
|
||||||
no_emit_package,
|
no_emit_package,
|
||||||
emit_index_url: flag(emit_index_url, no_emit_index_url),
|
emit_index_url: flag(emit_index_url, no_emit_index_url, "emit-index-url"),
|
||||||
emit_find_links: flag(emit_find_links, no_emit_find_links),
|
emit_find_links: flag(emit_find_links, no_emit_find_links, "emit-find-links"),
|
||||||
emit_build_options: flag(emit_build_options, no_emit_build_options),
|
emit_build_options: flag(
|
||||||
emit_marker_expression: flag(emit_marker_expression, no_emit_marker_expression),
|
emit_build_options,
|
||||||
emit_index_annotation: flag(emit_index_annotation, no_emit_index_annotation),
|
no_emit_build_options,
|
||||||
|
"emit-build-options",
|
||||||
|
),
|
||||||
|
emit_marker_expression: flag(
|
||||||
|
emit_marker_expression,
|
||||||
|
no_emit_marker_expression,
|
||||||
|
"emit-marker-expression",
|
||||||
|
),
|
||||||
|
emit_index_annotation: flag(
|
||||||
|
emit_index_annotation,
|
||||||
|
no_emit_index_annotation,
|
||||||
|
"emit-index-annotation",
|
||||||
|
),
|
||||||
annotation_style,
|
annotation_style,
|
||||||
torch_backend,
|
torch_backend,
|
||||||
..PipOptions::from(resolver)
|
..PipOptions::from(resolver)
|
||||||
|
@ -2050,22 +2070,27 @@ impl PipSyncSettings {
|
||||||
settings: PipSettings::combine(
|
settings: PipSettings::combine(
|
||||||
PipOptions {
|
PipOptions {
|
||||||
python: python.and_then(Maybe::into_option),
|
python: python.and_then(Maybe::into_option),
|
||||||
system: flag(system, no_system),
|
system: flag(system, no_system, "system"),
|
||||||
break_system_packages: flag(break_system_packages, no_break_system_packages),
|
break_system_packages: flag(
|
||||||
|
break_system_packages,
|
||||||
|
no_break_system_packages,
|
||||||
|
"break-system-packages",
|
||||||
|
),
|
||||||
target,
|
target,
|
||||||
prefix,
|
prefix,
|
||||||
require_hashes: flag(require_hashes, no_require_hashes),
|
require_hashes: flag(require_hashes, no_require_hashes, "require-hashes"),
|
||||||
verify_hashes: flag(verify_hashes, no_verify_hashes),
|
verify_hashes: flag(verify_hashes, no_verify_hashes, "verify-hashes"),
|
||||||
no_build: flag(no_build, build),
|
no_build: flag(no_build, build, "build"),
|
||||||
no_binary,
|
no_binary,
|
||||||
only_binary,
|
only_binary,
|
||||||
allow_empty_requirements: flag(
|
allow_empty_requirements: flag(
|
||||||
allow_empty_requirements,
|
allow_empty_requirements,
|
||||||
no_allow_empty_requirements,
|
no_allow_empty_requirements,
|
||||||
|
"allow-empty-requirements",
|
||||||
),
|
),
|
||||||
python_version,
|
python_version,
|
||||||
python_platform,
|
python_platform,
|
||||||
strict: flag(strict, no_strict),
|
strict: flag(strict, no_strict, "strict"),
|
||||||
torch_backend,
|
torch_backend,
|
||||||
..PipOptions::from(installer)
|
..PipOptions::from(installer)
|
||||||
},
|
},
|
||||||
|
@ -2199,7 +2224,7 @@ impl PipInstallSettings {
|
||||||
constraints_from_workspace,
|
constraints_from_workspace,
|
||||||
overrides_from_workspace,
|
overrides_from_workspace,
|
||||||
build_constraints_from_workspace,
|
build_constraints_from_workspace,
|
||||||
modifications: if flag(exact, inexact).unwrap_or(false) {
|
modifications: if flag(exact, inexact, "inexact").unwrap_or(false) {
|
||||||
Modifications::Exact
|
Modifications::Exact
|
||||||
} else {
|
} else {
|
||||||
Modifications::Sufficient
|
Modifications::Sufficient
|
||||||
|
@ -2208,22 +2233,26 @@ impl PipInstallSettings {
|
||||||
settings: PipSettings::combine(
|
settings: PipSettings::combine(
|
||||||
PipOptions {
|
PipOptions {
|
||||||
python: python.and_then(Maybe::into_option),
|
python: python.and_then(Maybe::into_option),
|
||||||
system: flag(system, no_system),
|
system: flag(system, no_system, "system"),
|
||||||
break_system_packages: flag(break_system_packages, no_break_system_packages),
|
break_system_packages: flag(
|
||||||
|
break_system_packages,
|
||||||
|
no_break_system_packages,
|
||||||
|
"break-system-packages",
|
||||||
|
),
|
||||||
target,
|
target,
|
||||||
prefix,
|
prefix,
|
||||||
no_build: flag(no_build, build),
|
no_build: flag(no_build, build, "build"),
|
||||||
no_binary,
|
no_binary,
|
||||||
only_binary,
|
only_binary,
|
||||||
strict: flag(strict, no_strict),
|
strict: flag(strict, no_strict, "strict"),
|
||||||
extra,
|
extra,
|
||||||
all_extras: flag(all_extras, no_all_extras),
|
all_extras: flag(all_extras, no_all_extras, "all-extras"),
|
||||||
group: Some(group),
|
group: Some(group),
|
||||||
no_deps: flag(no_deps, deps),
|
no_deps: flag(no_deps, deps, "deps"),
|
||||||
python_version,
|
python_version,
|
||||||
python_platform,
|
python_platform,
|
||||||
require_hashes: flag(require_hashes, no_require_hashes),
|
require_hashes: flag(require_hashes, no_require_hashes, "require-hashes"),
|
||||||
verify_hashes: flag(verify_hashes, no_verify_hashes),
|
verify_hashes: flag(verify_hashes, no_verify_hashes, "verify-hashes"),
|
||||||
torch_backend,
|
torch_backend,
|
||||||
..PipOptions::from(installer)
|
..PipOptions::from(installer)
|
||||||
},
|
},
|
||||||
|
@ -2267,8 +2296,12 @@ impl PipUninstallSettings {
|
||||||
settings: PipSettings::combine(
|
settings: PipSettings::combine(
|
||||||
PipOptions {
|
PipOptions {
|
||||||
python: python.and_then(Maybe::into_option),
|
python: python.and_then(Maybe::into_option),
|
||||||
system: flag(system, no_system),
|
system: flag(system, no_system, "system"),
|
||||||
break_system_packages: flag(break_system_packages, no_break_system_packages),
|
break_system_packages: flag(
|
||||||
|
break_system_packages,
|
||||||
|
no_break_system_packages,
|
||||||
|
"break-system-packages",
|
||||||
|
),
|
||||||
target,
|
target,
|
||||||
prefix,
|
prefix,
|
||||||
keyring_provider,
|
keyring_provider,
|
||||||
|
@ -2308,8 +2341,8 @@ impl PipFreezeSettings {
|
||||||
settings: PipSettings::combine(
|
settings: PipSettings::combine(
|
||||||
PipOptions {
|
PipOptions {
|
||||||
python: python.and_then(Maybe::into_option),
|
python: python.and_then(Maybe::into_option),
|
||||||
system: flag(system, no_system),
|
system: flag(system, no_system, "system"),
|
||||||
strict: flag(strict, no_strict),
|
strict: flag(strict, no_strict, "strict"),
|
||||||
..PipOptions::default()
|
..PipOptions::default()
|
||||||
},
|
},
|
||||||
filesystem,
|
filesystem,
|
||||||
|
@ -2348,15 +2381,15 @@ impl PipListSettings {
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
editable: flag(editable, exclude_editable),
|
editable: flag(editable, exclude_editable, "exclude-editable"),
|
||||||
exclude,
|
exclude,
|
||||||
format,
|
format,
|
||||||
outdated: flag(outdated, no_outdated).unwrap_or(false),
|
outdated: flag(outdated, no_outdated, "outdated").unwrap_or(false),
|
||||||
settings: PipSettings::combine(
|
settings: PipSettings::combine(
|
||||||
PipOptions {
|
PipOptions {
|
||||||
python: python.and_then(Maybe::into_option),
|
python: python.and_then(Maybe::into_option),
|
||||||
system: flag(system, no_system),
|
system: flag(system, no_system, "system"),
|
||||||
strict: flag(strict, no_strict),
|
strict: flag(strict, no_strict, "strict"),
|
||||||
..PipOptions::from(fetch)
|
..PipOptions::from(fetch)
|
||||||
},
|
},
|
||||||
filesystem,
|
filesystem,
|
||||||
|
@ -2393,8 +2426,8 @@ impl PipShowSettings {
|
||||||
settings: PipSettings::combine(
|
settings: PipSettings::combine(
|
||||||
PipOptions {
|
PipOptions {
|
||||||
python: python.and_then(Maybe::into_option),
|
python: python.and_then(Maybe::into_option),
|
||||||
system: flag(system, no_system),
|
system: flag(system, no_system, "system"),
|
||||||
strict: flag(strict, no_strict),
|
strict: flag(strict, no_strict, "strict"),
|
||||||
..PipOptions::default()
|
..PipOptions::default()
|
||||||
},
|
},
|
||||||
filesystem,
|
filesystem,
|
||||||
|
@ -2442,8 +2475,8 @@ impl PipTreeSettings {
|
||||||
settings: PipSettings::combine(
|
settings: PipSettings::combine(
|
||||||
PipOptions {
|
PipOptions {
|
||||||
python: python.and_then(Maybe::into_option),
|
python: python.and_then(Maybe::into_option),
|
||||||
system: flag(system, no_system),
|
system: flag(system, no_system, "system"),
|
||||||
strict: flag(strict, no_strict),
|
strict: flag(strict, no_strict, "strict"),
|
||||||
..PipOptions::from(fetch)
|
..PipOptions::from(fetch)
|
||||||
},
|
},
|
||||||
filesystem,
|
filesystem,
|
||||||
|
@ -2471,7 +2504,7 @@ impl PipCheckSettings {
|
||||||
settings: PipSettings::combine(
|
settings: PipSettings::combine(
|
||||||
PipOptions {
|
PipOptions {
|
||||||
python: python.and_then(Maybe::into_option),
|
python: python.and_then(Maybe::into_option),
|
||||||
system: flag(system, no_system),
|
system: flag(system, no_system, "system"),
|
||||||
..PipOptions::default()
|
..PipOptions::default()
|
||||||
},
|
},
|
||||||
filesystem,
|
filesystem,
|
||||||
|
@ -2538,15 +2571,15 @@ impl BuildSettings {
|
||||||
sdist,
|
sdist,
|
||||||
wheel,
|
wheel,
|
||||||
list,
|
list,
|
||||||
build_logs: flag(build_logs, no_build_logs).unwrap_or(true),
|
build_logs: flag(build_logs, no_build_logs, "build-logs").unwrap_or(true),
|
||||||
build_constraints: build_constraints
|
build_constraints: build_constraints
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(Maybe::into_option)
|
.filter_map(Maybe::into_option)
|
||||||
.collect(),
|
.collect(),
|
||||||
force_pep517,
|
force_pep517,
|
||||||
hash_checking: HashCheckingMode::from_args(
|
hash_checking: HashCheckingMode::from_args(
|
||||||
flag(require_hashes, no_require_hashes),
|
flag(require_hashes, no_require_hashes, "require-hashes"),
|
||||||
flag(verify_hashes, no_verify_hashes),
|
flag(verify_hashes, no_verify_hashes, "verify-hashes"),
|
||||||
),
|
),
|
||||||
python: python.and_then(Maybe::into_option),
|
python: python.and_then(Maybe::into_option),
|
||||||
refresh: Refresh::from(refresh),
|
refresh: Refresh::from(refresh),
|
||||||
|
@ -2605,7 +2638,7 @@ impl VenvSettings {
|
||||||
settings: PipSettings::combine(
|
settings: PipSettings::combine(
|
||||||
PipOptions {
|
PipOptions {
|
||||||
python: python.and_then(Maybe::into_option),
|
python: python.and_then(Maybe::into_option),
|
||||||
system: flag(system, no_system),
|
system: flag(system, no_system, "system"),
|
||||||
index_strategy,
|
index_strategy,
|
||||||
keyring_provider,
|
keyring_provider,
|
||||||
exclude_newer,
|
exclude_newer,
|
||||||
|
|
|
@ -11486,3 +11486,25 @@ fn pep_751_dependency() -> Result<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Test that we show an error instead of panicking for conflicting arguments in different levels,
|
||||||
|
/// which are not caught by clap.
|
||||||
|
#[test]
|
||||||
|
fn conflicting_flags_clap_bug() {
|
||||||
|
let context = TestContext::new("3.12");
|
||||||
|
|
||||||
|
uv_snapshot!(context.filters(), context.command()
|
||||||
|
.arg("pip")
|
||||||
|
.arg("--offline")
|
||||||
|
.arg("install")
|
||||||
|
.arg("--no-offline")
|
||||||
|
.arg("tqdm"), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: `--offline` and `--no-offline` cannot be used together. Boolean flags on different levels are currently not supported (https://github.com/clap-rs/clap/issues/6049)
|
||||||
|
"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue