use std::env::VarError;
use std::num::NonZeroUsize;
use std::path::PathBuf;
use std::process;
use std::str::FromStr;
use std::time::Duration;
use rustc_hash::FxHashSet;
use uv_audit::service::VulnerabilityServiceFormat;
use uv_audit::types::VulnerabilityID;
use crate::commands::{PythonUpgrade, PythonUpgradeSource};
use uv_auth::Service;
use uv_cache::{CacheArgs, Refresh};
use uv_cli::comma::CommaSeparatedRequirements;
use uv_cli::{
AddArgs, AuditArgs, AuthLoginArgs, AuthLogoutArgs, AuthTokenArgs, ColorChoice, ExternalCommand,
GlobalArgs, InitArgs, ListFormat, LockArgs, Maybe, MetadataArgs, PipCheckArgs, PipCompileArgs,
PipFreezeArgs, PipInstallArgs, PipListArgs, PipShowArgs, PipSyncArgs, PipTreeArgs,
PipUninstallArgs, PythonFindArgs, PythonInstallArgs, PythonListArgs, PythonListFormat,
PythonPinArgs, PythonUninstallArgs, PythonUpgradeArgs, RemoveArgs, RunArgs, SyncArgs,
SyncFormat, ToolDirArgs, ToolInstallArgs, ToolListArgs, ToolRunArgs, ToolUninstallArgs,
TreeArgs, VenvArgs, VersionArgs, VersionBumpSpec, VersionFormat,
};
use uv_cli::{
AuthorFrom, BuildArgs, ExportArgs, FormatArgs, PublishArgs, PythonDirArgs,
ResolverInstallerArgs, ToolUpgradeArgs,
options::{
Flag, FlagSource, check_conflicts, flag, resolve_flag, resolve_flag_pair,
resolver_installer_options, resolver_options,
},
};
use uv_client::Connectivity;
use uv_configuration::{
BuildIsolation, BuildOptions, Concurrency, DependencyGroups, DryRun, EditableMode, EnvFile,
ExportFormat, ExtrasSpecification, GitLfsSetting, HashCheckingMode, IndexStrategy,
InstallOptions, KeyringProviderType, NoBinary, NoBuild, NoSources, PipCompileFormat,
ProjectBuildBackend, ProxyUrl, Reinstall, RequiredVersion, TargetTriple, TrustedHost,
TrustedPublishing, Upgrade, VersionControlSystem,
};
use uv_distribution_types::{
ConfigSettings, DependencyMetadata, ExtraBuildVariables, Index, IndexLocations, IndexUrl,
PackageConfigSettings, Requirement,
};
use uv_install_wheel::LinkMode;
use uv_normalize::{ExtraName, PackageName, PipGroupName};
use uv_pep508::{MarkerTree, RequirementOrigin};
use uv_preview::Preview;
use uv_pypi_types::SupportedEnvironments;
use uv_python::{Prefix, PythonDownloads, PythonPreference, PythonVersion, Target};
use uv_redacted::DisplaySafeUrl;
use uv_resolver::{
AnnotationStyle, DependencyMode, ExcludeNewer, ExcludeNewerPackage, ForkStrategy,
PrereleaseMode, ResolutionMode,
};
use uv_settings::{
Combine, EnvironmentOptions, FilesystemOptions, Options, PipOptions, PublishOptions,
PythonInstallMirrors, ResolverInstallerOptions, ResolverInstallerSchema, ResolverOptions,
};
use uv_static::EnvVars;
use uv_torch::TorchMode;
use uv_warnings::warn_user_once;
use uv_workspace::pyproject::{DependencyType, ExtraBuildDependencies};
use uv_workspace::pyproject_mut::AddBoundsKind;
use crate::commands::ToolRunCommand;
use crate::commands::{InitKind, InitProjectKind, pip::operations::Modifications};
const PYPI_PUBLISH_URL: &str = "https://upload.pypi.org/legacy/";
#[derive(Debug, Clone)]
pub(crate) struct GlobalSettings {
pub(crate) required_version: Option<RequiredVersion>,
pub(crate) quiet: u8,
pub(crate) verbose: u8,
pub(crate) color: ColorChoice,
pub(crate) network_settings: NetworkSettings,
pub(crate) concurrency: Concurrency,
pub(crate) show_settings: bool,
pub(crate) preview: Preview,
pub(crate) python_preference: PythonPreference,
pub(crate) python_downloads: PythonDownloads,
pub(crate) no_progress: bool,
pub(crate) installer_metadata: bool,
}
impl GlobalSettings {
pub(crate) fn resolve(
args: &GlobalArgs,
workspace: Option<&FilesystemOptions>,
environment: &EnvironmentOptions,
) -> Self {
let network_settings = NetworkSettings::resolve(args, workspace, environment);
let python_preference = resolve_python_preference(args, workspace, environment);
let color = resolve_color(args);
Self {
required_version: workspace
.and_then(|workspace| workspace.globals.required_version.clone()),
quiet: args.quiet,
verbose: args.verbose,
color,
network_settings,
concurrency: Concurrency::new(
environment
.concurrency
.downloads
.combine(workspace.and_then(|workspace| workspace.globals.concurrent_downloads))
.map(NonZeroUsize::get)
.unwrap_or(Concurrency::DEFAULT_DOWNLOADS),
environment
.concurrency
.builds
.combine(workspace.and_then(|workspace| workspace.globals.concurrent_builds))
.map(NonZeroUsize::get)
.unwrap_or_else(Concurrency::threads),
environment
.concurrency
.installs
.combine(workspace.and_then(|workspace| workspace.globals.concurrent_installs))
.map(NonZeroUsize::get)
.unwrap_or_else(Concurrency::threads),
),
show_settings: args.show_settings,
preview: Preview::from_args(
resolve_preview(args, workspace, environment),
args.no_preview,
&args.preview_features,
),
python_preference,
python_downloads: flag(
args.allow_python_downloads,
args.no_python_downloads,
"python-downloads",
)
.map(PythonDownloads::from)
.combine(env(env::UV_PYTHON_DOWNLOADS))
.combine(workspace.and_then(|workspace| workspace.globals.python_downloads))
.unwrap_or_default(),
no_progress: resolve_flag(args.no_progress, "no-progress", environment.no_progress)
.is_enabled()
|| std::env::var_os(EnvVars::RUST_LOG).is_some(),
installer_metadata: !resolve_flag(
args.no_installer_metadata,
"no-installer-metadata",
environment.no_installer_metadata,
)
.is_enabled(),
}
}
}
pub(crate) fn resolve_color(args: &GlobalArgs) -> ColorChoice {
if let Some(color_choice) = args.color {
color_choice
} else if args.no_color {
ColorChoice::Never
} else if std::env::var_os(EnvVars::NO_COLOR)
.as_ref()
.is_some_and(|v| !v.is_empty())
{
ColorChoice::Never
} else if std::env::var_os(EnvVars::FORCE_COLOR)
.as_ref()
.is_some_and(|v| !v.is_empty())
|| std::env::var_os(EnvVars::CLICOLOR_FORCE)
.as_ref()
.is_some_and(|v| !v.is_empty())
{
ColorChoice::Always
} else {
ColorChoice::Auto
}
}
fn resolve_python_preference(
args: &GlobalArgs,
workspace: Option<&FilesystemOptions>,
environment: &EnvironmentOptions,
) -> PythonPreference {
let (managed_python, no_managed_python) = resolve_flag_pair(
args.managed_python,
args.no_managed_python,
"managed-python",
"no-managed-python",
Some(environment.managed_python),
Some(environment.no_managed_python),
);
if managed_python.is_enabled() && args.python_preference.is_some() {
check_conflicts(managed_python, Flag::from_cli("python-preference"));
}
if no_managed_python.is_enabled() && args.python_preference.is_some() {
check_conflicts(no_managed_python, Flag::from_cli("python-preference"));
}
if managed_python.is_enabled() {
PythonPreference::OnlyManaged
} else if no_managed_python.is_enabled() {
PythonPreference::OnlySystem
} else {
args.python_preference
.combine(workspace.and_then(|workspace| workspace.globals.python_preference))
.unwrap_or_default()
}
}
pub(crate) fn resolve_preview(
args: &GlobalArgs,
workspace: Option<&FilesystemOptions>,
environment: &EnvironmentOptions,
) -> bool {
match flag(args.preview, args.no_preview, "preview") {
Some(value) => value,
None => {
if environment.preview.value == Some(true) {
true
} else {
workspace
.and_then(|workspace| workspace.globals.preview)
.unwrap_or(false)
}
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct NetworkSettings {
pub(crate) connectivity: Connectivity,
pub(crate) offline: Flag,
pub(crate) system_certs: bool,
pub(crate) http_proxy: Option<ProxyUrl>,
pub(crate) https_proxy: Option<ProxyUrl>,
pub(crate) no_proxy: Option<Vec<String>>,
pub(crate) allow_insecure_host: Vec<TrustedHost>,
pub(crate) read_timeout: Duration,
pub(crate) connect_timeout: Duration,
pub(crate) retries: u32,
}
impl NetworkSettings {
#[allow(deprecated)]
pub(crate) fn resolve(
args: &GlobalArgs,
workspace: Option<&FilesystemOptions>,
environment: &EnvironmentOptions,
) -> Self {
let offline = match flag(args.offline, args.no_offline, "offline") {
Some(true) => Flag::from_cli("offline"),
Some(false) => Flag::disabled(),
None => {
let env_flag = resolve_flag(false, "offline", environment.offline);
if env_flag.is_enabled() {
env_flag
} else if workspace
.and_then(|workspace| workspace.globals.offline)
.unwrap_or(false)
{
Flag::from_config("offline")
} else {
Flag::disabled()
}
}
};
let connectivity = if offline.is_enabled() {
Connectivity::Offline
} else {
Connectivity::Online
};
if args.native_tls {
warn_user_once!(
"The `--native-tls` flag is deprecated and will be removed in a future release. Use `--system-certs` instead."
);
}
if args.no_native_tls {
warn_user_once!(
"The `--no-native-tls` flag is deprecated and will be removed in a future release. Use `--no-system-certs` instead."
);
}
if environment.native_tls.value.is_some() {
warn_user_once!(
"The `UV_NATIVE_TLS` environment variable is deprecated and will be removed in a future release. Use `UV_SYSTEM_CERTS` instead."
);
}
if workspace
.and_then(|workspace| workspace.globals.native_tls)
.is_some()
{
warn_user_once!(
"The `native-tls` setting is deprecated and will be removed in a future release. Use `system-certs` instead."
);
}
let system_certs =
if let Some(value) = flag(args.system_certs, args.no_system_certs, "system-certs") {
value
} else if let Some(value) = flag(args.native_tls, args.no_native_tls, "native-tls") {
value
} else if let Some(true) = environment.system_certs.value {
true
} else if let Some(true) = environment.native_tls.value {
true
} else {
workspace
.and_then(|workspace| {
workspace
.globals
.system_certs
.or(workspace.globals.native_tls)
})
.unwrap_or(false)
};
let allow_insecure_host = args
.allow_insecure_host
.as_ref()
.map(|allow_insecure_host| {
allow_insecure_host
.iter()
.filter_map(|value| value.clone().into_option())
})
.into_iter()
.flatten()
.chain(
workspace
.and_then(|workspace| workspace.globals.allow_insecure_host.clone())
.into_iter()
.flatten(),
)
.collect();
let http_proxy = workspace.and_then(|workspace| workspace.globals.http_proxy.clone());
let https_proxy = workspace.and_then(|workspace| workspace.globals.https_proxy.clone());
let no_proxy = workspace.and_then(|workspace| workspace.globals.no_proxy.clone());
Self {
connectivity,
offline,
system_certs,
http_proxy,
https_proxy,
no_proxy,
allow_insecure_host,
read_timeout: environment.http_read_timeout,
connect_timeout: environment.http_connect_timeout,
retries: environment.http_retries,
}
}
pub(crate) fn check_refresh_conflict(&self, refresh: &Refresh) {
if !matches!(refresh, Refresh::None(_)) {
check_conflicts(self.offline, Flag::from_cli("refresh"));
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct CacheSettings {
pub(crate) no_cache: bool,
pub(crate) cache_dir: Option<PathBuf>,
}
impl CacheSettings {
pub(crate) fn resolve(args: CacheArgs, workspace: Option<&FilesystemOptions>) -> Self {
Self {
no_cache: args.no_cache
|| workspace
.and_then(|workspace| workspace.globals.no_cache)
.unwrap_or(false),
cache_dir: args
.cache_dir
.or_else(|| workspace.and_then(|workspace| workspace.globals.cache_dir.clone())),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct InitSettings {
pub(crate) path: Option<PathBuf>,
pub(crate) name: Option<PackageName>,
pub(crate) package: bool,
pub(crate) kind: InitKind,
pub(crate) bare: bool,
pub(crate) description: Option<String>,
pub(crate) no_description: bool,
pub(crate) vcs: Option<VersionControlSystem>,
pub(crate) build_backend: Option<ProjectBuildBackend>,
pub(crate) no_readme: bool,
pub(crate) author_from: Option<AuthorFrom>,
pub(crate) pin_python: bool,
pub(crate) no_workspace: bool,
pub(crate) python: Option<String>,
pub(crate) install_mirrors: PythonInstallMirrors,
}
impl InitSettings {
pub(crate) fn resolve(
args: InitArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let InitArgs {
path,
name,
r#virtual,
package,
no_package,
bare,
app,
lib,
script,
description,
no_description,
vcs,
build_backend,
no_readme,
author_from,
no_pin_python,
pin_python,
no_workspace,
python,
..
} = args;
let kind = match (app, lib, script) {
(true, false, false) => InitKind::Project(InitProjectKind::Application),
(false, true, false) => InitKind::Project(InitProjectKind::Library),
(false, false, true) => InitKind::Script,
(false, false, false) => InitKind::default(),
(_, _, _) => unreachable!("`app`, `lib`, and `script` are mutually exclusive"),
};
let package = flag(
package || build_backend.is_some(),
no_package || r#virtual,
"virtual",
)
.unwrap_or(kind.packaged_by_default());
let bare = resolve_flag(bare, "bare", environment.init_bare).is_enabled();
let filesystem_install_mirrors = filesystem
.map(|fs| fs.install_mirrors.clone())
.unwrap_or_default();
let no_description = no_description || (bare && description.is_none());
Self {
path,
name,
package,
kind,
bare,
description,
no_description,
vcs: vcs.or(bare.then_some(VersionControlSystem::None)),
build_backend,
no_readme,
author_from,
pin_python: flag(pin_python, no_pin_python, "pin-python").unwrap_or(!bare),
no_workspace,
python: python.and_then(Maybe::into_option),
install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
}
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum LockCheckSource {
LockedCli,
LockedEnv,
LockedConfiguration,
Check,
}
impl std::fmt::Display for LockCheckSource {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::LockedCli => write!(f, "--locked"),
Self::LockedEnv => write!(f, "UV_LOCKED=1"),
Self::LockedConfiguration => write!(f, "locked (workspace configuration)"),
Self::Check => write!(f, "--check"),
}
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum LockCheck {
Enabled(LockCheckSource),
Disabled,
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum FrozenSource {
Cli,
Env,
Configuration,
}
fn resolve_frozen(flag: Flag) -> Option<FrozenSource> {
if flag.is_enabled() {
Some(match flag.source() {
Some(FlagSource::Cli) | None => FrozenSource::Cli,
Some(FlagSource::Env(_)) => FrozenSource::Env,
Some(FlagSource::Config) => FrozenSource::Configuration,
})
} else {
None
}
}
fn resolve_lock_check(flag: Flag) -> LockCheck {
if flag.is_enabled() {
LockCheck::Enabled(match flag.source() {
Some(FlagSource::Cli) | None => LockCheckSource::LockedCli,
Some(FlagSource::Env(_)) => LockCheckSource::LockedEnv,
Some(FlagSource::Config) => LockCheckSource::LockedConfiguration,
})
} else {
LockCheck::Disabled
}
}
#[derive(Debug, Clone)]
pub(crate) struct RunSettings {
pub(crate) lock_check: LockCheck,
pub(crate) frozen: Option<FrozenSource>,
pub(crate) extras: ExtrasSpecification,
pub(crate) groups: DependencyGroups,
pub(crate) editable: Option<EditableMode>,
pub(crate) modifications: Modifications,
pub(crate) with: Vec<String>,
pub(crate) with_editable: Vec<String>,
pub(crate) with_requirements: Vec<PathBuf>,
pub(crate) isolated: bool,
pub(crate) show_resolution: bool,
pub(crate) all_packages: bool,
pub(crate) package: Option<PackageName>,
pub(crate) no_project: bool,
pub(crate) active: Option<bool>,
pub(crate) no_sync: bool,
pub(crate) python: Option<String>,
pub(crate) python_platform: Option<TargetTriple>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) refresh: Refresh,
pub(crate) settings: ResolverInstallerSettings,
pub(crate) env_file: EnvFile,
pub(crate) max_recursion_depth: u32,
}
impl RunSettings {
const DEFAULT_MAX_RECURSION_DEPTH: u32 = 100;
pub(crate) fn resolve(
args: RunArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let RunArgs {
extra,
all_extras,
no_extra,
no_all_extras,
dev,
no_dev,
group,
no_group,
no_default_groups,
only_group,
all_groups,
module: _,
only_dev,
editable,
no_editable,
inexact,
exact,
script: _,
gui_script: _,
command: _,
with,
with_editable,
with_requirements,
isolated,
active,
no_active,
no_sync,
locked,
frozen,
installer,
build,
refresh,
all_packages,
package,
no_project,
python,
python_platform,
show_resolution,
env_file,
no_env_file,
max_recursion_depth,
} = args;
let filesystem_install_mirrors = filesystem
.clone()
.map(|fs| fs.install_mirrors.clone())
.unwrap_or_default();
let locked = resolve_flag(locked, "locked", environment.locked);
let frozen = resolve_flag(frozen, "frozen", environment.frozen);
let no_sync = resolve_flag(no_sync, "no-sync", environment.no_sync);
check_conflicts(locked, frozen);
let (dev, no_dev) = resolve_flag_pair(
dev,
no_dev,
"dev",
"no-dev",
Some(environment.dev),
Some(environment.no_dev),
);
let (editable, no_editable) = resolve_flag_pair(
editable,
no_editable,
"editable",
"no-editable",
None,
Some(environment.no_editable),
);
let isolated = isolated || environment.isolated.value == Some(true);
let show_resolution = show_resolution || environment.show_resolution.value == Some(true);
let no_env_file = no_env_file || environment.no_env_file.value == Some(true);
Self {
lock_check: resolve_lock_check(locked),
frozen: resolve_frozen(frozen),
extras: ExtrasSpecification::from_args(
extra.unwrap_or_default(),
no_extra,
false,
vec![],
flag(all_extras, no_all_extras, "all-extras").unwrap_or_default(),
),
groups: DependencyGroups::from_args(
dev.into(),
no_dev.into(),
only_dev,
group,
no_group,
no_default_groups,
only_group,
all_groups,
),
editable: flag(editable.into(), no_editable.into(), "editable").map(EditableMode::from),
modifications: if flag(exact, inexact, "inexact").unwrap_or(false) {
Modifications::Exact
} else {
Modifications::Sufficient
},
with: with
.into_iter()
.flat_map(CommaSeparatedRequirements::into_iter)
.collect(),
with_editable: with_editable
.into_iter()
.flat_map(CommaSeparatedRequirements::into_iter)
.collect(),
with_requirements: with_requirements
.into_iter()
.filter_map(Maybe::into_option)
.collect(),
isolated,
show_resolution,
all_packages,
package,
no_project,
no_sync: no_sync.is_enabled(),
active: flag(active, no_active, "active"),
python: python.and_then(Maybe::into_option),
python_platform,
refresh: Refresh::from(refresh),
settings: ResolverInstallerSettings::combine(
resolver_installer_options(installer, build),
filesystem,
),
env_file: EnvFile::from_args(env_file, no_env_file),
install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
max_recursion_depth: max_recursion_depth.unwrap_or(Self::DEFAULT_MAX_RECURSION_DEPTH),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct ToolRunSettings {
pub(crate) command: Option<ExternalCommand>,
pub(crate) from: Option<String>,
pub(crate) with: Vec<String>,
pub(crate) with_requirements: Vec<PathBuf>,
pub(crate) with_editable: Vec<String>,
pub(crate) constraints: Vec<PathBuf>,
pub(crate) overrides: Vec<PathBuf>,
pub(crate) build_constraints: Vec<PathBuf>,
pub(crate) isolated: bool,
pub(crate) show_resolution: bool,
pub(crate) lfs: GitLfsSetting,
pub(crate) python: Option<String>,
pub(crate) python_platform: Option<TargetTriple>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) refresh: Refresh,
pub(crate) options: ResolverInstallerOptions,
pub(crate) settings: ResolverInstallerSettings,
pub(crate) env_file: Vec<PathBuf>,
pub(crate) no_env_file: bool,
}
impl ToolRunSettings {
pub(crate) fn resolve(
args: ToolRunArgs,
filesystem: Option<FilesystemOptions>,
invocation_source: ToolRunCommand,
environment: EnvironmentOptions,
) -> Self {
let ToolRunArgs {
command,
from,
with,
with_editable,
with_requirements,
constraints,
overrides,
build_constraints,
isolated,
env_file,
no_env_file,
show_resolution,
installer,
build,
refresh,
lfs,
python,
python_platform,
torch_backend,
generate_shell_completion: _,
} = args;
if installer.upgrade || !installer.upgrade_package.is_empty() {
if with.is_empty() && with_requirements.is_empty() {
warn_user_once!(
"Tools cannot be upgraded via `{invocation_source}`; use `uv tool upgrade --all` to upgrade all installed tools, or `{invocation_source} package@latest` to run the latest version of a tool."
);
} else {
warn_user_once!(
"Tools cannot be upgraded via `{invocation_source}`; use `uv tool upgrade --all` to upgrade all installed tools, `{invocation_source} package@latest` to run the latest version of a tool, or `{invocation_source} --refresh package` to upgrade any `--with` dependencies."
);
}
}
if installer.reinstall || !installer.reinstall_package.is_empty() {
if with.is_empty() && with_requirements.is_empty() {
warn_user_once!(
"Tools cannot be reinstalled via `{invocation_source}`; use `uv tool upgrade --all --reinstall` to reinstall all installed tools, `{invocation_source} package@latest` to run the latest version of a tool, or `uv cache prune` to clear any cached tool environments."
);
} else {
warn_user_once!(
"Tools cannot be reinstalled via `{invocation_source}`; use `uv tool upgrade --all --reinstall` to reinstall all installed tools, `{invocation_source} package@latest` to run the latest version of a tool, `{invocation_source} --refresh package` to reinstall any `--with` dependencies, or `uv cache prune` to clear any cached tool environments."
);
}
}
let filesystem_options = filesystem.map(FilesystemOptions::into_options);
let options =
resolver_installer_options(installer, build).combine(ResolverInstallerOptions::from(
filesystem_options
.as_ref()
.map(|options| options.top_level.clone())
.unwrap_or_default(),
));
let filesystem_install_mirrors = filesystem_options
.map(|options| options.install_mirrors.clone())
.unwrap_or_default();
let mut settings = ResolverInstallerSettings::from(options.clone());
if torch_backend.is_some() {
settings.resolver.torch_backend = torch_backend;
}
let lfs = GitLfsSetting::new(lfs.then_some(true), environment.lfs);
let isolated = isolated || environment.isolated.value == Some(true);
let show_resolution = show_resolution || environment.show_resolution.value == Some(true);
let no_env_file = no_env_file || environment.no_env_file.value == Some(true);
Self {
command,
from,
with: with
.into_iter()
.flat_map(CommaSeparatedRequirements::into_iter)
.collect(),
with_editable: with_editable
.into_iter()
.flat_map(CommaSeparatedRequirements::into_iter)
.collect(),
with_requirements: with_requirements
.into_iter()
.filter_map(Maybe::into_option)
.collect(),
constraints: constraints
.into_iter()
.filter_map(Maybe::into_option)
.collect(),
overrides: overrides
.into_iter()
.filter_map(Maybe::into_option)
.collect(),
build_constraints: build_constraints
.into_iter()
.filter_map(Maybe::into_option)
.collect(),
isolated,
show_resolution,
lfs,
python: python.and_then(Maybe::into_option),
python_platform,
refresh: Refresh::from(refresh),
settings,
options,
install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
env_file,
no_env_file,
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct ToolInstallSettings {
pub(crate) package: String,
pub(crate) from: Option<String>,
pub(crate) with: Vec<String>,
pub(crate) with_requirements: Vec<PathBuf>,
pub(crate) with_executables_from: Vec<String>,
pub(crate) with_editable: Vec<String>,
pub(crate) constraints: Vec<PathBuf>,
pub(crate) overrides: Vec<PathBuf>,
pub(crate) excludes: Vec<PathBuf>,
pub(crate) build_constraints: Vec<PathBuf>,
pub(crate) lfs: GitLfsSetting,
pub(crate) python: Option<String>,
pub(crate) python_platform: Option<TargetTriple>,
pub(crate) refresh: Refresh,
pub(crate) options: ResolverInstallerOptions,
pub(crate) settings: ResolverInstallerSettings,
pub(crate) force: bool,
pub(crate) editable: bool,
pub(crate) install_mirrors: PythonInstallMirrors,
}
impl ToolInstallSettings {
pub(crate) fn resolve(
args: ToolInstallArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let ToolInstallArgs {
package,
editable,
from,
with,
with_editable,
with_requirements,
with_executables_from,
constraints,
overrides,
excludes,
build_constraints,
lfs,
installer,
force,
build,
refresh,
python,
python_platform,
torch_backend,
} = args;
let filesystem_options = filesystem.map(FilesystemOptions::into_options);
let options =
resolver_installer_options(installer, build).combine(ResolverInstallerOptions::from(
filesystem_options
.as_ref()
.map(|options| options.top_level.clone())
.unwrap_or_default(),
));
let filesystem_install_mirrors = filesystem_options
.map(|options| options.install_mirrors.clone())
.unwrap_or_default();
let mut settings = ResolverInstallerSettings::from(options.clone());
if torch_backend.is_some() {
settings.resolver.torch_backend = torch_backend;
}
let lfs = GitLfsSetting::new(lfs.then_some(true), environment.lfs);
Self {
package,
from,
with: with
.into_iter()
.flat_map(CommaSeparatedRequirements::into_iter)
.collect(),
with_editable: with_editable
.into_iter()
.flat_map(CommaSeparatedRequirements::into_iter)
.collect(),
with_requirements: with_requirements
.into_iter()
.filter_map(Maybe::into_option)
.collect(),
with_executables_from: with_executables_from
.into_iter()
.flat_map(CommaSeparatedRequirements::into_iter)
.collect(),
constraints: constraints
.into_iter()
.filter_map(Maybe::into_option)
.collect(),
overrides: overrides
.into_iter()
.filter_map(Maybe::into_option)
.collect(),
excludes: excludes
.into_iter()
.filter_map(Maybe::into_option)
.collect(),
build_constraints: build_constraints
.into_iter()
.filter_map(Maybe::into_option)
.collect(),
lfs,
python: python.and_then(Maybe::into_option),
python_platform,
force,
editable,
refresh: Refresh::from(refresh),
options,
settings,
install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct ToolUpgradeSettings {
pub(crate) names: Vec<String>,
pub(crate) python: Option<String>,
pub(crate) python_platform: Option<TargetTriple>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) args: ResolverInstallerOptions,
pub(crate) filesystem: ResolverInstallerOptions,
}
impl ToolUpgradeSettings {
pub(crate) fn resolve(
args: ToolUpgradeArgs,
filesystem: Option<FilesystemOptions>,
environment: &EnvironmentOptions,
) -> Self {
let ToolUpgradeArgs {
name,
python,
python_platform,
upgrade,
upgrade_package,
upgrade_group,
index_args,
all,
reinstall,
no_reinstall,
reinstall_package,
index_strategy,
keyring_provider,
resolution,
prerelease,
pre,
fork_strategy,
config_setting,
config_setting_package: config_settings_package,
no_build_isolation,
no_build_isolation_package,
build_isolation,
exclude_newer,
link_mode,
compile_bytecode,
no_compile_bytecode,
no_sources,
no_sources_package,
exclude_newer_package,
build,
} = args;
if upgrade {
warn_user_once!("`--upgrade` is enabled by default on `uv tool upgrade`");
}
if !upgrade_package.is_empty() {
warn_user_once!("`--upgrade-package` is enabled by default on `uv tool upgrade`");
}
let installer = ResolverInstallerArgs {
index_args,
upgrade: upgrade_package.is_empty(),
no_upgrade: false,
upgrade_package,
upgrade_group,
reinstall,
no_reinstall,
reinstall_package,
index_strategy,
keyring_provider,
resolution,
prerelease,
pre,
fork_strategy,
config_setting,
config_settings_package,
no_build_isolation,
no_build_isolation_package,
build_isolation,
exclude_newer,
exclude_newer_package,
link_mode,
compile_bytecode,
no_compile_bytecode,
no_sources,
no_sources_package,
};
let args = resolver_installer_options(installer, build);
let filesystem = filesystem.map(FilesystemOptions::into_options);
let filesystem_install_mirrors = filesystem
.clone()
.map(|options| options.install_mirrors)
.unwrap_or_default();
let top_level = ResolverInstallerOptions::from(
filesystem
.map(|options| options.top_level)
.unwrap_or_default(),
);
Self {
names: if all { vec![] } else { name },
python: python.and_then(Maybe::into_option),
python_platform,
args,
filesystem: top_level,
install_mirrors: environment
.install_mirrors
.clone()
.combine(filesystem_install_mirrors),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct ToolListSettings {
pub(crate) show_paths: bool,
pub(crate) show_version_specifiers: bool,
pub(crate) show_with: bool,
pub(crate) show_extras: bool,
pub(crate) show_python: bool,
pub(crate) outdated: bool,
pub(crate) args: ResolverInstallerOptions,
pub(crate) filesystem: ResolverInstallerOptions,
}
impl ToolListSettings {
pub(crate) fn resolve(args: ToolListArgs, filesystem: Option<FilesystemOptions>) -> Self {
let ToolListArgs {
show_paths,
show_version_specifiers,
show_with,
show_extras,
show_python,
outdated,
no_outdated,
exclude_newer,
python_preference: _,
no_python_downloads: _,
} = args;
let filesystem = filesystem.map(FilesystemOptions::into_options);
let filesystem = ResolverInstallerOptions {
exclude_newer: filesystem.and_then(|options| options.top_level.exclude_newer),
..ResolverInstallerOptions::default()
};
Self {
show_paths,
show_version_specifiers,
show_with,
show_extras,
show_python,
outdated: flag(outdated, no_outdated, "outdated").unwrap_or(false),
args: ResolverInstallerOptions {
exclude_newer,
..ResolverInstallerOptions::default()
},
filesystem,
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct ToolUninstallSettings {
pub(crate) name: Vec<PackageName>,
}
impl ToolUninstallSettings {
pub(crate) fn resolve(args: ToolUninstallArgs, _filesystem: Option<FilesystemOptions>) -> Self {
let ToolUninstallArgs { name, all } = args;
Self {
name: if all { vec![] } else { name },
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct ToolDirSettings {
pub(crate) bin: bool,
}
impl ToolDirSettings {
#[expect(clippy::needless_pass_by_value)]
pub(crate) fn resolve(args: ToolDirArgs, _filesystem: Option<FilesystemOptions>) -> Self {
let ToolDirArgs { bin } = args;
Self { bin }
}
}
#[derive(Debug, Clone, Default)]
pub(crate) enum PythonListKinds {
#[default]
Default,
Downloads,
Installed,
}
#[derive(Debug, Clone)]
pub(crate) struct PythonListSettings {
pub(crate) request: Option<String>,
pub(crate) kinds: PythonListKinds,
pub(crate) all_platforms: bool,
pub(crate) all_arches: bool,
pub(crate) all_versions: bool,
pub(crate) show_urls: bool,
pub(crate) output_format: PythonListFormat,
pub(crate) python_downloads_json_url: Option<String>,
pub(crate) python_install_mirror: Option<String>,
pub(crate) pypy_install_mirror: Option<String>,
}
impl PythonListSettings {
#[expect(clippy::needless_pass_by_value)]
pub(crate) fn resolve(
args: PythonListArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let PythonListArgs {
request,
all_versions,
all_platforms,
all_arches,
only_installed,
only_downloads,
show_urls,
output_format,
python_downloads_json_url: python_downloads_json_url_arg,
} = args;
let options = filesystem.map(FilesystemOptions::into_options);
let (
python_downloads_json_url_option,
python_install_mirror_option,
pypy_install_mirror_option,
) = match &options {
Some(options) => (
options.install_mirrors.python_downloads_json_url.clone(),
options.install_mirrors.python_install_mirror.clone(),
options.install_mirrors.pypy_install_mirror.clone(),
),
None => (None, None, None),
};
let python_downloads_json_url = python_downloads_json_url_arg
.or(environment
.install_mirrors
.python_downloads_json_url
.clone())
.or(python_downloads_json_url_option);
let python_install_mirror = environment
.install_mirrors
.python_install_mirror
.clone()
.or(python_install_mirror_option);
let pypy_install_mirror = environment
.install_mirrors
.pypy_install_mirror
.clone()
.or(pypy_install_mirror_option);
let kinds = if only_installed {
PythonListKinds::Installed
} else if only_downloads {
PythonListKinds::Downloads
} else {
PythonListKinds::default()
};
Self {
request,
kinds,
all_platforms,
all_arches,
all_versions,
show_urls,
output_format,
python_downloads_json_url,
python_install_mirror,
pypy_install_mirror,
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct PythonDirSettings {
pub(crate) bin: bool,
}
impl PythonDirSettings {
#[expect(clippy::needless_pass_by_value)]
pub(crate) fn resolve(args: PythonDirArgs, _filesystem: Option<FilesystemOptions>) -> Self {
let PythonDirArgs { bin } = args;
Self { bin }
}
}
#[derive(Debug, Clone)]
pub(crate) struct PythonInstallSettings {
pub(crate) install_dir: Option<PathBuf>,
pub(crate) targets: Vec<String>,
pub(crate) reinstall: bool,
pub(crate) force: bool,
pub(crate) upgrade: PythonUpgrade,
pub(crate) bin: Option<bool>,
pub(crate) registry: Option<bool>,
pub(crate) python_install_mirror: Option<String>,
pub(crate) pypy_install_mirror: Option<String>,
pub(crate) python_downloads_json_url: Option<String>,
pub(crate) default: bool,
pub(crate) compile_bytecode: bool,
}
impl PythonInstallSettings {
pub(crate) fn resolve(
args: PythonInstallArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let filesystem_install_mirrors = filesystem
.map(|fs| fs.install_mirrors.clone())
.unwrap_or_default();
let install_mirrors = args
.install_mirrors()
.combine(environment.install_mirrors)
.combine(filesystem_install_mirrors);
let PythonInstallMirrors {
python_install_mirror,
pypy_install_mirror,
python_downloads_json_url,
} = install_mirrors;
let PythonInstallArgs {
install_dir,
targets,
reinstall,
bin,
no_bin,
registry,
no_registry,
force,
upgrade,
mirror: _,
pypy_mirror: _,
python_downloads_json_url: _,
default,
compile_bytecode,
} = args;
Self {
install_dir,
targets,
reinstall,
force,
upgrade: if upgrade {
PythonUpgrade::Enabled(PythonUpgradeSource::Install)
} else {
PythonUpgrade::Disabled
},
bin: flag(bin, no_bin, "bin").or(environment.python_install_bin),
registry: match flag(registry, no_registry, "registry") {
Some(registry) => Some(registry),
None => environment.python_install_registry.or(
if environment.python_no_registry.value == Some(true) {
Some(false)
} else {
None
},
),
},
python_install_mirror,
pypy_install_mirror,
python_downloads_json_url,
default,
compile_bytecode: flag(
compile_bytecode.compile_bytecode,
compile_bytecode.no_compile_bytecode,
"compile-bytecode",
)
.unwrap_or_default(),
}
}
}
#[expect(clippy::struct_excessive_bools)]
#[derive(Debug, Clone)]
pub(crate) struct PythonUpgradeSettings {
pub(crate) install_dir: Option<PathBuf>,
pub(crate) targets: Vec<String>,
pub(crate) force: bool,
pub(crate) registry: Option<bool>,
pub(crate) python_install_mirror: Option<String>,
pub(crate) pypy_install_mirror: Option<String>,
pub(crate) reinstall: bool,
pub(crate) python_downloads_json_url: Option<String>,
pub(crate) default: bool,
pub(crate) bin: Option<bool>,
pub(crate) compile_bytecode: bool,
}
impl PythonUpgradeSettings {
pub(crate) fn resolve(
args: PythonUpgradeArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let filesystem_install_mirrors = filesystem
.map(|fs| fs.install_mirrors.clone())
.unwrap_or_default();
let install_mirrors = args
.install_mirrors()
.combine(environment.install_mirrors)
.combine(filesystem_install_mirrors);
let PythonInstallMirrors {
python_install_mirror,
pypy_install_mirror,
python_downloads_json_url,
} = install_mirrors;
let force = false;
let default = false;
let bin = None;
let registry = environment.python_install_registry.or(
if environment.python_no_registry.value == Some(true) {
Some(false)
} else {
None
},
);
let PythonUpgradeArgs {
install_dir,
targets,
mirror: _,
pypy_mirror: _,
reinstall,
python_downloads_json_url: _,
compile_bytecode,
} = args;
Self {
install_dir,
targets,
force,
registry,
python_install_mirror,
pypy_install_mirror,
reinstall,
python_downloads_json_url,
default,
bin,
compile_bytecode: flag(
compile_bytecode.compile_bytecode,
compile_bytecode.no_compile_bytecode,
"compile-bytecode",
)
.unwrap_or_default(),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct PythonUninstallSettings {
pub(crate) install_dir: Option<PathBuf>,
pub(crate) targets: Vec<String>,
pub(crate) all: bool,
}
impl PythonUninstallSettings {
pub(crate) fn resolve(
args: PythonUninstallArgs,
_filesystem: Option<FilesystemOptions>,
) -> Self {
let PythonUninstallArgs {
install_dir,
targets,
all,
} = args;
Self {
install_dir,
targets,
all,
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct PythonFindSettings {
pub(crate) request: Option<String>,
pub(crate) show_version: bool,
pub(crate) resolve_links: bool,
pub(crate) no_project: bool,
pub(crate) system: bool,
pub(crate) python_downloads_json_url: Option<String>,
}
impl PythonFindSettings {
pub(crate) fn resolve(
args: PythonFindArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let PythonFindArgs {
request,
show_version,
resolve_links,
no_project,
system,
no_system,
script: _,
python_downloads_json_url,
} = args;
let filesystem_install_mirrors = filesystem
.map(|fs| fs.install_mirrors.clone())
.unwrap_or_default();
let install_mirrors = PythonInstallMirrors {
python_downloads_json_url,
..Default::default()
}
.combine(environment.install_mirrors)
.combine(filesystem_install_mirrors);
let PythonInstallMirrors {
python_install_mirror: _,
pypy_install_mirror: _,
python_downloads_json_url,
} = install_mirrors;
Self {
request,
show_version,
resolve_links,
no_project,
system: flag(system, no_system, "system").unwrap_or_default(),
python_downloads_json_url,
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct PythonPinSettings {
pub(crate) request: Option<String>,
pub(crate) resolved: bool,
pub(crate) no_project: bool,
pub(crate) global: bool,
pub(crate) rm: bool,
pub(crate) install_mirrors: PythonInstallMirrors,
}
impl PythonPinSettings {
pub(crate) fn resolve(
args: PythonPinArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let PythonPinArgs {
request,
no_resolved,
resolved,
no_project,
global,
rm,
python_downloads_json_url,
} = args;
let filesystem_install_mirrors = filesystem
.map(|fs| fs.install_mirrors.clone())
.unwrap_or_default();
let install_mirrors = PythonInstallMirrors {
python_downloads_json_url,
..Default::default()
}
.combine(environment.install_mirrors)
.combine(filesystem_install_mirrors);
Self {
request,
resolved: flag(resolved, no_resolved, "resolved").unwrap_or(false),
no_project,
global,
rm,
install_mirrors,
}
}
}
#[expect(dead_code)]
#[derive(Debug, Clone)]
pub(crate) struct SyncSettings {
pub(crate) lock_check: LockCheck,
pub(crate) frozen: Option<FrozenSource>,
pub(crate) dry_run: DryRun,
pub(crate) script: Option<PathBuf>,
pub(crate) active: Option<bool>,
pub(crate) extras: ExtrasSpecification,
pub(crate) groups: DependencyGroups,
pub(crate) editable: Option<EditableMode>,
pub(crate) install_options: InstallOptions,
pub(crate) modifications: Modifications,
pub(crate) all_packages: bool,
pub(crate) package: Vec<PackageName>,
pub(crate) python: Option<String>,
pub(crate) python_platform: Option<TargetTriple>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) refresh: Refresh,
pub(crate) settings: ResolverInstallerSettings,
pub(crate) output_format: SyncFormat,
}
impl SyncSettings {
pub(crate) fn resolve(
args: SyncArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let SyncArgs {
extra,
all_extras,
no_extra,
no_all_extras,
dev,
no_dev,
only_dev,
group,
no_group,
no_default_groups,
only_group,
all_groups,
editable,
no_editable,
inexact,
exact,
no_install_project,
only_install_project,
no_install_workspace,
only_install_workspace,
no_install_local,
only_install_local,
no_install_package,
only_install_package,
locked,
frozen,
active,
no_active,
dry_run,
installer,
build,
refresh,
all_packages,
package,
script,
python,
python_platform,
check,
no_check,
output_format,
} = args;
let filesystem_install_mirrors = filesystem
.clone()
.map(|fs| fs.install_mirrors.clone())
.unwrap_or_default();
let settings = ResolverInstallerSettings::combine(
resolver_installer_options(installer, build),
filesystem,
);
let check = flag(check, no_check, "check").unwrap_or_default();
let dry_run = if check {
DryRun::Check
} else {
DryRun::from_args(dry_run)
};
let locked = resolve_flag(locked, "locked", environment.locked);
let frozen = resolve_flag(frozen, "frozen", environment.frozen);
check_conflicts(locked, frozen);
let (dev, no_dev) = resolve_flag_pair(
dev,
no_dev,
"dev",
"no-dev",
Some(environment.dev),
Some(environment.no_dev),
);
let (editable, no_editable) = resolve_flag_pair(
editable,
no_editable,
"editable",
"no-editable",
None,
Some(environment.no_editable),
);
Self {
output_format,
lock_check: resolve_lock_check(locked),
frozen: resolve_frozen(frozen),
dry_run,
script,
active: flag(active, no_active, "active"),
extras: ExtrasSpecification::from_args(
extra.unwrap_or_default(),
no_extra,
false,
vec![],
flag(all_extras, no_all_extras, "all-extras").unwrap_or_default(),
),
groups: DependencyGroups::from_args(
dev.into(),
no_dev.into(),
only_dev,
group,
no_group,
no_default_groups,
only_group,
all_groups,
),
editable: flag(editable.into(), no_editable.into(), "editable").map(EditableMode::from),
install_options: InstallOptions::new(
no_install_project,
only_install_project,
no_install_workspace,
only_install_workspace,
no_install_local,
only_install_local,
no_install_package,
only_install_package,
),
modifications: if flag(exact, inexact, "inexact").unwrap_or(true) {
Modifications::Exact
} else {
Modifications::Sufficient
},
all_packages,
package,
python: python.and_then(Maybe::into_option),
python_platform,
refresh: Refresh::from(refresh),
settings,
install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct LockSettings {
pub(crate) lock_check: LockCheck,
pub(crate) frozen: Option<FrozenSource>,
pub(crate) dry_run: DryRun,
pub(crate) script: Option<PathBuf>,
pub(crate) python: Option<String>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) refresh: Refresh,
pub(crate) settings: ResolverSettings,
}
impl LockSettings {
pub(crate) fn resolve(
args: LockArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let LockArgs {
check,
locked,
check_exists,
dry_run,
script,
resolver,
build,
refresh,
python,
} = args;
let filesystem_install_mirrors = filesystem
.clone()
.map(|fs| fs.install_mirrors.clone())
.unwrap_or_default();
let locked = resolve_flag(locked, "locked", environment.locked);
let frozen = resolve_flag(check_exists, "frozen", environment.frozen);
check_conflicts(locked, frozen);
let lock_check = if check {
LockCheck::Enabled(LockCheckSource::Check)
} else {
resolve_lock_check(locked)
};
Self {
lock_check,
frozen: resolve_frozen(frozen),
dry_run: DryRun::from_args(dry_run),
script,
python: python.and_then(Maybe::into_option),
refresh: Refresh::from(refresh),
settings: ResolverSettings::combine(resolver_options(resolver, build), filesystem),
install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct MetadataSettings {
pub(crate) lock_check: LockCheck,
pub(crate) frozen: Option<FrozenSource>,
pub(crate) dry_run: DryRun,
pub(crate) python: Option<String>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) refresh: Refresh,
pub(crate) settings: ResolverSettings,
}
impl MetadataSettings {
pub(crate) fn resolve(
args: Box<MetadataArgs>,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let MetadataArgs {
locked,
frozen,
dry_run,
resolver,
build,
refresh,
python,
} = *args;
let filesystem_install_mirrors = filesystem
.clone()
.map(|fs| fs.install_mirrors.clone())
.unwrap_or_default();
let locked = resolve_flag(locked, "locked", environment.locked);
let frozen = resolve_flag(frozen, "frozen", environment.frozen);
check_conflicts(locked, frozen);
Self {
lock_check: resolve_lock_check(locked),
frozen: resolve_frozen(frozen),
dry_run: DryRun::from_args(dry_run),
python: python.and_then(Maybe::into_option),
refresh: Refresh::from(refresh),
settings: ResolverSettings::combine(resolver_options(resolver, build), filesystem),
install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
}
}
}
#[expect(clippy::struct_excessive_bools)]
#[derive(Debug, Clone)]
pub(crate) struct AddSettings {
pub(crate) lock_check: LockCheck,
pub(crate) frozen: Option<FrozenSource>,
pub(crate) active: Option<bool>,
pub(crate) no_sync: bool,
pub(crate) packages: Vec<String>,
pub(crate) requirements: Vec<PathBuf>,
pub(crate) constraints: Vec<PathBuf>,
pub(crate) marker: Option<MarkerTree>,
pub(crate) dependency_type: DependencyType,
pub(crate) editable: Option<bool>,
pub(crate) extras: Vec<ExtraName>,
pub(crate) raw: bool,
pub(crate) bounds: Option<AddBoundsKind>,
pub(crate) rev: Option<String>,
pub(crate) tag: Option<String>,
pub(crate) branch: Option<String>,
pub(crate) lfs: GitLfsSetting,
pub(crate) package: Option<PackageName>,
pub(crate) script: Option<PathBuf>,
pub(crate) python: Option<String>,
pub(crate) workspace: Option<bool>,
pub(crate) no_install_project: bool,
pub(crate) only_install_project: bool,
pub(crate) no_install_workspace: bool,
pub(crate) only_install_workspace: bool,
pub(crate) no_install_local: bool,
pub(crate) only_install_local: bool,
pub(crate) no_install_package: Vec<PackageName>,
pub(crate) only_install_package: Vec<PackageName>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) refresh: Refresh,
pub(crate) indexes: Vec<Index>,
pub(crate) settings: ResolverInstallerSettings,
}
impl AddSettings {
pub(crate) fn resolve(
args: AddArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let AddArgs {
packages,
requirements,
constraints,
marker,
dev,
optional,
group,
editable,
no_editable,
extra,
raw,
bounds,
rev,
tag,
branch,
lfs,
no_sync,
locked,
frozen,
active,
no_active,
installer,
build,
refresh,
package,
script,
python,
workspace,
no_workspace,
no_install_project,
only_install_project,
no_install_workspace,
only_install_workspace,
no_install_local,
only_install_local,
no_install_package,
only_install_package,
} = args;
let dev = dev || environment.dev.value == Some(true);
let (editable, no_editable) = resolve_flag_pair(
editable,
no_editable,
"editable",
"no-editable",
None,
Some(environment.no_editable),
);
let dependency_type = if let Some(extra) = optional {
DependencyType::Optional(extra)
} else if let Some(group) = group {
DependencyType::Group(group)
} else if dev {
DependencyType::Dev
} else {
DependencyType::Production
};
let indexes = installer
.index_args
.default_index
.clone()
.and_then(Maybe::into_option)
.into_iter()
.chain(
installer
.index_args
.index
.clone()
.into_iter()
.flat_map(|v| v.clone())
.flatten()
.filter_map(Maybe::into_option),
)
.collect::<Vec<_>>();
for index in &indexes {
index.url().warn_on_disambiguated_relative_path();
}
if installer
.index_args
.index_url
.as_ref()
.is_some_and(Maybe::is_some)
{
if script.is_some() {
warn_user_once!(
"Indexes specified via `--index-url` will not be persisted to the script; use `--default-index` instead."
);
} else {
warn_user_once!(
"Indexes specified via `--index-url` will not be persisted to the `pyproject.toml` file; use `--default-index` instead."
);
}
}
if installer
.index_args
.extra_index_url
.as_ref()
.is_some_and(|extra_index_url| extra_index_url.iter().any(Maybe::is_some))
{
if script.is_some() {
warn_user_once!(
"Indexes specified via `--extra-index-url` will not be persisted to the script; use `--index` instead."
);
} else {
warn_user_once!(
"Indexes specified via `--extra-index-url` will not be persisted to the `pyproject.toml` file; use `--index` instead."
);
}
}
let filesystem_install_mirrors = filesystem
.as_ref()
.map(|fs| fs.install_mirrors.clone())
.unwrap_or_default();
let bounds = bounds.or(filesystem.as_ref().and_then(|fs| fs.add.add_bounds));
let lfs = GitLfsSetting::new(lfs.then_some(true), environment.lfs);
let locked = resolve_flag(locked, "locked", environment.locked);
let frozen = resolve_flag(frozen, "frozen", environment.frozen);
let no_sync = resolve_flag(no_sync, "no-sync", environment.no_sync);
check_conflicts(locked, frozen);
check_conflicts(no_sync, frozen);
Self {
lock_check: resolve_lock_check(locked),
frozen: resolve_frozen(frozen),
active: flag(active, no_active, "active"),
no_sync: no_sync.is_enabled(),
packages,
requirements,
constraints: constraints
.into_iter()
.filter_map(Maybe::into_option)
.collect(),
marker,
dependency_type,
raw,
bounds,
rev,
tag,
branch,
lfs,
package,
script,
python: python.and_then(Maybe::into_option),
workspace: flag(workspace, no_workspace, "workspace"),
no_install_project,
only_install_project,
no_install_workspace,
only_install_workspace,
no_install_local,
only_install_local,
no_install_package,
only_install_package,
editable: flag(editable.into(), no_editable.into(), "editable"),
extras: extra.unwrap_or_default(),
refresh: Refresh::from(refresh),
indexes,
settings: ResolverInstallerSettings::combine(
resolver_installer_options(installer, build),
filesystem,
),
install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
}
}
}
#[expect(dead_code)]
#[derive(Debug, Clone)]
pub(crate) struct RemoveSettings {
pub(crate) lock_check: LockCheck,
pub(crate) frozen: Option<FrozenSource>,
pub(crate) active: Option<bool>,
pub(crate) no_sync: bool,
pub(crate) packages: Vec<PackageName>,
pub(crate) dependency_type: DependencyType,
pub(crate) package: Option<PackageName>,
pub(crate) script: Option<PathBuf>,
pub(crate) python: Option<String>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) refresh: Refresh,
pub(crate) settings: ResolverInstallerSettings,
}
impl RemoveSettings {
pub(crate) fn resolve(
args: RemoveArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let RemoveArgs {
dev,
optional,
packages,
group,
no_sync,
locked,
frozen,
active,
no_active,
installer,
build,
refresh,
package,
script,
python,
} = args;
let dev = dev || environment.dev.value == Some(true);
let dependency_type = if let Some(extra) = optional {
DependencyType::Optional(extra)
} else if let Some(group) = group {
DependencyType::Group(group)
} else if dev {
DependencyType::Dev
} else {
DependencyType::Production
};
let filesystem_install_mirrors = filesystem
.clone()
.map(|fs| fs.install_mirrors.clone())
.unwrap_or_default();
let packages = packages
.into_iter()
.map(|requirement| requirement.name)
.collect();
let locked = resolve_flag(locked, "locked", environment.locked);
let frozen = resolve_flag(frozen, "frozen", environment.frozen);
let no_sync = resolve_flag(no_sync, "no-sync", environment.no_sync);
check_conflicts(locked, frozen);
check_conflicts(no_sync, frozen);
Self {
lock_check: resolve_lock_check(locked),
frozen: resolve_frozen(frozen),
active: flag(active, no_active, "active"),
no_sync: no_sync.is_enabled(),
packages,
dependency_type,
package,
script,
python: python.and_then(Maybe::into_option),
refresh: Refresh::from(refresh),
settings: ResolverInstallerSettings::combine(
resolver_installer_options(installer, build),
filesystem,
),
install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct VersionSettings {
pub(crate) value: Option<String>,
pub(crate) bump: Vec<VersionBumpSpec>,
pub(crate) short: bool,
pub(crate) output_format: VersionFormat,
pub(crate) dry_run: bool,
pub(crate) lock_check: LockCheck,
pub(crate) frozen: Option<FrozenSource>,
pub(crate) active: Option<bool>,
pub(crate) no_sync: bool,
pub(crate) package: Option<PackageName>,
pub(crate) python: Option<String>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) refresh: Refresh,
pub(crate) settings: ResolverInstallerSettings,
}
impl VersionSettings {
pub(crate) fn resolve(
args: VersionArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let VersionArgs {
value,
bump,
short,
output_format,
dry_run,
no_sync,
locked,
frozen,
active,
no_active,
installer,
build,
refresh,
package,
python,
} = args;
let filesystem_install_mirrors = filesystem
.clone()
.map(|fs| fs.install_mirrors.clone())
.unwrap_or_default();
let locked = resolve_flag(locked, "locked", environment.locked);
let frozen = resolve_flag(frozen, "frozen", environment.frozen);
let no_sync = resolve_flag(no_sync, "no-sync", environment.no_sync);
check_conflicts(locked, frozen);
check_conflicts(no_sync, frozen);
Self {
value,
bump,
short,
output_format,
dry_run,
lock_check: resolve_lock_check(locked),
frozen: resolve_frozen(frozen),
active: flag(active, no_active, "active"),
no_sync: no_sync.is_enabled(),
package,
python: python.and_then(Maybe::into_option),
refresh: Refresh::from(refresh),
settings: ResolverInstallerSettings::combine(
resolver_installer_options(installer, build),
filesystem,
),
install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct TreeSettings {
pub(crate) groups: DependencyGroups,
pub(crate) lock_check: LockCheck,
pub(crate) frozen: Option<FrozenSource>,
pub(crate) universal: bool,
pub(crate) depth: u8,
pub(crate) prune: Vec<PackageName>,
pub(crate) package: Vec<PackageName>,
pub(crate) no_dedupe: bool,
pub(crate) invert: bool,
pub(crate) outdated: bool,
pub(crate) show_sizes: bool,
#[allow(dead_code)]
pub(crate) script: Option<PathBuf>,
pub(crate) python_version: Option<PythonVersion>,
pub(crate) python_platform: Option<TargetTriple>,
pub(crate) python: Option<String>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) resolver: ResolverSettings,
}
impl TreeSettings {
pub(crate) fn resolve(
args: TreeArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let TreeArgs {
tree,
universal,
dev,
only_dev,
no_dev,
group,
no_group,
no_default_groups,
only_group,
all_groups,
locked,
frozen,
build,
resolver,
script,
python_version,
python_platform,
python,
} = args;
let filesystem_install_mirrors = filesystem
.clone()
.map(|fs| fs.install_mirrors.clone())
.unwrap_or_default();
let locked = resolve_flag(locked, "locked", environment.locked);
let frozen = resolve_flag(frozen, "frozen", environment.frozen);
check_conflicts(locked, frozen);
let (dev, no_dev) = resolve_flag_pair(
dev,
no_dev,
"dev",
"no-dev",
Some(environment.dev),
Some(environment.no_dev),
);
Self {
groups: DependencyGroups::from_args(
dev.into(),
no_dev.into(),
only_dev,
group,
no_group,
no_default_groups,
only_group,
all_groups,
),
lock_check: resolve_lock_check(locked),
frozen: resolve_frozen(frozen),
universal,
depth: tree.depth,
prune: tree.prune,
package: tree.package,
no_dedupe: tree.no_dedupe,
invert: tree.invert,
outdated: tree.outdated,
show_sizes: tree.show_sizes,
script,
python_version,
python_platform,
python: python.and_then(Maybe::into_option),
resolver: ResolverSettings::combine(resolver_options(resolver, build), filesystem),
install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
}
}
}
#[expect(clippy::struct_excessive_bools, dead_code)]
#[derive(Debug, Clone)]
pub(crate) struct ExportSettings {
pub(crate) format: Option<ExportFormat>,
pub(crate) all_packages: bool,
pub(crate) package: Vec<PackageName>,
pub(crate) prune: Vec<PackageName>,
pub(crate) extras: ExtrasSpecification,
pub(crate) groups: DependencyGroups,
pub(crate) editable: Option<EditableMode>,
pub(crate) hashes: bool,
pub(crate) install_options: InstallOptions,
pub(crate) output_file: Option<PathBuf>,
pub(crate) lock_check: LockCheck,
pub(crate) frozen: Option<FrozenSource>,
pub(crate) include_annotations: bool,
pub(crate) include_header: bool,
pub(crate) script: Option<PathBuf>,
pub(crate) python: Option<String>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) refresh: Refresh,
pub(crate) settings: ResolverSettings,
}
impl ExportSettings {
pub(crate) fn resolve(
args: ExportArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let ExportArgs {
format,
all_packages,
package,
prune,
extra,
all_extras,
no_extra,
no_all_extras,
dev,
no_dev,
only_dev,
group,
no_group,
no_default_groups,
only_group,
all_groups,
annotate,
no_annotate,
header,
no_header,
editable,
no_editable,
hashes,
no_hashes,
output_file,
no_emit_project,
only_emit_project,
no_emit_workspace,
only_emit_workspace,
no_emit_local,
only_emit_local,
no_emit_package,
only_emit_package,
locked,
frozen: frozen_cli,
resolver,
build,
refresh,
script,
python,
} = args;
let filesystem_install_mirrors = filesystem
.clone()
.map(|fs| fs.install_mirrors.clone())
.unwrap_or_default();
let locked = resolve_flag(locked, "locked", environment.locked);
let frozen = resolve_flag(frozen_cli, "frozen", environment.frozen);
check_conflicts(locked, frozen);
let (dev, no_dev) = resolve_flag_pair(
dev,
no_dev,
"dev",
"no-dev",
Some(environment.dev),
Some(environment.no_dev),
);
let (editable, no_editable) = resolve_flag_pair(
editable,
no_editable,
"editable",
"no-editable",
None,
Some(environment.no_editable),
);
Self {
format,
all_packages,
package,
prune,
extras: ExtrasSpecification::from_args(
extra.unwrap_or_default(),
no_extra,
false,
vec![],
flag(all_extras, no_all_extras, "all-extras").unwrap_or_default(),
),
groups: DependencyGroups::from_args(
dev.into(),
no_dev.into(),
only_dev,
group,
no_group,
no_default_groups,
only_group,
all_groups,
),
editable: flag(editable.into(), no_editable.into(), "editable").map(EditableMode::from),
hashes: flag(hashes, no_hashes, "hashes").unwrap_or(true),
install_options: InstallOptions::new(
no_emit_project,
only_emit_project,
no_emit_workspace,
only_emit_workspace,
no_emit_local,
only_emit_local,
no_emit_package,
only_emit_package,
),
output_file,
lock_check: resolve_lock_check(locked),
frozen: resolve_frozen(frozen),
include_annotations: flag(annotate, no_annotate, "annotate").unwrap_or(true),
include_header: flag(header, no_header, "header").unwrap_or(true),
script,
python: python.and_then(Maybe::into_option),
refresh: Refresh::from(refresh),
settings: ResolverSettings::combine(resolver_options(resolver, build), filesystem),
install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct FormatSettings {
pub(crate) check: bool,
pub(crate) diff: bool,
pub(crate) extra_args: Vec<String>,
pub(crate) version: Option<String>,
pub(crate) exclude_newer: Option<jiff::Timestamp>,
pub(crate) no_project: bool,
pub(crate) show_version: bool,
}
impl FormatSettings {
pub(crate) fn resolve(args: FormatArgs, _filesystem: Option<FilesystemOptions>) -> Self {
let FormatArgs {
check,
diff,
extra_args,
version,
exclude_newer,
no_project,
show_version,
} = args;
Self {
check,
diff,
extra_args,
version,
exclude_newer: exclude_newer.map(|v| v.timestamp()),
no_project,
show_version,
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct AuditSettings {
pub(crate) extras: ExtrasSpecification,
pub(crate) groups: DependencyGroups,
pub(crate) lock_check: LockCheck,
pub(crate) frozen: Option<FrozenSource>,
pub(crate) python_version: Option<PythonVersion>,
pub(crate) python_platform: Option<TargetTriple>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) settings: ResolverSettings,
pub(crate) service_format: VulnerabilityServiceFormat,
pub(crate) service_url: Option<String>,
pub(crate) ignore: Vec<VulnerabilityID>,
pub(crate) ignore_until_fixed: Vec<VulnerabilityID>,
}
impl AuditSettings {
pub(crate) fn resolve(
args: AuditArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let AuditArgs {
no_extra,
no_dev,
no_group,
no_default_groups,
only_group,
only_dev,
script: _,
python_version,
python_platform,
locked,
frozen,
build,
resolver,
ignore,
ignore_until_fixed,
service_format,
service_url,
} = args;
let filesystem_install_mirrors = filesystem
.clone()
.map(|fs| fs.install_mirrors.clone())
.unwrap_or_default();
let filesystem_audit = filesystem
.as_ref()
.and_then(|fs| fs.audit.clone())
.unwrap_or_default();
let no_dev = no_dev || environment.no_dev.value == Some(true);
let locked = resolve_flag(locked, "locked", environment.locked);
let frozen = resolve_flag(frozen, "frozen", environment.frozen);
check_conflicts(locked, frozen);
Self {
extras: ExtrasSpecification::from_args(
vec![],
no_extra,
false,
vec![],
true,
),
groups: DependencyGroups::from_args(
only_group.is_empty() && !only_dev,
no_dev,
only_dev,
vec![],
no_group,
no_default_groups,
only_group.clone(),
only_group.is_empty() && !only_dev,
),
lock_check: resolve_lock_check(locked),
frozen: resolve_frozen(frozen),
python_version,
python_platform,
install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
settings: ResolverSettings::combine(resolver_options(resolver, build), filesystem),
service_format,
service_url,
ignore: {
let config_ignore = filesystem_audit.ignore.unwrap_or_default();
let mut merged = ignore;
merged.extend(config_ignore);
merged.into_iter().map(VulnerabilityID::new).collect()
},
ignore_until_fixed: {
let config_ignore_until_fixed =
filesystem_audit.ignore_until_fixed.unwrap_or_default();
let mut merged = ignore_until_fixed;
merged.extend(config_ignore_until_fixed);
merged.into_iter().map(VulnerabilityID::new).collect()
},
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct PipCompileSettings {
pub(crate) format: Option<PipCompileFormat>,
pub(crate) src_file: Vec<PathBuf>,
pub(crate) constraints: Vec<PathBuf>,
pub(crate) overrides: Vec<PathBuf>,
pub(crate) excludes: Vec<PathBuf>,
pub(crate) build_constraints: Vec<PathBuf>,
pub(crate) constraints_from_workspace: Vec<Requirement>,
pub(crate) overrides_from_workspace: Vec<Requirement>,
pub(crate) excludes_from_workspace: Vec<PackageName>,
pub(crate) build_constraints_from_workspace: Vec<Requirement>,
pub(crate) environments: SupportedEnvironments,
pub(crate) refresh: Refresh,
pub(crate) settings: PipSettings,
}
impl PipCompileSettings {
pub(crate) fn resolve(
args: PipCompileArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let PipCompileArgs {
src_file,
constraints,
overrides,
excludes,
extra,
all_extras,
no_all_extras,
build_constraints,
refresh,
no_deps,
deps,
group,
output_file,
format,
no_strip_extras,
strip_extras,
no_strip_markers,
strip_markers,
no_annotate,
annotate,
no_header,
header,
annotation_style,
custom_compile_command,
resolver,
python,
system,
no_system,
generate_hashes,
no_generate_hashes,
no_build,
build,
no_binary,
only_binary,
python_version,
python_platform,
universal,
no_universal,
no_emit_package,
emit_index_url,
no_emit_index_url,
emit_find_links,
no_emit_find_links,
emit_build_options,
no_emit_build_options,
emit_marker_expression,
no_emit_marker_expression,
emit_index_annotation,
no_emit_index_annotation,
torch_backend,
compat_args: _,
} = args;
let constraints_from_workspace = if let Some(configuration) = &filesystem {
configuration
.constraint_dependencies
.clone()
.unwrap_or_default()
.into_iter()
.map(|requirement| {
Requirement::from(requirement.with_origin(RequirementOrigin::Workspace))
})
.collect()
} else {
Vec::new()
};
let overrides_from_workspace = if let Some(configuration) = &filesystem {
configuration
.override_dependencies
.clone()
.unwrap_or_default()
.into_iter()
.map(|requirement| {
Requirement::from(requirement.with_origin(RequirementOrigin::Workspace))
})
.collect()
} else {
Vec::new()
};
let excludes_from_workspace = if let Some(configuration) = &filesystem {
configuration
.exclude_dependencies
.clone()
.unwrap_or_default()
} else {
Vec::new()
};
let build_constraints_from_workspace = if let Some(configuration) = &filesystem {
configuration
.build_constraint_dependencies
.clone()
.unwrap_or_default()
.into_iter()
.map(|requirement| {
Requirement::from(requirement.with_origin(RequirementOrigin::Workspace))
})
.collect()
} else {
Vec::new()
};
let environments = if let Some(configuration) = &filesystem {
configuration.environments.clone().unwrap_or_default()
} else {
SupportedEnvironments::default()
};
Self {
format,
src_file,
constraints: constraints
.into_iter()
.filter_map(Maybe::into_option)
.collect(),
build_constraints: build_constraints
.into_iter()
.filter_map(Maybe::into_option)
.collect(),
overrides: overrides
.into_iter()
.filter_map(Maybe::into_option)
.collect(),
excludes: excludes
.into_iter()
.filter_map(Maybe::into_option)
.collect(),
constraints_from_workspace,
overrides_from_workspace,
excludes_from_workspace,
build_constraints_from_workspace,
environments,
refresh: Refresh::from(refresh),
settings: PipSettings::combine(
PipOptions {
python: python.and_then(Maybe::into_option),
system: flag(system, no_system, "system"),
no_build: flag(no_build, build, "build"),
no_binary,
only_binary,
extra,
all_extras: flag(all_extras, no_all_extras, "all-extras"),
no_deps: flag(no_deps, deps, "deps"),
group: Some(group),
output_file,
no_strip_extras: flag(no_strip_extras, strip_extras, "strip-extras"),
no_strip_markers: flag(no_strip_markers, strip_markers, "strip-markers"),
no_annotate: flag(no_annotate, annotate, "annotate"),
no_header: flag(no_header, header, "header"),
custom_compile_command,
generate_hashes: flag(generate_hashes, no_generate_hashes, "generate-hashes"),
python_version,
python_platform,
universal: flag(universal, no_universal, "universal"),
no_emit_package,
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"),
emit_build_options: flag(
emit_build_options,
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,
torch_backend,
..PipOptions::from(resolver)
},
filesystem,
environment,
),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct PipSyncSettings {
pub(crate) src_file: Vec<PathBuf>,
pub(crate) constraints: Vec<PathBuf>,
pub(crate) build_constraints: Vec<PathBuf>,
pub(crate) dry_run: DryRun,
pub(crate) refresh: Refresh,
pub(crate) settings: PipSettings,
}
impl PipSyncSettings {
pub(crate) fn resolve(
args: Box<PipSyncArgs>,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let PipSyncArgs {
src_file,
constraints,
build_constraints,
extra,
all_extras,
no_all_extras,
group,
installer,
refresh,
require_hashes,
no_require_hashes,
verify_hashes,
no_verify_hashes,
python,
system,
no_system,
break_system_packages,
no_break_system_packages,
target,
prefix,
allow_empty_requirements,
no_allow_empty_requirements,
no_build,
build,
no_binary,
only_binary,
python_version,
python_platform,
strict,
no_strict,
dry_run,
torch_backend,
compat_args: _,
} = *args;
Self {
src_file,
constraints: constraints
.into_iter()
.filter_map(Maybe::into_option)
.collect(),
build_constraints: build_constraints
.into_iter()
.filter_map(Maybe::into_option)
.collect(),
dry_run: DryRun::from_args(dry_run),
refresh: Refresh::from(refresh),
settings: PipSettings::combine(
PipOptions {
python: python.and_then(Maybe::into_option),
system: flag(system, no_system, "system"),
break_system_packages: flag(
break_system_packages,
no_break_system_packages,
"break-system-packages",
),
target,
prefix,
require_hashes: flag(require_hashes, no_require_hashes, "require-hashes"),
verify_hashes: flag(verify_hashes, no_verify_hashes, "verify-hashes"),
no_build: flag(no_build, build, "build"),
no_binary,
only_binary,
allow_empty_requirements: flag(
allow_empty_requirements,
no_allow_empty_requirements,
"allow-empty-requirements",
),
python_version,
python_platform,
strict: flag(strict, no_strict, "strict"),
extra,
all_extras: flag(all_extras, no_all_extras, "all-extras"),
group: Some(group),
torch_backend,
..PipOptions::from(installer)
},
filesystem,
environment,
),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct PipInstallSettings {
pub(crate) package: Vec<String>,
pub(crate) requirements: Vec<PathBuf>,
pub(crate) editables: Vec<String>,
pub(crate) editable: Option<EditableMode>,
pub(crate) constraints: Vec<PathBuf>,
pub(crate) overrides: Vec<PathBuf>,
pub(crate) excludes: Vec<PathBuf>,
pub(crate) build_constraints: Vec<PathBuf>,
pub(crate) dry_run: DryRun,
pub(crate) constraints_from_workspace: Vec<Requirement>,
pub(crate) overrides_from_workspace: Vec<Requirement>,
pub(crate) excludes_from_workspace: Vec<PackageName>,
pub(crate) build_constraints_from_workspace: Vec<Requirement>,
pub(crate) modifications: Modifications,
pub(crate) refresh: Refresh,
pub(crate) settings: PipSettings,
}
impl PipInstallSettings {
pub(crate) fn resolve(
args: PipInstallArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let PipInstallArgs {
package,
requirements,
editable,
no_editable,
constraints,
overrides,
excludes,
build_constraints,
extra,
all_extras,
no_all_extras,
installer,
refresh,
no_deps,
deps,
group,
require_hashes,
no_require_hashes,
verify_hashes,
no_verify_hashes,
python,
system,
no_system,
break_system_packages,
no_break_system_packages,
target,
prefix,
no_build,
build,
no_binary,
only_binary,
python_version,
python_platform,
inexact,
exact,
strict,
no_strict,
dry_run,
torch_backend,
compat_args: _,
} = args;
let constraints_from_workspace = if let Some(configuration) = &filesystem {
configuration
.constraint_dependencies
.clone()
.unwrap_or_default()
.into_iter()
.map(|requirement| {
Requirement::from(requirement.with_origin(RequirementOrigin::Workspace))
})
.collect()
} else {
Vec::new()
};
let overrides_from_workspace = if let Some(configuration) = &filesystem {
configuration
.override_dependencies
.clone()
.unwrap_or_default()
.into_iter()
.map(|requirement| {
Requirement::from(requirement.with_origin(RequirementOrigin::Workspace))
})
.collect()
} else {
Vec::new()
};
let excludes_from_workspace = if let Some(configuration) = &filesystem {
configuration
.exclude_dependencies
.clone()
.unwrap_or_default()
} else {
Vec::new()
};
let build_constraints_from_workspace = if let Some(configuration) = &filesystem {
configuration
.build_constraint_dependencies
.clone()
.unwrap_or_default()
.into_iter()
.map(|requirement| {
Requirement::from(requirement.with_origin(RequirementOrigin::Workspace))
})
.collect()
} else {
Vec::new()
};
Self {
package,
requirements,
editables: editable,
constraints: constraints
.into_iter()
.filter_map(Maybe::into_option)
.collect(),
overrides: overrides
.into_iter()
.filter_map(Maybe::into_option)
.collect(),
excludes: excludes
.into_iter()
.filter_map(Maybe::into_option)
.collect(),
build_constraints: build_constraints
.into_iter()
.filter_map(Maybe::into_option)
.collect(),
dry_run: DryRun::from_args(dry_run),
constraints_from_workspace,
overrides_from_workspace,
excludes_from_workspace,
build_constraints_from_workspace,
modifications: if flag(exact, inexact, "inexact").unwrap_or(false) {
Modifications::Exact
} else {
Modifications::Sufficient
},
editable: if no_editable || environment.no_editable.value == Some(true) {
Some(EditableMode::NonEditable)
} else {
None
},
refresh: Refresh::from(refresh),
settings: PipSettings::combine(
PipOptions {
python: python.and_then(Maybe::into_option),
system: flag(system, no_system, "system"),
break_system_packages: flag(
break_system_packages,
no_break_system_packages,
"break-system-packages",
),
target,
prefix,
no_build: flag(no_build, build, "build"),
no_binary,
only_binary,
strict: flag(strict, no_strict, "strict"),
extra,
all_extras: flag(all_extras, no_all_extras, "all-extras"),
group: Some(group),
no_deps: flag(no_deps, deps, "deps"),
python_version,
python_platform,
require_hashes: flag(require_hashes, no_require_hashes, "require-hashes"),
verify_hashes: flag(verify_hashes, no_verify_hashes, "verify-hashes"),
torch_backend,
..PipOptions::from(installer)
},
filesystem,
environment,
),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct PipUninstallSettings {
pub(crate) package: Vec<String>,
pub(crate) requirements: Vec<PathBuf>,
pub(crate) dry_run: DryRun,
pub(crate) settings: PipSettings,
}
impl PipUninstallSettings {
pub(crate) fn resolve(
args: PipUninstallArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let PipUninstallArgs {
package,
requirements,
python,
keyring_provider,
system,
no_system,
break_system_packages,
no_break_system_packages,
target,
prefix,
dry_run,
compat_args: _,
} = args;
Self {
package,
requirements,
dry_run: DryRun::from_args(dry_run),
settings: PipSettings::combine(
PipOptions {
python: python.and_then(Maybe::into_option),
system: flag(system, no_system, "system"),
break_system_packages: flag(
break_system_packages,
no_break_system_packages,
"break-system-packages",
),
target,
prefix,
keyring_provider,
..PipOptions::default()
},
filesystem,
environment,
),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct PipFreezeSettings {
pub(crate) exclude_editable: bool,
pub(crate) exclude: FxHashSet<PackageName>,
pub(crate) paths: Option<Vec<PathBuf>>,
pub(crate) settings: PipSettings,
}
impl PipFreezeSettings {
pub(crate) fn resolve(
args: PipFreezeArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let PipFreezeArgs {
exclude_editable,
exclude,
strict,
no_strict,
python,
paths,
system,
no_system,
target,
prefix,
compat_args: _,
} = args;
Self {
exclude_editable,
exclude: exclude.into_iter().collect(),
paths,
settings: PipSettings::combine(
PipOptions {
python: python.and_then(Maybe::into_option),
system: flag(system, no_system, "system"),
strict: flag(strict, no_strict, "strict"),
target,
prefix,
..PipOptions::default()
},
filesystem,
environment,
),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct PipListSettings {
pub(crate) editable: Option<bool>,
pub(crate) exclude: FxHashSet<PackageName>,
pub(crate) format: ListFormat,
pub(crate) outdated: bool,
pub(crate) settings: PipSettings,
}
impl PipListSettings {
pub(crate) fn resolve(
args: PipListArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let PipListArgs {
editable,
exclude_editable,
exclude,
format,
outdated,
no_outdated,
strict,
no_strict,
fetch,
python,
system,
no_system,
target,
prefix,
compat_args: _,
} = args;
Self {
editable: flag(editable, exclude_editable, "exclude-editable"),
exclude: exclude.into_iter().collect(),
format,
outdated: flag(outdated, no_outdated, "outdated").unwrap_or(false),
settings: PipSettings::combine(
PipOptions {
python: python.and_then(Maybe::into_option),
system: flag(system, no_system, "system"),
strict: flag(strict, no_strict, "strict"),
target,
prefix,
..PipOptions::from(fetch)
},
filesystem,
environment,
),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct PipShowSettings {
pub(crate) package: Vec<PackageName>,
pub(crate) files: bool,
pub(crate) settings: PipSettings,
}
impl PipShowSettings {
pub(crate) fn resolve(
args: PipShowArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let PipShowArgs {
package,
strict,
no_strict,
files,
python,
system,
no_system,
target,
prefix,
compat_args: _,
} = args;
Self {
package,
files,
settings: PipSettings::combine(
PipOptions {
python: python.and_then(Maybe::into_option),
system: flag(system, no_system, "system"),
strict: flag(strict, no_strict, "strict"),
target,
prefix,
..PipOptions::default()
},
filesystem,
environment,
),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct PipTreeSettings {
pub(crate) show_version_specifiers: bool,
pub(crate) depth: u8,
pub(crate) prune: Vec<PackageName>,
pub(crate) package: Vec<PackageName>,
pub(crate) no_dedupe: bool,
pub(crate) invert: bool,
pub(crate) outdated: bool,
pub(crate) settings: PipSettings,
}
impl PipTreeSettings {
pub(crate) fn resolve(
args: PipTreeArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let PipTreeArgs {
show_version_specifiers,
tree,
strict,
no_strict,
fetch,
python,
system,
no_system,
compat_args: _,
} = args;
Self {
show_version_specifiers,
depth: tree.depth,
prune: tree.prune,
no_dedupe: tree.no_dedupe,
invert: tree.invert,
package: tree.package,
outdated: tree.outdated,
settings: PipSettings::combine(
PipOptions {
python: python.and_then(Maybe::into_option),
system: flag(system, no_system, "system"),
strict: flag(strict, no_strict, "strict"),
..PipOptions::from(fetch)
},
filesystem,
environment,
),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct PipCheckSettings {
pub(crate) settings: PipSettings,
}
impl PipCheckSettings {
pub(crate) fn resolve(
args: PipCheckArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let PipCheckArgs {
python,
system,
no_system,
python_version,
python_platform,
} = args;
Self {
settings: PipSettings::combine(
PipOptions {
python: python.and_then(Maybe::into_option),
system: flag(system, no_system, "system"),
python_version,
python_platform,
..PipOptions::default()
},
filesystem,
environment,
),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct BuildSettings {
pub(crate) src: Option<PathBuf>,
pub(crate) package: Option<PackageName>,
pub(crate) all_packages: bool,
pub(crate) out_dir: Option<PathBuf>,
pub(crate) sdist: bool,
pub(crate) wheel: bool,
pub(crate) list: bool,
pub(crate) build_logs: bool,
pub(crate) gitignore: bool,
pub(crate) force_pep517: bool,
pub(crate) clear: bool,
pub(crate) build_constraints: Vec<PathBuf>,
pub(crate) build_constraints_from_workspace: Vec<Requirement>,
pub(crate) hash_checking: Option<HashCheckingMode>,
pub(crate) python: Option<String>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) refresh: Refresh,
pub(crate) settings: ResolverSettings,
}
impl BuildSettings {
pub(crate) fn resolve(
args: BuildArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let BuildArgs {
src,
out_dir,
package,
all_packages,
sdist,
wheel,
list,
force_pep517,
clear,
build_constraints,
require_hashes,
no_require_hashes,
verify_hashes,
no_verify_hashes,
build_logs,
no_build_logs,
create_gitignore,
no_create_gitignore,
python,
build,
refresh,
resolver,
} = args;
let filesystem_install_mirrors = match &filesystem {
Some(fs) => fs.install_mirrors.clone(),
None => PythonInstallMirrors::default(),
};
let build_constraints_from_workspace = if let Some(configuration) = &filesystem {
configuration
.build_constraint_dependencies
.clone()
.unwrap_or_default()
.into_iter()
.map(|requirement| {
Requirement::from(requirement.with_origin(RequirementOrigin::Workspace))
})
.collect()
} else {
Vec::new()
};
Self {
src,
package,
all_packages,
out_dir,
sdist,
wheel,
list,
build_logs: flag(build_logs, no_build_logs, "build-logs").unwrap_or(true),
force_pep517,
clear,
gitignore: flag(create_gitignore, no_create_gitignore, "create-gitignore")
.unwrap_or(true),
build_constraints: build_constraints
.into_iter()
.filter_map(Maybe::into_option)
.collect(),
build_constraints_from_workspace,
hash_checking: HashCheckingMode::from_args(
flag(require_hashes, no_require_hashes, "require-hashes"),
flag(verify_hashes, no_verify_hashes, "verify-hashes"),
),
python: python.and_then(Maybe::into_option),
refresh: Refresh::from(refresh),
settings: ResolverSettings::combine(resolver_options(resolver, build), filesystem),
install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct VenvSettings {
pub(crate) seed: bool,
pub(crate) allow_existing: bool,
pub(crate) clear: bool,
pub(crate) no_clear: bool,
pub(crate) path: Option<PathBuf>,
pub(crate) prompt: Option<String>,
pub(crate) system_site_packages: bool,
pub(crate) relocatable: bool,
pub(crate) no_relocatable: bool,
pub(crate) no_project: bool,
pub(crate) refresh: Refresh,
pub(crate) settings: PipSettings,
}
impl VenvSettings {
pub(crate) fn resolve(
args: VenvArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let VenvArgs {
python,
system,
no_system,
seed,
allow_existing,
clear,
no_clear,
path,
prompt,
system_site_packages,
relocatable,
no_relocatable,
index_args,
index_strategy,
keyring_provider,
exclude_newer,
no_project,
link_mode,
refresh,
compat_args: _,
exclude_newer_package,
} = args;
let seed = seed || environment.venv_seed.value == Some(true);
let (clear, no_clear) = resolve_flag_pair(
clear,
no_clear,
"clear",
"no-clear",
Some(environment.venv_clear),
None,
);
let (relocatable, no_relocatable) = resolve_flag_pair(
relocatable,
no_relocatable,
"relocatable",
"no-relocatable",
Some(environment.venv_relocatable),
None,
);
Self {
seed,
allow_existing,
clear: clear.into(),
no_clear: no_clear.into(),
path,
prompt,
system_site_packages,
no_project,
relocatable: relocatable.into(),
no_relocatable: no_relocatable.into(),
refresh: Refresh::from(refresh),
settings: PipSettings::combine(
PipOptions {
python: python.and_then(Maybe::into_option),
system: flag(system, no_system, "system"),
index_strategy,
keyring_provider,
exclude_newer,
exclude_newer_package: exclude_newer_package
.map(ExcludeNewerPackage::from_iter),
link_mode,
..PipOptions::from(index_args)
},
filesystem,
environment,
),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct InstallerSettingsRef<'a> {
pub(crate) index_locations: &'a IndexLocations,
pub(crate) index_strategy: IndexStrategy,
pub(crate) keyring_provider: KeyringProviderType,
pub(crate) dependency_metadata: &'a DependencyMetadata,
pub(crate) config_setting: &'a ConfigSettings,
pub(crate) config_settings_package: &'a PackageConfigSettings,
pub(crate) build_isolation: &'a BuildIsolation,
pub(crate) extra_build_dependencies: &'a ExtraBuildDependencies,
pub(crate) extra_build_variables: &'a ExtraBuildVariables,
pub(crate) exclude_newer: &'a ExcludeNewer,
pub(crate) link_mode: LinkMode,
pub(crate) compile_bytecode: bool,
pub(crate) reinstall: &'a Reinstall,
pub(crate) build_options: &'a BuildOptions,
pub(crate) sources: NoSources,
}
#[derive(Debug, Clone, Default)]
pub(crate) struct ResolverSettings {
pub(crate) build_options: BuildOptions,
pub(crate) config_setting: ConfigSettings,
pub(crate) config_settings_package: PackageConfigSettings,
pub(crate) dependency_metadata: DependencyMetadata,
pub(crate) exclude_newer: ExcludeNewer,
pub(crate) fork_strategy: ForkStrategy,
pub(crate) index_locations: IndexLocations,
pub(crate) index_strategy: IndexStrategy,
pub(crate) keyring_provider: KeyringProviderType,
pub(crate) link_mode: LinkMode,
pub(crate) build_isolation: BuildIsolation,
pub(crate) extra_build_dependencies: ExtraBuildDependencies,
pub(crate) extra_build_variables: ExtraBuildVariables,
pub(crate) prerelease: PrereleaseMode,
pub(crate) resolution: ResolutionMode,
pub(crate) sources: NoSources,
pub(crate) torch_backend: Option<TorchMode>,
pub(crate) upgrade: Upgrade,
}
impl ResolverSettings {
pub(crate) fn combine(args: ResolverOptions, filesystem: Option<FilesystemOptions>) -> Self {
let options = args.combine(ResolverOptions::from(
filesystem
.map(FilesystemOptions::into_options)
.map(|options| options.top_level)
.unwrap_or_default(),
));
Self::from(options)
}
}
impl From<ResolverOptions> for ResolverSettings {
fn from(value: ResolverOptions) -> Self {
let index_locations = IndexLocations::new(
value
.index
.into_iter()
.flatten()
.chain(value.extra_index_url.into_iter().flatten().map(Index::from))
.chain(value.index_url.into_iter().map(Index::from))
.collect(),
value
.find_links
.into_iter()
.flatten()
.map(Index::from)
.collect(),
value.no_index.unwrap_or_default(),
);
Self {
index_locations,
resolution: value.resolution.unwrap_or_default(),
prerelease: value.prerelease.unwrap_or_default(),
fork_strategy: value.fork_strategy.unwrap_or_default(),
dependency_metadata: DependencyMetadata::from_entries(
value.dependency_metadata.into_iter().flatten(),
),
index_strategy: value.index_strategy.unwrap_or_default(),
keyring_provider: value.keyring_provider.unwrap_or_default(),
config_setting: value.config_settings.unwrap_or_default(),
config_settings_package: value.config_settings_package.unwrap_or_default(),
build_isolation: value.build_isolation.unwrap_or_default(),
extra_build_dependencies: value.extra_build_dependencies.unwrap_or_default(),
extra_build_variables: value.extra_build_variables.unwrap_or_default(),
exclude_newer: value.exclude_newer,
link_mode: value.link_mode.unwrap_or_default(),
torch_backend: value.torch_backend,
sources: NoSources::from_args(
value.no_sources,
value.no_sources_package.unwrap_or_default(),
),
upgrade: value.upgrade.unwrap_or_default(),
build_options: BuildOptions::new(
NoBinary::from_args(value.no_binary, value.no_binary_package.unwrap_or_default()),
NoBuild::from_args(value.no_build, value.no_build_package.unwrap_or_default()),
),
}
}
}
#[derive(Debug, Clone, Default)]
pub(crate) struct ResolverInstallerSettings {
pub(crate) resolver: ResolverSettings,
pub(crate) compile_bytecode: bool,
pub(crate) reinstall: Reinstall,
}
impl ResolverInstallerSettings {
pub(crate) fn combine(
args: ResolverInstallerOptions,
filesystem: Option<FilesystemOptions>,
) -> Self {
let options = args.combine(ResolverInstallerOptions::from(
filesystem
.map(FilesystemOptions::into_options)
.map(|options| options.top_level)
.unwrap_or_default(),
));
Self::from(options)
}
}
impl From<ResolverInstallerOptions> for ResolverInstallerSettings {
fn from(value: ResolverInstallerOptions) -> Self {
let index_locations = IndexLocations::new(
value
.index
.into_iter()
.flatten()
.chain(value.extra_index_url.into_iter().flatten().map(Index::from))
.chain(value.index_url.into_iter().map(Index::from))
.collect(),
value
.find_links
.into_iter()
.flatten()
.map(Index::from)
.collect(),
value.no_index.unwrap_or_default(),
);
Self {
resolver: ResolverSettings {
build_options: BuildOptions::new(
NoBinary::from_args(
value.no_binary,
value.no_binary_package.unwrap_or_default(),
),
NoBuild::from_args(value.no_build, value.no_build_package.unwrap_or_default()),
),
config_setting: value.config_settings.unwrap_or_default(),
config_settings_package: value.config_settings_package.unwrap_or_default(),
dependency_metadata: DependencyMetadata::from_entries(
value.dependency_metadata.into_iter().flatten(),
),
exclude_newer: ExcludeNewer::from_args(
value.exclude_newer,
value
.exclude_newer_package
.unwrap_or_default()
.into_iter()
.map(Into::into)
.collect(),
),
fork_strategy: value.fork_strategy.unwrap_or_default(),
index_locations,
index_strategy: value.index_strategy.unwrap_or_default(),
keyring_provider: value.keyring_provider.unwrap_or_default(),
link_mode: value.link_mode.unwrap_or_default(),
build_isolation: value.build_isolation.unwrap_or_default(),
extra_build_dependencies: value.extra_build_dependencies.unwrap_or_default(),
extra_build_variables: value.extra_build_variables.unwrap_or_default(),
prerelease: value.prerelease.unwrap_or_default(),
resolution: value.resolution.unwrap_or_default(),
sources: NoSources::from_args(
value.no_sources,
value.no_sources_package.unwrap_or_default(),
),
torch_backend: value.torch_backend,
upgrade: value.upgrade.unwrap_or_default(),
},
compile_bytecode: value.compile_bytecode.unwrap_or_default(),
reinstall: value.reinstall.unwrap_or_default(),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct PipSettings {
pub(crate) index_locations: IndexLocations,
pub(crate) python: Option<String>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) system: bool,
pub(crate) extras: ExtrasSpecification,
pub(crate) groups: Vec<PipGroupName>,
pub(crate) break_system_packages: bool,
pub(crate) target: Option<Target>,
pub(crate) prefix: Option<Prefix>,
pub(crate) index_strategy: IndexStrategy,
pub(crate) keyring_provider: KeyringProviderType,
pub(crate) torch_backend: Option<TorchMode>,
pub(crate) build_isolation: BuildIsolation,
pub(crate) extra_build_dependencies: ExtraBuildDependencies,
pub(crate) extra_build_variables: ExtraBuildVariables,
pub(crate) build_options: BuildOptions,
pub(crate) allow_empty_requirements: bool,
pub(crate) strict: bool,
pub(crate) dependency_mode: DependencyMode,
pub(crate) resolution: ResolutionMode,
pub(crate) prerelease: PrereleaseMode,
pub(crate) fork_strategy: ForkStrategy,
pub(crate) dependency_metadata: DependencyMetadata,
pub(crate) output_file: Option<PathBuf>,
pub(crate) no_strip_extras: bool,
pub(crate) no_strip_markers: bool,
pub(crate) no_annotate: bool,
pub(crate) no_header: bool,
pub(crate) custom_compile_command: Option<String>,
pub(crate) generate_hashes: bool,
pub(crate) config_setting: ConfigSettings,
pub(crate) config_settings_package: PackageConfigSettings,
pub(crate) python_version: Option<PythonVersion>,
pub(crate) python_platform: Option<TargetTriple>,
pub(crate) universal: bool,
pub(crate) exclude_newer: ExcludeNewer,
pub(crate) no_emit_package: Vec<PackageName>,
pub(crate) emit_index_url: bool,
pub(crate) emit_find_links: bool,
pub(crate) emit_build_options: bool,
pub(crate) emit_marker_expression: bool,
pub(crate) emit_index_annotation: bool,
pub(crate) annotation_style: AnnotationStyle,
pub(crate) link_mode: LinkMode,
pub(crate) compile_bytecode: bool,
pub(crate) sources: NoSources,
pub(crate) hash_checking: Option<HashCheckingMode>,
pub(crate) upgrade: Upgrade,
pub(crate) reinstall: Reinstall,
}
impl PipSettings {
pub(crate) fn combine(
args: PipOptions,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let Options {
top_level,
pip,
install_mirrors: filesystem_install_mirrors,
..
} = filesystem
.map(FilesystemOptions::into_options)
.unwrap_or_default();
let PipOptions {
python,
system,
break_system_packages,
target,
prefix,
index,
index_url,
extra_index_url,
no_index,
find_links,
index_strategy,
torch_backend,
keyring_provider,
no_build,
no_binary,
only_binary,
no_build_isolation,
no_build_isolation_package,
extra_build_dependencies,
extra_build_variables,
strict,
extra,
all_extras,
no_extra,
group,
no_deps,
allow_empty_requirements,
resolution,
prerelease,
fork_strategy,
dependency_metadata,
output_file,
no_strip_extras,
no_strip_markers,
no_annotate,
no_header,
custom_compile_command,
generate_hashes,
config_settings,
config_settings_package,
python_version,
python_platform,
universal,
exclude_newer,
no_emit_package,
emit_index_url,
emit_find_links,
emit_build_options,
emit_marker_expression,
emit_index_annotation,
annotation_style,
link_mode,
compile_bytecode,
require_hashes,
verify_hashes,
no_sources,
no_sources_package,
upgrade,
upgrade_package,
reinstall,
reinstall_package,
exclude_newer_package,
} = pip.unwrap_or_default();
let ResolverInstallerSchema {
index: top_level_index,
index_url: top_level_index_url,
extra_index_url: top_level_extra_index_url,
no_index: top_level_no_index,
find_links: top_level_find_links,
index_strategy: top_level_index_strategy,
keyring_provider: top_level_keyring_provider,
resolution: top_level_resolution,
prerelease: top_level_prerelease,
fork_strategy: top_level_fork_strategy,
dependency_metadata: top_level_dependency_metadata,
config_settings: top_level_config_settings,
config_settings_package: top_level_config_settings_package,
no_build_isolation: top_level_no_build_isolation,
no_build_isolation_package: top_level_no_build_isolation_package,
extra_build_dependencies: top_level_extra_build_dependencies,
extra_build_variables: top_level_extra_build_variables,
exclude_newer: top_level_exclude_newer,
link_mode: top_level_link_mode,
compile_bytecode: top_level_compile_bytecode,
no_sources: top_level_no_sources,
no_sources_package: top_level_no_sources_package,
upgrade: top_level_upgrade,
upgrade_package: top_level_upgrade_package,
reinstall: top_level_reinstall,
reinstall_package: top_level_reinstall_package,
no_build: top_level_no_build,
no_build_package: top_level_no_build_package,
no_binary: top_level_no_binary,
no_binary_package: top_level_no_binary_package,
exclude_newer_package: top_level_exclude_newer_package,
torch_backend: top_level_torch_backend,
} = top_level;
let index = index.combine(top_level_index);
let no_index = no_index.combine(top_level_no_index);
let index_url = index_url.combine(top_level_index_url);
let extra_index_url = extra_index_url.combine(top_level_extra_index_url);
let find_links = find_links.combine(top_level_find_links);
let index_strategy = index_strategy.combine(top_level_index_strategy);
let keyring_provider = keyring_provider.combine(top_level_keyring_provider);
let resolution = resolution.combine(top_level_resolution);
let prerelease = prerelease.combine(top_level_prerelease);
let fork_strategy = fork_strategy.combine(top_level_fork_strategy);
let dependency_metadata = dependency_metadata.combine(top_level_dependency_metadata);
let config_settings = config_settings.combine(top_level_config_settings);
let config_settings_package =
config_settings_package.combine(top_level_config_settings_package);
let no_build_isolation = no_build_isolation.combine(top_level_no_build_isolation);
let no_build_isolation_package =
no_build_isolation_package.combine(top_level_no_build_isolation_package);
let extra_build_dependencies =
extra_build_dependencies.combine(top_level_extra_build_dependencies);
let extra_build_variables = extra_build_variables.combine(top_level_extra_build_variables);
let exclude_newer = args
.exclude_newer
.combine(exclude_newer)
.combine(top_level_exclude_newer);
let exclude_newer_package = args
.exclude_newer_package
.combine(exclude_newer_package)
.combine(top_level_exclude_newer_package)
.unwrap_or_default();
let link_mode = link_mode.combine(top_level_link_mode);
let compile_bytecode = compile_bytecode.combine(top_level_compile_bytecode);
let no_sources = no_sources.combine(top_level_no_sources);
let no_sources_package = no_sources_package.combine(top_level_no_sources_package);
let upgrade = upgrade.combine(top_level_upgrade);
let upgrade_package = upgrade_package.combine(top_level_upgrade_package);
let reinstall = reinstall.combine(top_level_reinstall);
let reinstall_package = reinstall_package.combine(top_level_reinstall_package);
let torch_backend = torch_backend.combine(top_level_torch_backend);
Self {
index_locations: IndexLocations::new(
args.index
.into_iter()
.flatten()
.chain(args.extra_index_url.into_iter().flatten().map(Index::from))
.chain(args.index_url.into_iter().map(Index::from))
.chain(index.into_iter().flatten())
.chain(extra_index_url.into_iter().flatten().map(Index::from))
.chain(index_url.into_iter().map(Index::from))
.collect(),
args.find_links
.combine(find_links)
.into_iter()
.flatten()
.map(Index::from)
.collect(),
args.no_index.combine(no_index).unwrap_or_default(),
),
extras: ExtrasSpecification::from_args(
args.extra.combine(extra).unwrap_or_default(),
args.no_extra.combine(no_extra).unwrap_or_default(),
false,
vec![],
args.all_extras.combine(all_extras).unwrap_or_default(),
),
groups: args.group.combine(group).unwrap_or_default(),
dependency_mode: if args.no_deps.combine(no_deps).unwrap_or_default() {
DependencyMode::Direct
} else {
DependencyMode::Transitive
},
resolution: args.resolution.combine(resolution).unwrap_or_default(),
prerelease: args.prerelease.combine(prerelease).unwrap_or_default(),
fork_strategy: args
.fork_strategy
.combine(fork_strategy)
.unwrap_or_default(),
dependency_metadata: DependencyMetadata::from_entries(
args.dependency_metadata
.combine(dependency_metadata)
.unwrap_or_default(),
),
output_file: args.output_file.combine(output_file),
no_strip_extras: args
.no_strip_extras
.combine(no_strip_extras)
.unwrap_or_default(),
no_strip_markers: args
.no_strip_markers
.combine(no_strip_markers)
.unwrap_or_default(),
no_annotate: args.no_annotate.combine(no_annotate).unwrap_or_default(),
no_header: args.no_header.combine(no_header).unwrap_or_default(),
custom_compile_command: args.custom_compile_command.combine(custom_compile_command),
annotation_style: args
.annotation_style
.combine(annotation_style)
.unwrap_or_default(),
index_strategy: args
.index_strategy
.combine(index_strategy)
.unwrap_or_default(),
keyring_provider: args
.keyring_provider
.combine(keyring_provider)
.unwrap_or_default(),
generate_hashes: args
.generate_hashes
.combine(generate_hashes)
.unwrap_or_default(),
allow_empty_requirements: args
.allow_empty_requirements
.combine(allow_empty_requirements)
.unwrap_or_default(),
build_isolation: BuildIsolation::from_args(
args.no_build_isolation,
args.no_build_isolation_package.unwrap_or_default(),
)
.combine(BuildIsolation::from_args(
no_build_isolation,
no_build_isolation_package.unwrap_or_default(),
))
.unwrap_or_default(),
extra_build_dependencies: args
.extra_build_dependencies
.combine(extra_build_dependencies)
.unwrap_or_default(),
extra_build_variables: args
.extra_build_variables
.combine(extra_build_variables)
.unwrap_or_default(),
config_setting: args
.config_settings
.combine(config_settings)
.unwrap_or_default(),
config_settings_package: args
.config_settings_package
.combine(config_settings_package)
.unwrap_or_default(),
torch_backend: args.torch_backend.combine(torch_backend),
python_version: args.python_version.combine(python_version),
python_platform: args.python_platform.combine(python_platform),
universal: args.universal.combine(universal).unwrap_or_default(),
exclude_newer: ExcludeNewer::from_args(
exclude_newer,
exclude_newer_package.into_iter().map(Into::into).collect(),
),
no_emit_package: args
.no_emit_package
.combine(no_emit_package)
.unwrap_or_default(),
emit_index_url: args
.emit_index_url
.combine(emit_index_url)
.unwrap_or_default(),
emit_find_links: args
.emit_find_links
.combine(emit_find_links)
.unwrap_or_default(),
emit_build_options: args
.emit_build_options
.combine(emit_build_options)
.unwrap_or_default(),
emit_marker_expression: args
.emit_marker_expression
.combine(emit_marker_expression)
.unwrap_or_default(),
emit_index_annotation: args
.emit_index_annotation
.combine(emit_index_annotation)
.unwrap_or_default(),
link_mode: args.link_mode.combine(link_mode).unwrap_or_default(),
hash_checking: HashCheckingMode::from_args(
args.require_hashes.combine(require_hashes),
args.verify_hashes.combine(verify_hashes),
),
python: args.python.combine(python),
system: args.system.combine(system).unwrap_or_default(),
break_system_packages: args
.break_system_packages
.combine(break_system_packages)
.unwrap_or_default(),
target: args.target.combine(target).map(Target::from),
prefix: args.prefix.combine(prefix).map(Prefix::from),
compile_bytecode: args
.compile_bytecode
.combine(compile_bytecode)
.unwrap_or_default(),
sources: NoSources::from_args(
args.no_sources.combine(no_sources),
args.no_sources_package
.combine(no_sources_package)
.unwrap_or_default(),
),
strict: args.strict.combine(strict).unwrap_or_default(),
upgrade: Upgrade::from_args(
args.upgrade,
args.upgrade_package
.into_iter()
.flatten()
.map(Requirement::from)
.collect(),
Vec::new(),
)
.combine(Upgrade::from_args(
upgrade,
upgrade_package
.into_iter()
.flatten()
.map(Requirement::from)
.collect(),
Vec::new(),
))
.unwrap_or_default(),
reinstall: Reinstall::from_args(
args.reinstall,
args.reinstall_package.unwrap_or_default(),
)
.combine(Reinstall::from_args(
reinstall,
reinstall_package.unwrap_or_default(),
))
.unwrap_or_default(),
build_options: BuildOptions::new(
NoBinary::from_pip_args(args.no_binary.combine(no_binary).unwrap_or_default())
.combine(NoBinary::from_args(
top_level_no_binary,
top_level_no_binary_package.unwrap_or_default(),
)),
NoBuild::from_pip_args(
args.only_binary.combine(only_binary).unwrap_or_default(),
args.no_build.combine(no_build).unwrap_or_default(),
)
.combine(NoBuild::from_args(
top_level_no_build,
top_level_no_build_package.unwrap_or_default(),
)),
),
install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
}
}
}
impl<'a> From<&'a ResolverInstallerSettings> for InstallerSettingsRef<'a> {
fn from(settings: &'a ResolverInstallerSettings) -> Self {
Self {
index_locations: &settings.resolver.index_locations,
index_strategy: settings.resolver.index_strategy,
keyring_provider: settings.resolver.keyring_provider,
dependency_metadata: &settings.resolver.dependency_metadata,
config_setting: &settings.resolver.config_setting,
config_settings_package: &settings.resolver.config_settings_package,
build_isolation: &settings.resolver.build_isolation,
extra_build_dependencies: &settings.resolver.extra_build_dependencies,
extra_build_variables: &settings.resolver.extra_build_variables,
exclude_newer: &settings.resolver.exclude_newer,
link_mode: settings.resolver.link_mode,
compile_bytecode: settings.compile_bytecode,
reinstall: &settings.reinstall,
build_options: &settings.resolver.build_options,
sources: settings.resolver.sources.clone(),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct PublishSettings {
pub(crate) files: Vec<String>,
pub(crate) username: Option<String>,
pub(crate) password: Option<String>,
pub(crate) index: Option<String>,
pub(crate) dry_run: bool,
pub(crate) no_attestations: bool,
pub(crate) direct: bool,
pub(crate) publish_url: DisplaySafeUrl,
pub(crate) trusted_publishing: TrustedPublishing,
pub(crate) keyring_provider: KeyringProviderType,
pub(crate) check_url: Option<IndexUrl>,
pub(crate) index_locations: IndexLocations,
}
impl PublishSettings {
pub(crate) fn resolve(args: PublishArgs, filesystem: Option<FilesystemOptions>) -> Self {
let Options {
publish, top_level, ..
} = filesystem
.map(FilesystemOptions::into_options)
.unwrap_or_default();
let PublishOptions {
publish_url,
trusted_publishing,
check_url,
} = publish;
let ResolverInstallerSchema {
keyring_provider,
index,
extra_index_url,
index_url,
..
} = top_level;
let (username, password) = if let Some(token) = args.token {
(Some("__token__".to_string()), Some(token))
} else {
(args.username, args.password)
};
Self {
files: args.files,
username,
password,
dry_run: args.dry_run,
no_attestations: args.no_attestations,
direct: args.direct,
publish_url: args
.publish_url
.combine(publish_url)
.unwrap_or_else(|| DisplaySafeUrl::parse(PYPI_PUBLISH_URL).unwrap()),
trusted_publishing: trusted_publishing
.combine(args.trusted_publishing)
.unwrap_or_default(),
keyring_provider: args
.keyring_provider
.combine(keyring_provider)
.unwrap_or_default(),
check_url: args.check_url.combine(check_url),
index: args.index,
index_locations: IndexLocations::new(
index
.into_iter()
.flatten()
.chain(extra_index_url.into_iter().flatten().map(Index::from))
.chain(index_url.into_iter().map(Index::from))
.collect(),
Vec::new(),
false,
),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct AuthLogoutSettings {
pub(crate) service: Service,
pub(crate) username: Option<String>,
}
impl AuthLogoutSettings {
pub(crate) fn resolve(args: AuthLogoutArgs) -> Self {
Self {
service: args.service,
username: args.username,
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct AuthTokenSettings {
pub(crate) service: Service,
pub(crate) username: Option<String>,
}
impl AuthTokenSettings {
pub(crate) fn resolve(args: AuthTokenArgs) -> Self {
Self {
service: args.service,
username: args.username,
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct AuthLoginSettings {
pub(crate) service: Service,
pub(crate) username: Option<String>,
pub(crate) password: Option<String>,
pub(crate) token: Option<String>,
}
impl AuthLoginSettings {
pub(crate) fn resolve(args: AuthLoginArgs) -> Self {
Self {
service: args.service,
username: args.username,
password: args.password,
token: args.token,
}
}
}
mod env {
use uv_static::EnvVars;
pub(super) const UV_PYTHON_DOWNLOADS: (&str, &str) = (
EnvVars::UV_PYTHON_DOWNLOADS,
"one of 'auto', 'true', 'manual', 'never', or 'false'",
);
}
fn env<T>((name, expected): (&str, &str)) -> Option<T>
where
T: FromStr,
{
let val = match std::env::var(name) {
Ok(val) => val,
Err(VarError::NotPresent) => return None,
Err(VarError::NotUnicode(_)) => parse_failure(name, expected),
};
Some(
val.parse()
.unwrap_or_else(|_| parse_failure(name, expected)),
)
}
#[expect(clippy::exit, clippy::print_stderr)]
fn parse_failure(name: &str, expected: &str) -> ! {
eprintln!("error: invalid value for {name}, expected {expected}");
process::exit(1)
}