diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index 56a4f0a88186..ac3704ec8e40 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -827,6 +827,16 @@ fn parse_maybe_file_path(input: &str) -> Result, String> { } } +// Parse a string, mapping the empty string to `None`. +#[allow(clippy::unnecessary_wraps)] +fn parse_maybe_string(input: &str) -> Result, String> { + if input.is_empty() { + Ok(Maybe::None) + } else { + Ok(Maybe::Some(input.to_string())) + } +} + #[derive(Args)] #[allow(clippy::struct_excessive_bools)] pub struct PipCompileArgs { @@ -967,8 +977,8 @@ pub struct PipCompileArgs { /// /// See `uv help python` for details on Python discovery and supported /// request formats. - #[arg(long, verbatim_doc_comment, help_heading = "Python options")] - pub python: Option, + #[arg(long, verbatim_doc_comment, help_heading = "Python options", value_parser = parse_maybe_string)] + pub python: Option>, /// Install packages into the system Python environment. /// @@ -1221,9 +1231,10 @@ pub struct PipSyncArgs { short, env = "UV_PYTHON", verbatim_doc_comment, - help_heading = "Python options" + help_heading = "Python options", + value_parser = parse_maybe_string, )] - pub python: Option, + pub python: Option>, /// Install packages into the system Python environment. /// @@ -1503,9 +1514,10 @@ pub struct PipInstallArgs { short, env = "UV_PYTHON", verbatim_doc_comment, - help_heading = "Python options" + help_heading = "Python options", + value_parser = parse_maybe_string, )] - pub python: Option, + pub python: Option>, /// Install packages into the system Python environment. /// @@ -1668,9 +1680,10 @@ pub struct PipUninstallArgs { short, env = "UV_PYTHON", verbatim_doc_comment, - help_heading = "Python options" + help_heading = "Python options", + value_parser = parse_maybe_string, )] - pub python: Option, + pub python: Option>, /// Attempt to use `keyring` for authentication for remote requirements files. /// @@ -1776,9 +1789,10 @@ pub struct PipFreezeArgs { short, env = "UV_PYTHON", verbatim_doc_comment, - help_heading = "Python options" + help_heading = "Python options", + value_parser = parse_maybe_string, )] - pub python: Option, + pub python: Option>, /// List packages in the system Python environment. /// @@ -1840,9 +1854,10 @@ pub struct PipListArgs { short, env = "UV_PYTHON", verbatim_doc_comment, - help_heading = "Python options" + help_heading = "Python options", + value_parser = parse_maybe_string, )] - pub python: Option, + pub python: Option>, /// List packages in the system Python environment. /// @@ -1880,9 +1895,10 @@ pub struct PipCheckArgs { short, env = "UV_PYTHON", verbatim_doc_comment, - help_heading = "Python options" + help_heading = "Python options", + value_parser = parse_maybe_string, )] - pub python: Option, + pub python: Option>, /// Check packages in the system Python environment. /// @@ -1928,9 +1944,10 @@ pub struct PipShowArgs { short, env = "UV_PYTHON", verbatim_doc_comment, - help_heading = "Python options" + help_heading = "Python options", + value_parser = parse_maybe_string, )] - pub python: Option, + pub python: Option>, /// Show a package in the system Python environment. /// @@ -1983,9 +2000,10 @@ pub struct PipTreeArgs { short, env = "UV_PYTHON", verbatim_doc_comment, - help_heading = "Python options" + help_heading = "Python options", + value_parser = parse_maybe_string, )] - pub python: Option, + pub python: Option>, /// List packages in the system Python environment. /// @@ -2118,9 +2136,10 @@ pub struct BuildArgs { short, env = "UV_PYTHON", verbatim_doc_comment, - help_heading = "Python options" + help_heading = "Python options", + value_parser = parse_maybe_string, )] - pub python: Option, + pub python: Option>, #[command(flatten)] pub resolver: ResolverArgs, @@ -2147,9 +2166,10 @@ pub struct VenvArgs { short, env = "UV_PYTHON", verbatim_doc_comment, - help_heading = "Python options" + help_heading = "Python options", + value_parser = parse_maybe_string, )] - pub python: Option, + pub python: Option>, /// Ignore virtual environments when searching for the Python interpreter. /// @@ -2435,9 +2455,10 @@ pub struct InitArgs { short, env = "UV_PYTHON", verbatim_doc_comment, - help_heading = "Python options" + help_heading = "Python options", + value_parser = parse_maybe_string, )] - pub python: Option, + pub python: Option>, } #[derive(Args)] @@ -2610,9 +2631,10 @@ pub struct RunArgs { short, env = "UV_PYTHON", verbatim_doc_comment, - help_heading = "Python options" + help_heading = "Python options", + value_parser = parse_maybe_string, )] - pub python: Option, + pub python: Option>, /// Whether to show resolver and installer output from any environment modifications. /// @@ -2752,9 +2774,10 @@ pub struct SyncArgs { short, env = "UV_PYTHON", verbatim_doc_comment, - help_heading = "Python options" + help_heading = "Python options", + value_parser = parse_maybe_string, )] - pub python: Option, + pub python: Option>, } #[derive(Args)] @@ -2795,9 +2818,10 @@ pub struct LockArgs { short, env = "UV_PYTHON", verbatim_doc_comment, - help_heading = "Python options" + help_heading = "Python options", + value_parser = parse_maybe_string, )] - pub python: Option, + pub python: Option>, } #[derive(Args)] @@ -2917,9 +2941,10 @@ pub struct AddArgs { short, env = "UV_PYTHON", verbatim_doc_comment, - help_heading = "Python options" + help_heading = "Python options", + value_parser = parse_maybe_string, )] - pub python: Option, + pub python: Option>, } #[derive(Args)] @@ -2983,9 +3008,10 @@ pub struct RemoveArgs { short, env = "UV_PYTHON", verbatim_doc_comment, - help_heading = "Python options" + help_heading = "Python options", + value_parser = parse_maybe_string, )] - pub python: Option, + pub python: Option>, } #[derive(Args)] @@ -3057,9 +3083,10 @@ pub struct TreeArgs { short, env = "UV_PYTHON", verbatim_doc_comment, - help_heading = "Python options" + help_heading = "Python options", + value_parser = parse_maybe_string, )] - pub python: Option, + pub python: Option>, } #[derive(Args)] @@ -3181,9 +3208,10 @@ pub struct ExportArgs { short, env = "UV_PYTHON", verbatim_doc_comment, - help_heading = "Python options" + help_heading = "Python options", + value_parser = parse_maybe_string, )] - pub python: Option, + pub python: Option>, } #[derive(Args)] @@ -3330,9 +3358,10 @@ pub struct ToolRunArgs { short, env = "UV_PYTHON", verbatim_doc_comment, - help_heading = "Python options" + help_heading = "Python options", + value_parser = parse_maybe_string, )] - pub python: Option, + pub python: Option>, /// Whether to show resolver and installer output from any environment modifications. /// @@ -3391,9 +3420,10 @@ pub struct ToolInstallArgs { short, env = "UV_PYTHON", verbatim_doc_comment, - help_heading = "Python options" + help_heading = "Python options", + value_parser = parse_maybe_string, )] - pub python: Option, + pub python: Option>, } #[derive(Args)] @@ -3467,9 +3497,10 @@ pub struct ToolUpgradeArgs { short, env = "UV_PYTHON", verbatim_doc_comment, - help_heading = "Python options" + help_heading = "Python options", + value_parser = parse_maybe_string, )] - pub python: Option, + pub python: Option>, #[command(flatten)] pub installer: ResolverInstallerArgs, diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs index 582e20787cc6..d8ae29071941 100644 --- a/crates/uv/src/settings.rs +++ b/crates/uv/src/settings.rs @@ -208,7 +208,7 @@ impl InitSettings { no_readme, no_pin_python, no_workspace, - python, + python: python.and_then(Maybe::into_option), } } } @@ -286,7 +286,7 @@ impl RunSettings { package, no_project, no_sync, - python, + python: python.and_then(Maybe::into_option), refresh: Refresh::from(refresh), settings: ResolverInstallerSettings::combine( resolver_installer_options(installer, build), @@ -364,7 +364,7 @@ impl ToolRunSettings { .collect(), isolated, show_resolution, - python, + python: python.and_then(Maybe::into_option), refresh: Refresh::from(refresh), settings: ResolverInstallerSettings::combine( resolver_installer_options(installer, build), @@ -424,7 +424,7 @@ impl ToolInstallSettings { .into_iter() .filter_map(Maybe::into_option) .collect(), - python, + python: python.and_then(Maybe::into_option), force, editable, refresh: Refresh::from(refresh), @@ -472,7 +472,7 @@ impl ToolUpgradeSettings { Self { name: if all { vec![] } else { name }, - python, + python: python.and_then(Maybe::into_option), args, filesystem, } @@ -744,7 +744,7 @@ impl SyncSettings { Modifications::Sufficient }, package, - python, + python: python.and_then(Maybe::into_option), refresh: Refresh::from(refresh), settings, } @@ -778,7 +778,7 @@ impl LockSettings { Self { locked, frozen, - python, + python: python.and_then(Maybe::into_option), refresh: Refresh::from(refresh), settings: ResolverSettings::combine(resolver_options(resolver, build), filesystem), } @@ -856,7 +856,7 @@ impl AddSettings { branch, package, script, - python, + python: python.and_then(Maybe::into_option), editable: flag(editable, no_editable), extras: extra.unwrap_or_default(), refresh: Refresh::from(refresh), @@ -919,7 +919,7 @@ impl RemoveSettings { dependency_type, package, script, - python, + python: python.and_then(Maybe::into_option), refresh: Refresh::from(refresh), settings: ResolverInstallerSettings::combine( resolver_installer_options(installer, build), @@ -973,7 +973,7 @@ impl TreeSettings { invert: tree.invert, python_version, python_platform, - python, + python: python.and_then(Maybe::into_option), resolver: ResolverSettings::combine(resolver_options(resolver, build), filesystem), } } @@ -1044,7 +1044,7 @@ impl ExportSettings { output_file, locked, frozen, - python, + python: python.and_then(Maybe::into_option), refresh: Refresh::from(refresh), settings: ResolverSettings::combine(resolver_options(resolver, build), filesystem), } @@ -1173,7 +1173,7 @@ impl PipCompileSettings { refresh: Refresh::from(refresh), settings: PipSettings::combine( PipOptions { - python, + python: python.and_then(Maybe::into_option), system: flag(system, no_system), no_build: flag(no_build, build), no_binary, @@ -1266,7 +1266,7 @@ impl PipSyncSettings { refresh: Refresh::from(refresh), settings: PipSettings::combine( PipOptions { - python, + python: python.and_then(Maybe::into_option), system: flag(system, no_system), break_system_packages: flag(break_system_packages, no_break_system_packages), target, @@ -1398,7 +1398,7 @@ impl PipInstallSettings { refresh: Refresh::from(refresh), settings: PipSettings::combine( PipOptions { - python, + python: python.and_then(Maybe::into_option), system: flag(system, no_system), break_system_packages: flag(break_system_packages, no_break_system_packages), target, @@ -1454,7 +1454,7 @@ impl PipUninstallSettings { requirement, settings: PipSettings::combine( PipOptions { - python, + python: python.and_then(Maybe::into_option), system: flag(system, no_system), break_system_packages: flag(break_system_packages, no_break_system_packages), target, @@ -1499,7 +1499,7 @@ impl PipFreezeSettings { exclude_editable, settings: PipSettings::combine( PipOptions { - python, + python: python.and_then(Maybe::into_option), system: flag(system, no_system), strict: flag(strict, no_strict), ..PipOptions::default() @@ -1542,7 +1542,7 @@ impl PipListSettings { format, settings: PipSettings::combine( PipOptions { - python, + python: python.and_then(Maybe::into_option), system: flag(system, no_system), strict: flag(strict, no_strict), ..PipOptions::default() @@ -1578,7 +1578,7 @@ impl PipShowSettings { package, settings: PipSettings::combine( PipOptions { - python, + python: python.and_then(Maybe::into_option), system: flag(system, no_system), strict: flag(strict, no_strict), ..PipOptions::default() @@ -1627,7 +1627,7 @@ impl PipTreeSettings { // Shared settings. shared: PipSettings::combine( PipOptions { - python, + python: python.and_then(Maybe::into_option), system: flag(system, no_system), strict: flag(strict, no_strict), ..PipOptions::default() @@ -1657,7 +1657,7 @@ impl PipCheckSettings { Self { settings: PipSettings::combine( PipOptions { - python, + python: python.and_then(Maybe::into_option), system: flag(system, no_system), ..PipOptions::default() }, @@ -1724,7 +1724,7 @@ impl BuildSettings { flag(require_hashes, no_require_hashes).unwrap_or_default(), flag(verify_hashes, no_verify_hashes).unwrap_or_default(), ), - python, + python: python.and_then(Maybe::into_option), refresh: Refresh::from(refresh), settings: ResolverSettings::combine(resolver_options(resolver, build), filesystem), } @@ -1778,7 +1778,7 @@ impl VenvSettings { relocatable, settings: PipSettings::combine( PipOptions { - python, + python: python.and_then(Maybe::into_option), system: flag(system, no_system), index_strategy, keyring_provider,