1use std::env::VarError;
4use std::ffi::OsString;
5use std::fmt;
6use std::num::NonZeroUsize;
7use std::path::{Path, PathBuf};
8use std::process;
9use std::str::FromStr;
10use std::time::Duration;
11
12use anyhow::{Result, bail};
13use rustc_hash::FxHashSet;
14
15use uv_audit::{VulnerabilityID, VulnerabilityServiceFormat};
16use uv_auth::Service;
17use uv_cache::{CacheArgs, Refresh};
18use uv_client::{Certificates, Connectivity, MetadataRangeRequest};
19use uv_configuration::{
20 ActiveEnvironment, AddBoundsKind, AnnotationStyle, BuildIsolation, BuildOptions, Concurrency,
21 DependencyGroups, DependencyMode, DevMode, DryRun, EditableMode, EnvFile, ExcludeDependency,
22 ExcludeNewer, ExcludeNewerPackage, ExportFormat, ExtrasSpecification, ForkStrategy,
23 GitLfsSetting, HashCheckingMode, IndexStrategy, InitKind, InitProjectKind, InstallOptions,
24 KeyringProviderType, Modifications, NoBinary, NoBuild, NoSources, Override, PackageOverride,
25 PipCompileFormat, Prerelease, ProjectBuildBackend, ProxyUrl, PythonUpgrade,
26 PythonUpgradeSource, Reinstall, RequiredVersion, RequirementsInput, ResolutionMode,
27 TargetTriple, ToolRunCommand, TrustedHost, TrustedPublishing, Upgrade, VersionControlSystem,
28};
29use uv_distribution_types::{
30 ConfigSettings, DependencyMetadata, ExcludeNewerOverride, ExtraBuildVariables, Index,
31 IndexLocations, IndexUrl, MinimumLibcVersion, NameRequirementSpecification,
32 PackageConfigSettings, Requirement,
33};
34use uv_install_wheel::LinkMode;
35use uv_normalize::{ExtraName, PackageName, PipGroupName};
36use uv_pep440::Version;
37use uv_pep508::{MarkerTree, RequirementOrigin};
38use uv_preview::Preview;
39use uv_pypi_types::SupportedEnvironments;
40use uv_python_types::{
41 Prefix, PythonArchitecture, PythonDownloads, PythonPreference, PythonVersion, Target,
42};
43use uv_redacted::DisplaySafeUrl;
44use uv_settings::{
45 Combine, EnvFlag, EnvironmentOptions, FilesystemOptions, FrozenFlag, FrozenSource,
46 IndexOptions, LockCheck, LockedFlag, LockedSource, MalwareCheckSettings, Options, PipOptions,
47 PreviewFeaturesOption, PreviewOption, PublishOptions, PythonInstallMirrors, PythonListKinds,
48 ResolverInstallerOptions, ResolverInstallerSchema, ResolverInstallerSettings, ResolverOptions,
49 ResolverSettings, resolve_prerelease,
50};
51use uv_static::EnvVars;
52use uv_torch::{AmdGpuArchitecture, TorchMode};
53use uv_warnings::warn_user_once;
54use uv_workspace::pyproject::{DependencyType, ExtraBuildDependencies, OverrideDependency};
55
56use crate::comma::CommaSeparatedRequirements;
57use crate::{
58 AddArgs, AuditArgs, AuditCommonArgs, AuditOutputFormat, AuthLoginArgs, AuthLogoutArgs,
59 AuthTokenArgs, ColorChoice, DependencyConstraintsArgs, ExternalCommand, GlobalArgs, InitArgs,
60 ListFormat, LockArgs, Maybe, MetadataArgs, PipCheckArgs, PipCompileArgs, PipFreezeArgs,
61 PipInstallArgs, PipInstallFormat, PipListArgs, PipShowArgs, PipSyncArgs, PipTreeArgs,
62 PipUninstallArgs, ProjectDependencyGroupsArgs, PythonFindArgs, PythonInstallArgs,
63 PythonListArgs, PythonListFormat, PythonPinArgs, PythonUninstallArgs, PythonUpgradeArgs,
64 RemoveArgs, RunArgs, SyncArgs, SyncFormat, ToolAuditArgs, ToolDirArgs, ToolInstallArgs,
65 ToolListArgs, ToolRunArgs, ToolUninstallArgs, TreeArgs, TreeFormat, UpgradeArgs, VenvArgs,
66 VersionArgs, VersionBumpSpec, VersionFormat,
67};
68use crate::{
69 AuthorFrom, BuildArgs, BuildOptionsArgs, CheckArgs, ExcludeNewerArgs, ExportArgs, FormatArgs,
70 HashCheckingArgs, PackageExcludeNewerArgs, PublishArgs, PythonDirArgs, RegistryClientArgs,
71 ResolverArgs, ResolverInstallerArgs, ToolUpgradeArgs,
72 options::{
73 Flag, FlagSource, IntoPipOptions, check_conflicts, flag, resolve_flag, resolve_flag_pair,
74 resolver_installer_options, resolver_options, upgrade_options,
75 },
76};
77
78const PYPI_PUBLISH_URL: &str = "https://upload.pypi.org/legacy/";
80
81#[derive(Debug, Clone)]
83pub struct GlobalSettings {
84 pub required_version: Option<RequiredVersion>,
85 pub quiet: u8,
86 pub verbose: u8,
87 pub color: ColorChoice,
88 pub network_settings: NetworkSettings,
89 pub concurrency: Concurrency,
90 pub show_settings: bool,
91 pub preview: Preview,
92 pub python_preference: PythonPreference,
93 pub python_arch: Option<PythonArchitecture>,
94 pub python_downloads: PythonDownloads,
95 pub no_progress: bool,
96 pub installer_metadata: bool,
97}
98
99impl GlobalSettings {
100 pub fn resolve(
102 args: &GlobalArgs,
103 workspace: Option<&FilesystemOptions>,
104 environment: &EnvironmentOptions,
105 custom_certificate_file: Option<&Path>,
106 ) -> anyhow::Result<Self> {
107 let network_settings =
108 NetworkSettings::resolve(args, workspace, environment, custom_certificate_file)?;
109 let python_preference = resolve_python_preference(args, workspace, environment)?;
110 let color = resolve_color(args);
111 Ok(Self {
112 required_version: workspace
113 .and_then(|workspace| workspace.globals.required_version.clone()),
114 quiet: args.quiet,
115 verbose: args.verbose,
116 color,
117 network_settings,
118 concurrency: Concurrency::new(
119 environment
120 .concurrency
121 .downloads
122 .combine(workspace.and_then(|workspace| workspace.globals.concurrent_downloads))
123 .map(NonZeroUsize::get)
124 .unwrap_or(Concurrency::DEFAULT_DOWNLOADS),
125 environment
126 .concurrency
127 .builds
128 .combine(workspace.and_then(|workspace| workspace.globals.concurrent_builds))
129 .map(NonZeroUsize::get)
130 .unwrap_or_else(Concurrency::threads),
131 environment
132 .concurrency
133 .installs
134 .combine(workspace.and_then(|workspace| workspace.globals.concurrent_installs))
135 .map(NonZeroUsize::get)
136 .unwrap_or_else(Concurrency::threads),
137 environment
138 .concurrency
139 .cache_reads
140 .map(NonZeroUsize::get)
141 .unwrap_or(Concurrency::DEFAULT_CACHE_READS),
142 ),
143 show_settings: args.show_settings,
144 preview: resolve_preview(args, workspace, environment)?,
145 python_preference,
146 python_arch: environment.python_arch,
147 python_downloads: flag(
148 args.allow_python_downloads,
149 args.no_python_downloads,
150 "python-downloads",
151 )?
152 .map(PythonDownloads::from)
153 .combine(env(env::UV_PYTHON_DOWNLOADS))
154 .combine(workspace.and_then(|workspace| workspace.globals.python_downloads))
155 .unwrap_or_default(),
156 no_progress: resolve_flag(args.no_progress, "no-progress", environment.no_progress)
159 .is_enabled()
160 || std::env::var_os(EnvVars::RUST_LOG).is_some(),
161 installer_metadata: !resolve_flag(
162 args.no_installer_metadata,
163 "no-installer-metadata",
164 environment.no_installer_metadata,
165 )
166 .is_enabled(),
167 })
168 }
169}
170
171pub fn resolve_color(args: &GlobalArgs) -> ColorChoice {
173 if let Some(color_choice) = args.color {
174 color_choice
176 } else if args.no_color {
177 ColorChoice::Never
179 } else if std::env::var_os(EnvVars::NO_COLOR)
180 .as_ref()
181 .is_some_and(|v| !v.is_empty())
182 {
183 ColorChoice::Never
185 } else if std::env::var_os(EnvVars::FORCE_COLOR)
186 .as_ref()
187 .is_some_and(|v| !v.is_empty())
188 || std::env::var_os(EnvVars::CLICOLOR_FORCE)
189 .as_ref()
190 .is_some_and(|v| !v.is_empty())
191 {
192 ColorChoice::Always
194 } else {
195 ColorChoice::Auto
196 }
197}
198
199fn resolve_python_preference(
200 args: &GlobalArgs,
201 workspace: Option<&FilesystemOptions>,
202 environment: &EnvironmentOptions,
203) -> anyhow::Result<PythonPreference> {
204 let (managed_python, no_managed_python) = resolve_flag_pair(
206 args.managed_python,
207 args.no_managed_python,
208 "managed-python",
209 "no-managed-python",
210 Some(environment.managed_python),
211 Some(environment.no_managed_python),
212 );
213
214 if managed_python.is_enabled() && args.python_preference.is_some() {
216 check_conflicts(managed_python, Flag::from_cli("python-preference"))?;
217 }
218
219 if no_managed_python.is_enabled() && args.python_preference.is_some() {
221 check_conflicts(no_managed_python, Flag::from_cli("python-preference"))?;
222 }
223
224 Ok(if managed_python.is_enabled() {
225 PythonPreference::OnlyManaged
226 } else if no_managed_python.is_enabled() {
227 PythonPreference::OnlySystem
228 } else {
229 args.python_preference
230 .combine(workspace.and_then(|workspace| workspace.globals.python_preference))
231 .unwrap_or_default()
232 })
233}
234
235pub fn resolve_preview(
237 args: &GlobalArgs,
238 workspace: Option<&FilesystemOptions>,
239 environment: &EnvironmentOptions,
240) -> anyhow::Result<Preview> {
241 if let Some(enabled) = flag(args.preview, args.no_preview, "preview")? {
243 return Ok(if enabled {
244 Preview::all()
245 } else {
246 Preview::default()
247 });
248 }
249
250 if environment.preview.value == Some(true) {
252 return Ok(Preview::all());
253 }
254
255 let configured = workspace.and_then(|workspace| workspace.globals.preview.as_ref());
256
257 if matches!(
259 configured,
260 Some(
261 PreviewOption::Preview(true)
262 | PreviewOption::PreviewFeatures(PreviewFeaturesOption::Toggle(true))
263 )
264 ) {
265 return Ok(Preview::all());
266 }
267
268 if !args.preview_features.is_empty() {
270 return Ok(Preview::from_feature_names(&args.preview_features));
271 }
272
273 Ok(configured.map(PreviewOption::resolve).unwrap_or_default())
275}
276
277#[derive(Debug, Clone)]
279pub struct NetworkSettings {
280 pub connectivity: Connectivity,
281 offline: Flag,
282 pub system_certs: bool,
283 pub custom_certificates: Option<Certificates>,
284 pub http_proxy: Option<ProxyUrl>,
285 pub https_proxy: Option<ProxyUrl>,
286 pub no_proxy: Option<Vec<String>>,
287 pub allow_insecure_host: Vec<TrustedHost>,
288 pub read_timeout: Duration,
289 pub connect_timeout: Duration,
290 pub retries: u32,
291 pub metadata_range_request: MetadataRangeRequest,
292}
293
294impl NetworkSettings {
295 #[allow(deprecated)]
296 fn resolve(
297 args: &GlobalArgs,
298 workspace: Option<&FilesystemOptions>,
299 environment: &EnvironmentOptions,
300 custom_certificate_file: Option<&Path>,
301 ) -> anyhow::Result<Self> {
302 let offline = match flag(args.offline, args.no_offline, "offline")? {
305 Some(true) => Flag::from_cli("offline"),
306 Some(false) => Flag::disabled(),
307 None => {
308 let env_flag = resolve_flag(false, "offline", environment.offline);
310 if environment.offline.value.is_some() {
311 env_flag
312 } else if workspace
313 .and_then(|workspace| workspace.globals.offline)
314 .unwrap_or(false)
315 {
316 Flag::from_config("offline")
318 } else {
319 Flag::disabled()
320 }
321 }
322 };
323
324 let connectivity = if offline.is_enabled() {
325 Connectivity::Offline
326 } else {
327 Connectivity::Online
328 };
329
330 if args.native_tls {
331 warn_user_once!(
332 "The `--native-tls` flag is deprecated and will be removed in a future release. Use `--system-certs` instead."
333 );
334 }
335 if args.no_native_tls {
336 warn_user_once!(
337 "The `--no-native-tls` flag is deprecated and will be removed in a future release. Use `--no-system-certs` instead."
338 );
339 }
340 if environment.native_tls.value.is_some() && environment.system_certs.value.is_none() {
341 warn_user_once!(
342 "The `UV_NATIVE_TLS` environment variable is deprecated and will be removed in a future release. Use `UV_SYSTEM_CERTS` instead."
343 );
344 }
345 if let Some(workspace) = workspace
346 && workspace.globals.native_tls.is_some()
347 && workspace.globals.system_certs.is_none()
348 {
349 warn_user_once!(
350 "The `native-tls` setting is deprecated and will be removed in a future release. Use `system-certs` instead."
351 );
352 }
353
354 let system_certs =
361 if let Some(value) = flag(args.system_certs, args.no_system_certs, "system-certs")? {
362 value
363 } else if let Some(value) = flag(args.native_tls, args.no_native_tls, "native-tls")? {
364 value
365 } else if let Some(value) = environment.system_certs.value {
366 value
367 } else if let Some(value) = environment.native_tls.value {
368 value
369 } else {
370 workspace
371 .and_then(|workspace| {
372 workspace
373 .globals
374 .system_certs
375 .or(workspace.globals.native_tls)
376 })
377 .unwrap_or(false)
378 };
379
380 let allow_insecure_host = args
381 .allow_insecure_host
382 .as_ref()
383 .map(|allow_insecure_host| {
384 allow_insecure_host
385 .iter()
386 .filter_map(|value| value.clone().into_option())
387 })
388 .into_iter()
389 .flatten()
390 .chain(
391 workspace
392 .and_then(|workspace| workspace.globals.allow_insecure_host.clone())
393 .into_iter()
394 .flatten(),
395 )
396 .collect();
397 let http_proxy = workspace.and_then(|workspace| workspace.globals.http_proxy.clone());
398 let https_proxy = workspace.and_then(|workspace| workspace.globals.https_proxy.clone());
399 let no_proxy = workspace.and_then(|workspace| workspace.globals.no_proxy.clone());
400
401 let custom_certificates = custom_certificate_file
402 .map(Certificates::from_file)
403 .transpose()?
404 .or_else(Certificates::from_env);
405
406 Ok(Self {
407 connectivity,
408 offline,
409 system_certs,
410 custom_certificates,
411 http_proxy,
412 https_proxy,
413 no_proxy,
414 allow_insecure_host,
415 read_timeout: environment.http_read_timeout,
416 connect_timeout: environment.http_connect_timeout,
417 retries: environment.http_retries,
418 metadata_range_request: environment
419 .require_metadata_range_requests
420 .unwrap_or_default()
421 .into(),
422 })
423 }
424
425 pub fn check_refresh_conflict(&self, refresh: &Refresh) -> anyhow::Result<()> {
430 if !matches!(refresh, Refresh::None(_)) {
431 check_conflicts(self.offline, Flag::from_cli("refresh"))?;
435 }
436 Ok(())
437 }
438}
439
440#[derive(Debug, Clone)]
442pub struct CacheSettings {
443 pub no_cache: bool,
444 pub cache_dir: Option<PathBuf>,
445}
446
447impl CacheSettings {
448 pub fn resolve(
450 args: CacheArgs,
451 workspace: Option<&FilesystemOptions>,
452 environment: &EnvironmentOptions,
453 ) -> Self {
454 Self {
455 no_cache: args
456 .no_cache
457 .then_some(true)
458 .combine(environment.no_cache.value)
459 .combine(workspace.and_then(|workspace| workspace.globals.no_cache))
460 .unwrap_or(false),
461 cache_dir: args
462 .cache_dir
463 .or_else(|| workspace.and_then(|workspace| workspace.globals.cache_dir.clone())),
464 }
465 }
466}
467
468#[derive(Debug, Clone)]
470pub struct InitSettings {
471 pub path: Option<PathBuf>,
472 pub name: Option<PackageName>,
473 pub kind: InitKind,
474 pub bare: bool,
475 pub description: Option<String>,
476 pub no_description: bool,
477 pub vcs: Option<VersionControlSystem>,
478 pub build_backend: Option<ProjectBuildBackend>,
479 pub no_readme: bool,
480 pub author_from: Option<AuthorFrom>,
481 pub pin_python: bool,
482 pub no_workspace: bool,
483 pub python: Option<String>,
484 pub install_mirrors: PythonInstallMirrors,
485}
486
487impl InitSettings {
488 pub fn resolve(
490 args: InitArgs,
491 filesystem: Option<FilesystemOptions>,
492 environment: EnvironmentOptions,
493 ) -> Result<Self> {
494 let InitArgs {
495 path,
496 name,
497 r#virtual,
498 package,
499 no_package,
500 bare,
501 app,
502 lib,
503 script,
504 description,
505 no_description,
506 vcs,
507 build_backend,
508 no_readme,
509 author_from,
510 no_pin_python,
511 pin_python,
512 no_workspace,
513 python,
514 ..
515 } = args;
516
517 let bare = resolve_flag(bare, "bare", environment.init_bare).is_enabled();
518
519 let filesystem_install_mirrors = filesystem
520 .map(|fs| fs.install_mirrors.clone())
521 .unwrap_or_default();
522
523 let no_description = no_description || (bare && description.is_none());
524
525 if r#virtual && lib {
526 bail!("`--virtual` and `--lib` are mutually exclusive");
527 }
528 if r#virtual && build_backend.is_some() {
529 bail!("`--virtual` and `--build-backend` are mutually exclusive");
530 }
531
532 let package = flag(
533 package || build_backend.is_some(),
534 no_package || r#virtual,
535 "virtual",
536 )?;
537
538 let kind = if script {
539 InitKind::Script
540 } else if bare {
541 if package == Some(true) || lib {
542 InitKind::Project(InitProjectKind::BareWithBuildSystem)
543 } else {
544 InitKind::Project(InitProjectKind::Bare)
545 }
546 } else {
547 let app_lib_kind = match (app, lib) {
549 (false, false) => InitProjectKind::ApplicationWithLibrary,
550 (true, false) => InitProjectKind::Application,
551 (false, true) => InitProjectKind::Library,
552 (true, true) => bail!("`app` and `lib` are mutually exclusive"),
553 };
554
555 let app_lib_kind = match (app_lib_kind, package) {
557 (InitProjectKind::ApplicationWithLibrary, None | Some(true)) => {
558 InitProjectKind::ApplicationWithLibrary
559 }
560 (InitProjectKind::ApplicationWithLibrary, Some(false)) => {
561 InitProjectKind::Application
562 }
563 (InitProjectKind::Application, None | Some(true)) => {
564 InitProjectKind::ApplicationWithLibrary
565 }
566 (InitProjectKind::Application, Some(false)) => InitProjectKind::Application,
567 (InitProjectKind::Library, None | Some(true)) => InitProjectKind::Library,
568 (InitProjectKind::Library, Some(false)) => {
569 bail!("`lib` and `no_package` are mutually exclusive");
570 }
571 (InitProjectKind::Bare | InitProjectKind::BareWithBuildSystem, _) => {
572 unreachable!()
573 }
574 };
575 InitKind::Project(app_lib_kind)
576 };
577
578 if script && package == Some(true) {
579 warn_user_once!("`--package` is a no-op for Python scripts, which are standalone");
580 }
581
582 Ok(Self {
583 path,
584 name,
585 kind,
586 bare,
587 description,
588 no_description,
589 vcs: vcs.or(bare.then_some(VersionControlSystem::None)),
590 build_backend,
591 no_readme,
592 author_from,
593 pin_python: flag(pin_python, no_pin_python, "pin-python")?.unwrap_or(!bare),
594 no_workspace,
595 python: python.and_then(Maybe::into_option),
596 install_mirrors: environment
597 .install_mirrors
598 .combine(filesystem_install_mirrors),
599 })
600 }
601}
602
603impl From<LockCheck> for Flag {
604 fn from(lock_check: LockCheck) -> Self {
605 match lock_check {
606 LockCheck::Enabled(LockedSource::Cli(flag)) => Self::from_cli(flag.name()),
607 LockCheck::Enabled(LockedSource::Env) => Self::Enabled {
608 source: FlagSource::Env(EnvVars::UV_LOCKED),
609 name: "locked",
610 },
611 LockCheck::Disabled => Self::disabled(),
612 }
613 }
614}
615
616impl From<FrozenSource> for Flag {
617 fn from(source: FrozenSource) -> Self {
618 match source {
619 FrozenSource::Cli(flag) => Self::from_cli(flag.name()),
620 FrozenSource::Env => Self::Enabled {
621 source: FlagSource::Env(EnvVars::UV_FROZEN),
622 name: "frozen",
623 },
624 }
625 }
626}
627
628fn resolve_lock_flags(
630 locked: LockCheck,
631 frozen: Option<FrozenSource>,
632) -> anyhow::Result<(LockCheck, Option<FrozenSource>)> {
633 match (locked, frozen) {
634 (LockCheck::Enabled(LockedSource::Cli(flag)), Some(FrozenSource::Env)) => {
635 warn_user_once!("Ignoring `UV_FROZEN` because `{flag}` was provided");
636 Ok((locked, None))
637 }
638 (LockCheck::Enabled(LockedSource::Env), Some(FrozenSource::Cli(flag))) => {
639 warn_user_once!("Ignoring `UV_LOCKED` because `{flag}` was provided");
640 Ok((LockCheck::Disabled, frozen))
641 }
642 _ => {
643 check_conflicts(
644 Flag::from(locked),
645 frozen.map_or(Flag::Disabled, Flag::from),
646 )?;
647 Ok((locked, frozen))
648 }
649 }
650}
651
652fn resolve_frozen(
654 enabled: bool,
655 disabled: bool,
656 cli_flag: FrozenFlag,
657 environment: EnvFlag,
658) -> Option<FrozenSource> {
659 if enabled {
660 Some(FrozenSource::Cli(cli_flag))
661 } else if !disabled && environment.value == Some(true) {
662 Some(FrozenSource::Env)
663 } else {
664 None
665 }
666}
667
668fn resolve_lock_check(
670 enabled: bool,
671 disabled: bool,
672 cli_flag: LockedFlag,
673 environment: EnvFlag,
674) -> LockCheck {
675 if enabled {
676 LockCheck::Enabled(LockedSource::Cli(cli_flag))
677 } else if !disabled && environment.value == Some(true) {
678 LockCheck::Enabled(LockedSource::Env)
679 } else {
680 LockCheck::Disabled
681 }
682}
683
684#[derive(Debug, Clone)]
686pub struct RunSettings {
687 pub lock_check: LockCheck,
688 pub frozen: Option<FrozenSource>,
689 pub extras: ExtrasSpecification,
690 pub groups: DependencyGroups,
691 pub editable: Option<EditableMode>,
692 pub modifications: Modifications,
693 pub with: Vec<String>,
694 pub with_editable: Vec<String>,
695 pub with_requirements: Vec<RequirementsInput>,
696 pub isolated: bool,
697 pub show_resolution: bool,
698 pub all_packages: bool,
699 pub package: Option<PackageName>,
700 pub no_project: bool,
701 pub active: ActiveEnvironment,
702 pub no_sync: bool,
703 pub python: Option<String>,
704 pub python_platform: Option<TargetTriple>,
705 pub install_mirrors: PythonInstallMirrors,
706 pub refresh: Refresh,
707 pub settings: ResolverInstallerSettings,
708 pub env_file: EnvFile,
709 pub max_recursion_depth: u32,
710 pub malware_settings: MalwareCheckSettings,
711 #[cfg(unix)]
712 pub run_rlimit_nofile: Option<u32>,
713}
714
715impl RunSettings {
716 const DEFAULT_MAX_RECURSION_DEPTH: u32 = 100;
721
722 pub fn resolve(
724 args: RunArgs,
725 filesystem: Option<FilesystemOptions>,
726 environment: EnvironmentOptions,
727 ) -> anyhow::Result<Self> {
728 let RunArgs {
729 extra,
730 all_extras,
731 no_extra,
732 no_all_extras,
733 dependency_groups:
734 ProjectDependencyGroupsArgs {
735 dev,
736 no_dev,
737 only_dev,
738 group,
739 no_group,
740 no_default_groups,
741 only_group,
742 all_groups,
743 },
744 module: _,
745 editable,
746 no_editable,
747 no_editable_package,
748 inexact,
749 exact,
750 script: _,
751 gui_script: _,
752 command: _,
753 with,
754 with_editable,
755 with_requirements,
756 isolated,
757 active,
758 no_active,
759 no_sync,
760 locked,
761 no_locked,
762 frozen,
763 no_frozen,
764 installer,
765 build,
766 refresh,
767 all_packages,
768 package,
769 no_project,
770 python,
771 python_platform,
772 show_resolution,
773 env_file,
774 no_env_file,
775 max_recursion_depth,
776 } = args;
777
778 let filesystem_install_mirrors = filesystem
779 .as_ref()
780 .map(|fs| fs.install_mirrors.clone())
781 .unwrap_or_default();
782
783 let locked = resolve_lock_check(locked, no_locked, LockedFlag::Locked, environment.locked);
785 let frozen = resolve_frozen(frozen, no_frozen, FrozenFlag::Frozen, environment.frozen);
786 let no_sync = resolve_flag(no_sync, "no-sync", environment.no_sync);
787
788 let (locked, frozen) = resolve_lock_flags(locked, frozen)?;
789
790 let (dev, no_dev) = resolve_flag_pair(
791 dev,
792 no_dev,
793 "dev",
794 "no-dev",
795 Some(environment.dev),
796 Some(environment.no_dev),
797 );
798
799 let (editable, no_editable) = resolve_flag_pair(
800 editable,
801 no_editable,
802 "editable",
803 "no-editable",
804 None,
805 Some(environment.no_editable),
806 );
807 let isolated = isolated || environment.isolated.value == Some(true);
808 let show_resolution = show_resolution || environment.show_resolution.value == Some(true);
809 let no_env_file = no_env_file || environment.no_env_file.value == Some(true);
810
811 let malware_settings = MalwareCheckSettings::resolve(filesystem.as_ref(), &environment);
812
813 Ok(Self {
814 lock_check: locked,
815 frozen,
816 extras: ExtrasSpecification::from_args(
817 extra.unwrap_or_default(),
818 no_extra,
819 false,
821 vec![],
823 flag(all_extras, no_all_extras, "all-extras")?.unwrap_or_default(),
824 ),
825 groups: DependencyGroups::from_args(
826 DevMode::from_args(dev.into(), no_dev.into(), only_dev),
827 group,
828 if no_group.is_empty() {
829 environment.no_group.clone().unwrap_or_default()
830 } else {
831 no_group
832 },
833 no_default_groups,
834 only_group,
835 all_groups,
836 ),
837 editable: EditableMode::from_args(
838 flag(editable.into(), no_editable.into(), "editable")?,
839 no_editable_package,
840 ),
841 modifications: if flag(exact, inexact, "inexact")?.unwrap_or(false) {
842 Modifications::Exact
843 } else {
844 Modifications::Sufficient
845 },
846 with: with
847 .into_iter()
848 .flat_map(CommaSeparatedRequirements::into_iter)
849 .collect(),
850 with_editable: with_editable
851 .into_iter()
852 .flat_map(CommaSeparatedRequirements::into_iter)
853 .collect(),
854 with_requirements: with_requirements
855 .into_iter()
856 .filter_map(Maybe::into_option)
857 .collect(),
858 isolated,
859 show_resolution,
860 all_packages,
861 package,
862 no_project,
863 no_sync: no_sync.is_enabled(),
864 active: flag(active, no_active, "active")?.into(),
865 python: python.and_then(Maybe::into_option),
866 python_platform,
867 refresh: Refresh::try_from(refresh)?,
868 settings: resolve_resolver_installer_settings(
869 installer,
870 build,
871 filesystem,
872 &environment,
873 )?,
874 env_file: EnvFile::from_args(env_file, no_env_file),
875 install_mirrors: environment
876 .install_mirrors
877 .combine(filesystem_install_mirrors),
878 max_recursion_depth: max_recursion_depth.unwrap_or(Self::DEFAULT_MAX_RECURSION_DEPTH),
879 malware_settings,
880 #[cfg(unix)]
881 run_rlimit_nofile: environment.run_rlimit_nofile,
882 })
883 }
884}
885
886#[derive(Debug, Clone)]
888pub struct ToolRunSettings {
889 pub command: Option<Vec<OsString>>,
890 pub from: Option<String>,
891 pub with: Vec<String>,
892 pub with_requirements: Vec<RequirementsInput>,
893 pub with_editable: Vec<String>,
894 pub constraints: Vec<RequirementsInput>,
895 pub overrides: Vec<RequirementsInput>,
896 pub build_constraints: Vec<RequirementsInput>,
897 pub isolated: bool,
898 pub show_resolution: bool,
899 pub lfs: GitLfsSetting,
900 pub python: Option<String>,
901 pub python_platform: Option<TargetTriple>,
902 pub install_mirrors: PythonInstallMirrors,
903 pub refresh: Refresh,
904 pub options: ResolverInstallerOptions,
905 pub settings: ResolverInstallerSettings,
906 pub env_file: Vec<PathBuf>,
907 pub no_env_file: bool,
908}
909
910impl ToolRunSettings {
911 pub fn resolve(
913 args: ToolRunArgs,
914 filesystem: Option<FilesystemOptions>,
915 invocation_source: ToolRunCommand,
916 environment: EnvironmentOptions,
917 ) -> anyhow::Result<Self> {
918 let ToolRunArgs {
919 command,
920 from,
921 with,
922 with_editable,
923 with_requirements,
924 constraints,
925 overrides,
926 build_constraints,
927 isolated,
928 env_file,
929 no_env_file,
930 show_resolution,
931 installer,
932 build,
933 refresh,
934 lfs,
935 python,
936 python_platform,
937 torch_backend,
938 generate_shell_completion: _,
939 } = args;
940
941 if installer.upgrade || !installer.upgrade_package.is_empty() {
943 if with.is_empty() && with_requirements.is_empty() {
944 warn_user_once!(
945 "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."
946 );
947 } else {
948 warn_user_once!(
949 "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."
950 );
951 }
952 }
953
954 if installer.reinstall.reinstall || !installer.reinstall.reinstall_package.is_empty() {
956 if with.is_empty() && with_requirements.is_empty() {
957 warn_user_once!(
958 "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."
959 );
960 } else {
961 warn_user_once!(
962 "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."
963 );
964 }
965 }
966
967 let filesystem_options = filesystem.map(FilesystemOptions::into_options);
968
969 let options = resolver_installer_options_with_environment(
970 resolver_installer_options(
971 installer,
972 build,
973 filesystem_options
974 .as_ref()
975 .and_then(|options| options.top_level.index.as_deref())
976 .unwrap_or_default(),
977 )?,
978 &environment,
979 )
980 .combine(ResolverInstallerOptions::from(
981 filesystem_options
982 .as_ref()
983 .map(|options| options.top_level.clone())
984 .unwrap_or_default(),
985 ));
986
987 let filesystem_install_mirrors = filesystem_options
988 .map(|options| options.install_mirrors.clone())
989 .unwrap_or_default();
990
991 let mut settings = ResolverInstallerSettings::from(options.clone());
992 if torch_backend.is_some() {
993 settings.resolver.torch_backend = torch_backend;
994 }
995 let lfs = GitLfsSetting::new(lfs.then_some(true), environment.lfs);
996
997 let isolated = isolated || environment.isolated.value == Some(true);
999 let show_resolution = show_resolution || environment.show_resolution.value == Some(true);
1000 let no_env_file = no_env_file || environment.no_env_file.value == Some(true);
1001
1002 Ok(Self {
1003 command: command.map(|ExternalCommand::Cmd(command)| command),
1004 from,
1005 with: with
1006 .into_iter()
1007 .flat_map(CommaSeparatedRequirements::into_iter)
1008 .collect(),
1009 with_editable: with_editable
1010 .into_iter()
1011 .flat_map(CommaSeparatedRequirements::into_iter)
1012 .collect(),
1013 with_requirements: with_requirements
1014 .into_iter()
1015 .filter_map(Maybe::into_option)
1016 .collect(),
1017 constraints: constraints
1018 .into_iter()
1019 .filter_map(Maybe::into_option)
1020 .collect(),
1021 overrides: overrides
1022 .into_iter()
1023 .filter_map(Maybe::into_option)
1024 .collect(),
1025 build_constraints: build_constraints
1026 .into_iter()
1027 .filter_map(Maybe::into_option)
1028 .collect(),
1029 isolated,
1030 show_resolution,
1031 lfs,
1032 python: python.and_then(Maybe::into_option),
1033 python_platform,
1034 refresh: Refresh::try_from(refresh)?,
1035 settings,
1036 options,
1037 install_mirrors: environment
1038 .install_mirrors
1039 .combine(filesystem_install_mirrors),
1040 env_file,
1041 no_env_file,
1042 })
1043 }
1044}
1045
1046#[derive(Debug, Clone)]
1048pub struct ToolInstallSettings {
1049 pub package: String,
1050 pub from: Option<String>,
1051 pub with: Vec<String>,
1052 pub with_requirements: Vec<RequirementsInput>,
1053 pub with_executables_from: Vec<String>,
1054 pub with_editable: Vec<String>,
1055 pub constraints: Vec<RequirementsInput>,
1056 pub overrides: Vec<RequirementsInput>,
1057 pub excludes: Vec<RequirementsInput>,
1058 pub build_constraints: Vec<RequirementsInput>,
1059 pub lfs: GitLfsSetting,
1060 pub python: Option<String>,
1061 pub python_platform: Option<TargetTriple>,
1062 pub refresh: Refresh,
1063 pub options: ResolverInstallerOptions,
1064 pub settings: ResolverInstallerSettings,
1065 pub force: bool,
1066 pub editable: bool,
1067 pub install_mirrors: PythonInstallMirrors,
1068}
1069
1070impl ToolInstallSettings {
1071 pub fn resolve(
1073 args: ToolInstallArgs,
1074 filesystem: Option<FilesystemOptions>,
1075 environment: EnvironmentOptions,
1076 ) -> anyhow::Result<Self> {
1077 let ToolInstallArgs {
1078 package,
1079 editable,
1080 from,
1081 with,
1082 with_editable,
1083 with_requirements,
1084 with_executables_from,
1085 constraints:
1086 DependencyConstraintsArgs {
1087 constraints,
1088 overrides,
1089 excludes,
1090 build_constraints,
1091 },
1092 lfs,
1093 installer,
1094 force,
1095 build,
1096 refresh,
1097 python,
1098 python_platform,
1099 torch_backend,
1100 } = args;
1101
1102 let filesystem_options = filesystem.map(FilesystemOptions::into_options);
1103
1104 let options = resolver_installer_options_with_environment(
1105 resolver_installer_options(
1106 installer,
1107 build,
1108 filesystem_options
1109 .as_ref()
1110 .and_then(|options| options.top_level.index.as_deref())
1111 .unwrap_or_default(),
1112 )?,
1113 &environment,
1114 )
1115 .combine(ResolverInstallerOptions::from(
1116 filesystem_options
1117 .as_ref()
1118 .map(|options| options.top_level.clone())
1119 .unwrap_or_default(),
1120 ));
1121
1122 let filesystem_install_mirrors = filesystem_options
1123 .map(|options| options.install_mirrors.clone())
1124 .unwrap_or_default();
1125
1126 let mut settings = ResolverInstallerSettings::from(options.clone());
1127 if torch_backend.is_some() {
1128 settings.resolver.torch_backend = torch_backend;
1129 }
1130 let lfs = GitLfsSetting::new(lfs.then_some(true), environment.lfs);
1131
1132 Ok(Self {
1133 package,
1134 from,
1135 with: with
1136 .into_iter()
1137 .flat_map(CommaSeparatedRequirements::into_iter)
1138 .collect(),
1139 with_editable: with_editable
1140 .into_iter()
1141 .flat_map(CommaSeparatedRequirements::into_iter)
1142 .collect(),
1143 with_requirements: with_requirements
1144 .into_iter()
1145 .filter_map(Maybe::into_option)
1146 .collect(),
1147 with_executables_from: with_executables_from
1148 .into_iter()
1149 .flat_map(CommaSeparatedRequirements::into_iter)
1150 .collect(),
1151 constraints: constraints
1152 .into_iter()
1153 .filter_map(Maybe::into_option)
1154 .collect(),
1155 overrides: overrides
1156 .into_iter()
1157 .filter_map(Maybe::into_option)
1158 .collect(),
1159 excludes: excludes
1160 .into_iter()
1161 .filter_map(Maybe::into_option)
1162 .collect(),
1163 build_constraints: build_constraints
1164 .into_iter()
1165 .filter_map(Maybe::into_option)
1166 .collect(),
1167 lfs,
1168 python: python.and_then(Maybe::into_option),
1169 python_platform,
1170 force,
1171 editable,
1172 refresh: Refresh::try_from(refresh)?,
1173 options,
1174 settings,
1175 install_mirrors: environment
1176 .install_mirrors
1177 .combine(filesystem_install_mirrors),
1178 })
1179 }
1180}
1181
1182#[derive(Debug, Clone)]
1184pub struct ToolUpgradeSettings {
1185 pub names: Vec<String>,
1186 pub python: Option<String>,
1187 pub python_platform: Option<TargetTriple>,
1188 pub install_mirrors: PythonInstallMirrors,
1189 pub args: ResolverInstallerOptions,
1190 pub filesystem: ResolverInstallerOptions,
1191}
1192impl ToolUpgradeSettings {
1193 pub fn resolve(
1195 args: ToolUpgradeArgs,
1196 filesystem: Option<FilesystemOptions>,
1197 environment: &EnvironmentOptions,
1198 ) -> anyhow::Result<Self> {
1199 let ToolUpgradeArgs {
1200 name,
1201 python,
1202 python_platform,
1203 upgrade,
1204 upgrade_package,
1205 upgrade_group,
1206 index_args,
1207 all,
1208 reinstall,
1209 registry_client,
1210 version_selection,
1211 config_setting,
1212 config_setting_package: config_settings_package,
1213 build_isolation,
1214 exclude_newer,
1215 link_mode,
1216 compile_bytecode,
1217 sources,
1218 build,
1219 } = args;
1220
1221 if upgrade {
1222 warn_user_once!("`--upgrade` is enabled by default on `uv tool upgrade`");
1223 }
1224 if !upgrade_package.is_empty() {
1225 warn_user_once!("`--upgrade-package` is enabled by default on `uv tool upgrade`");
1226 }
1227
1228 let installer = ResolverInstallerArgs {
1230 index_args,
1231 upgrade: upgrade_package.is_empty(),
1232 no_upgrade: false,
1233 upgrade_package,
1234 upgrade_group,
1235 reinstall,
1236 registry_client,
1237 version_selection,
1238 config_setting,
1239 config_settings_package,
1240 build_isolation,
1241 exclude_newer,
1242 link_mode,
1243 compile_bytecode,
1244 sources,
1245 };
1246
1247 let args = resolver_installer_options_with_environment(
1248 resolver_installer_options(installer, build, configured_indexes(filesystem.as_ref()))?,
1249 environment,
1250 );
1251 let filesystem = filesystem.map(FilesystemOptions::into_options);
1252 let filesystem_install_mirrors = filesystem
1253 .as_ref()
1254 .map(|options| options.install_mirrors.clone())
1255 .unwrap_or_default();
1256 let top_level = ResolverInstallerOptions::from(
1257 filesystem
1258 .map(|options| options.top_level)
1259 .unwrap_or_default(),
1260 );
1261
1262 Ok(Self {
1263 names: if all { vec![] } else { name },
1264 python: python.and_then(Maybe::into_option),
1265 python_platform,
1266 args,
1267 filesystem: top_level,
1268 install_mirrors: environment
1269 .install_mirrors
1270 .clone()
1271 .combine(filesystem_install_mirrors),
1272 })
1273 }
1274}
1275
1276#[derive(Debug, Clone)]
1278pub struct ToolListSettings {
1279 pub show_paths: bool,
1280 pub show_version_specifiers: bool,
1281 pub show_with: bool,
1282 pub show_extras: bool,
1283 pub show_python: bool,
1284 pub outdated: bool,
1285 pub args: ResolverInstallerOptions,
1286 pub filesystem: ResolverInstallerOptions,
1287}
1288
1289impl ToolListSettings {
1290 pub fn resolve(
1292 args: ToolListArgs,
1293 filesystem: Option<FilesystemOptions>,
1294 ) -> anyhow::Result<Self> {
1295 let ToolListArgs {
1296 show_paths,
1297 show_version_specifiers,
1298 show_with,
1299 show_extras,
1300 show_python,
1301 outdated,
1302 no_outdated,
1303 exclude_newer:
1304 PackageExcludeNewerArgs {
1305 exclude_newer: ExcludeNewerArgs { exclude_newer },
1306 exclude_newer_package,
1307 },
1308 python_preference: _,
1309 no_python_downloads: _,
1310 } = args;
1311
1312 let top_level = filesystem
1313 .map(FilesystemOptions::into_options)
1314 .map(|options| options.top_level)
1315 .unwrap_or_default();
1316 let filesystem = ResolverInstallerOptions {
1317 indexes: IndexOptions {
1318 index: top_level.index,
1319 ..IndexOptions::default()
1320 },
1321 exclude_newer: top_level.exclude_newer,
1322 exclude_newer_package: top_level.exclude_newer_package,
1323 ..ResolverInstallerOptions::default()
1324 };
1325
1326 Ok(Self {
1327 show_paths,
1328 show_version_specifiers,
1329 show_with,
1330 show_extras,
1331 show_python,
1332 outdated: flag(outdated, no_outdated, "outdated")?.unwrap_or(false),
1333 args: ResolverInstallerOptions {
1334 exclude_newer,
1335 exclude_newer_package: exclude_newer_package.map(ExcludeNewerPackage::from_iter),
1336 ..ResolverInstallerOptions::default()
1337 },
1338 filesystem,
1339 })
1340 }
1341}
1342
1343#[derive(Debug, Clone)]
1345pub struct ToolAuditSettings {
1346 pub names: Vec<PackageName>,
1347 pub output_format: AuditOutputFormat,
1348 pub service_format: VulnerabilityServiceFormat,
1349 pub service_url: Option<DisplaySafeUrl>,
1350 pub ignore: Vec<VulnerabilityID>,
1351 pub ignore_until_fixed: Vec<VulnerabilityID>,
1352 pub filesystem: ResolverInstallerOptions,
1353}
1354
1355impl ToolAuditSettings {
1356 pub fn resolve(args: ToolAuditArgs, filesystem: Option<FilesystemOptions>) -> Self {
1358 let ToolAuditArgs {
1359 name,
1360 all,
1361 audit:
1362 AuditCommonArgs {
1363 offline: _,
1364 output_format,
1365 ignore,
1366 ignore_until_fixed,
1367 service_format,
1368 service_url,
1369 },
1370 } = args;
1371
1372 let audit = filesystem
1373 .as_ref()
1374 .and_then(|options| options.audit.clone())
1375 .unwrap_or_default();
1376 let filesystem = filesystem
1377 .map(FilesystemOptions::into_options)
1378 .map(|options| ResolverInstallerOptions::from(options.top_level))
1379 .unwrap_or_default();
1380
1381 let ignore = ignore
1382 .into_iter()
1383 .chain(audit.ignore.unwrap_or_default())
1384 .map(VulnerabilityID::new)
1385 .collect();
1386 let ignore_until_fixed = ignore_until_fixed
1387 .into_iter()
1388 .chain(audit.ignore_until_fixed.unwrap_or_default())
1389 .map(VulnerabilityID::new)
1390 .collect();
1391
1392 Self {
1393 names: if all { vec![] } else { name },
1394 output_format,
1395 service_format,
1396 service_url,
1397 ignore,
1398 ignore_until_fixed,
1399 filesystem,
1400 }
1401 }
1402}
1403
1404#[derive(Debug, Clone)]
1406pub struct ToolUninstallSettings {
1407 pub name: Vec<PackageName>,
1408}
1409
1410impl ToolUninstallSettings {
1411 pub fn resolve(args: ToolUninstallArgs, _filesystem: Option<FilesystemOptions>) -> Self {
1413 let ToolUninstallArgs { name, all } = args;
1414
1415 Self {
1416 name: if all { vec![] } else { name },
1417 }
1418 }
1419}
1420
1421#[derive(Debug, Clone)]
1423pub struct ToolDirSettings {
1424 pub bin: bool,
1425}
1426
1427impl ToolDirSettings {
1428 #[expect(clippy::needless_pass_by_value)]
1430 pub fn resolve(args: ToolDirArgs, _filesystem: Option<FilesystemOptions>) -> Self {
1431 let ToolDirArgs { bin } = args;
1432
1433 Self { bin }
1434 }
1435}
1436
1437#[derive(Debug, Clone)]
1439pub struct PythonListSettings {
1440 pub request: Option<String>,
1441 pub kinds: PythonListKinds,
1442 pub all_platforms: bool,
1443 pub all_arches: bool,
1444 pub all_versions: bool,
1445 pub show_urls: bool,
1446 pub output_format: PythonListFormat,
1447 pub install_mirrors: PythonInstallMirrors,
1448}
1449
1450impl PythonListSettings {
1451 pub fn resolve(
1453 args: PythonListArgs,
1454 filesystem: Option<FilesystemOptions>,
1455 environment: EnvironmentOptions,
1456 ) -> Self {
1457 let PythonListArgs {
1458 request,
1459 all_versions,
1460 all_platforms,
1461 all_arches,
1462 only_installed,
1463 only_downloads,
1464 show_urls,
1465 output_format,
1466 python_downloads_json_url: python_downloads_json_url_arg,
1467 } = args;
1468
1469 let filesystem_install_mirrors = filesystem
1470 .map(|fs| fs.install_mirrors.clone())
1471 .unwrap_or_default();
1472
1473 let install_mirrors = PythonInstallMirrors {
1474 python_downloads_json_url: python_downloads_json_url_arg,
1475 ..Default::default()
1476 }
1477 .combine(environment.install_mirrors)
1478 .combine(filesystem_install_mirrors);
1479
1480 let kinds = if only_installed {
1481 PythonListKinds::Installed
1482 } else if only_downloads {
1483 PythonListKinds::Downloads
1484 } else {
1485 PythonListKinds::default()
1486 };
1487
1488 Self {
1489 request,
1490 kinds,
1491 all_platforms,
1492 all_arches,
1493 all_versions,
1494 show_urls,
1495 output_format,
1496 install_mirrors,
1497 }
1498 }
1499}
1500
1501#[derive(Debug, Clone)]
1503pub struct PythonDirSettings {
1504 pub bin: bool,
1505}
1506
1507impl PythonDirSettings {
1508 #[expect(clippy::needless_pass_by_value)]
1510 pub fn resolve(args: PythonDirArgs, _filesystem: Option<FilesystemOptions>) -> Self {
1511 let PythonDirArgs { bin } = args;
1512
1513 Self { bin }
1514 }
1515}
1516
1517#[derive(Debug, Clone)]
1519pub struct PythonInstallSettings {
1520 pub install_dir: Option<PathBuf>,
1521 pub targets: Vec<String>,
1522 pub reinstall: bool,
1523 pub force: bool,
1524 pub upgrade: PythonUpgrade,
1525 pub bin: Option<bool>,
1526 pub registry: Option<bool>,
1527 pub install_mirrors: PythonInstallMirrors,
1528 pub default: bool,
1529 pub compile_bytecode: bool,
1530}
1531
1532impl PythonInstallSettings {
1533 pub fn resolve(
1535 args: PythonInstallArgs,
1536 filesystem: Option<FilesystemOptions>,
1537 environment: EnvironmentOptions,
1538 ) -> anyhow::Result<Self> {
1539 let filesystem_install_mirrors = filesystem
1540 .map(|fs| fs.install_mirrors.clone())
1541 .unwrap_or_default();
1542
1543 let install_mirrors = args
1544 .install_mirrors()
1545 .combine(environment.install_mirrors)
1546 .combine(filesystem_install_mirrors);
1547
1548 let PythonInstallArgs {
1549 install_dir,
1550 targets,
1551 reinstall,
1552 bin,
1553 no_bin,
1554 registry,
1555 no_registry,
1556 force,
1557 upgrade,
1558 mirror: _,
1559 pypy_mirror: _,
1560 graalpy_mirror: _,
1561 pyodide_mirror: _,
1562 python_downloads_json_url: _,
1563 default,
1564 compile_bytecode,
1565 } = args;
1566
1567 Ok(Self {
1568 install_dir,
1569 targets,
1570 reinstall,
1571 force,
1572 upgrade: if upgrade {
1573 PythonUpgrade::Enabled(PythonUpgradeSource::Install)
1574 } else {
1575 PythonUpgrade::Disabled
1576 },
1577 bin: flag(bin, no_bin, "bin")?.or(environment.python_install_bin),
1578 registry: match flag(registry, no_registry, "registry")? {
1579 Some(registry) => Some(registry),
1580 None => environment.python_install_registry.or(
1581 if environment.python_no_registry.value == Some(true) {
1582 Some(false)
1583 } else {
1584 None
1585 },
1586 ),
1587 },
1588 install_mirrors,
1589 default,
1590 compile_bytecode: flag(
1591 compile_bytecode.compile_bytecode,
1592 compile_bytecode.no_compile_bytecode,
1593 "compile-bytecode",
1594 )?
1595 .unwrap_or_default(),
1596 })
1597 }
1598}
1599
1600#[expect(clippy::struct_excessive_bools)]
1602#[derive(Debug, Clone)]
1603pub struct PythonUpgradeSettings {
1604 pub install_dir: Option<PathBuf>,
1605 pub targets: Vec<String>,
1606 pub force: bool,
1607 pub registry: Option<bool>,
1608 pub install_mirrors: PythonInstallMirrors,
1609 pub reinstall: bool,
1610 pub default: bool,
1611 pub bin: Option<bool>,
1612 pub compile_bytecode: bool,
1613}
1614
1615impl PythonUpgradeSettings {
1616 pub fn resolve(
1618 args: PythonUpgradeArgs,
1619 filesystem: Option<FilesystemOptions>,
1620 environment: EnvironmentOptions,
1621 ) -> anyhow::Result<Self> {
1622 let filesystem_install_mirrors = filesystem
1623 .map(|fs| fs.install_mirrors.clone())
1624 .unwrap_or_default();
1625
1626 let install_mirrors = args
1627 .install_mirrors()
1628 .combine(environment.install_mirrors)
1629 .combine(filesystem_install_mirrors);
1630
1631 let force = false;
1632 let default = false;
1633 let bin = None;
1634 let registry = environment.python_install_registry.or(
1635 if environment.python_no_registry.value == Some(true) {
1636 Some(false)
1637 } else {
1638 None
1639 },
1640 );
1641
1642 let PythonUpgradeArgs {
1643 install_dir,
1644 targets,
1645 mirror: _,
1646 pypy_mirror: _,
1647 graalpy_mirror: _,
1648 pyodide_mirror: _,
1649 reinstall,
1650 python_downloads_json_url: _,
1651 compile_bytecode,
1652 } = args;
1653
1654 Ok(Self {
1655 install_dir,
1656 targets,
1657 force,
1658 registry,
1659 install_mirrors,
1660 reinstall,
1661 default,
1662 bin,
1663 compile_bytecode: flag(
1664 compile_bytecode.compile_bytecode,
1665 compile_bytecode.no_compile_bytecode,
1666 "compile-bytecode",
1667 )?
1668 .unwrap_or_default(),
1669 })
1670 }
1671}
1672
1673#[derive(Debug, Clone)]
1675pub struct PythonUninstallSettings {
1676 pub install_dir: Option<PathBuf>,
1677 pub targets: Vec<String>,
1678 pub all: bool,
1679}
1680
1681impl PythonUninstallSettings {
1682 pub fn resolve(args: PythonUninstallArgs, _filesystem: Option<FilesystemOptions>) -> Self {
1684 let PythonUninstallArgs {
1685 install_dir,
1686 targets,
1687 all,
1688 } = args;
1689
1690 Self {
1691 install_dir,
1692 targets,
1693 all,
1694 }
1695 }
1696}
1697
1698#[derive(Debug, Clone)]
1700pub struct PythonFindSettings {
1701 pub request: Option<String>,
1702 pub show_version: bool,
1703 pub resolve_links: bool,
1704 pub no_project: bool,
1705 pub system: bool,
1706 pub python_downloads_json_url: Option<String>,
1707}
1708
1709impl PythonFindSettings {
1710 pub fn resolve(
1712 args: PythonFindArgs,
1713 filesystem: Option<FilesystemOptions>,
1714 environment: EnvironmentOptions,
1715 ) -> anyhow::Result<Self> {
1716 let PythonFindArgs {
1717 request,
1718 show_version,
1719 resolve_links,
1720 no_project,
1721 system,
1722 no_system,
1723 script: _,
1724 python_downloads_json_url,
1725 } = args;
1726
1727 let filesystem_install_mirrors = filesystem
1728 .map(|fs| fs.install_mirrors.clone())
1729 .unwrap_or_default();
1730
1731 let install_mirrors = PythonInstallMirrors {
1732 python_downloads_json_url,
1733 ..Default::default()
1734 }
1735 .combine(environment.install_mirrors)
1736 .combine(filesystem_install_mirrors);
1737
1738 let PythonInstallMirrors {
1739 python_install_mirror: _,
1740 pypy_install_mirror: _,
1741 graalpy_install_mirror: _,
1742 pyodide_install_mirror: _,
1743 python_downloads_json_url,
1744 } = install_mirrors;
1745
1746 Ok(Self {
1747 request,
1748 show_version,
1749 resolve_links,
1750 no_project,
1751 system: flag(system, no_system, "system")?.unwrap_or_default(),
1752 python_downloads_json_url,
1753 })
1754 }
1755}
1756
1757#[derive(Debug, Clone)]
1759pub struct PythonPinSettings {
1760 pub request: Option<String>,
1761 pub resolved: bool,
1762 pub no_project: bool,
1763 pub global: bool,
1764 pub rm: bool,
1765 pub install_mirrors: PythonInstallMirrors,
1766}
1767
1768impl PythonPinSettings {
1769 pub fn resolve(
1771 args: PythonPinArgs,
1772 filesystem: Option<FilesystemOptions>,
1773 environment: EnvironmentOptions,
1774 ) -> anyhow::Result<Self> {
1775 let PythonPinArgs {
1776 request,
1777 no_resolved,
1778 resolved,
1779 no_project,
1780 global,
1781 rm,
1782 python_downloads_json_url,
1783 } = args;
1784
1785 let filesystem_install_mirrors = filesystem
1786 .map(|fs| fs.install_mirrors.clone())
1787 .unwrap_or_default();
1788
1789 let install_mirrors = PythonInstallMirrors {
1790 python_downloads_json_url,
1791 ..Default::default()
1792 }
1793 .combine(environment.install_mirrors)
1794 .combine(filesystem_install_mirrors);
1795
1796 Ok(Self {
1797 request,
1798 resolved: flag(resolved, no_resolved, "resolved")?.unwrap_or(false),
1799 no_project,
1800 global,
1801 rm,
1802 install_mirrors,
1803 })
1804 }
1805}
1806
1807#[derive(Debug, Clone)]
1809pub struct SyncSettings {
1810 pub lock_check: LockCheck,
1811 pub frozen: Option<FrozenSource>,
1812 pub dry_run: DryRun,
1813 pub script: Option<PathBuf>,
1814 pub active: ActiveEnvironment,
1815 pub extras: ExtrasSpecification,
1816 pub groups: DependencyGroups,
1817 pub editable: Option<EditableMode>,
1818 pub install_options: InstallOptions,
1819 pub modifications: Modifications,
1820 pub all_packages: bool,
1821 pub package: Vec<PackageName>,
1822 pub python: Option<String>,
1823 pub python_platform: Option<TargetTriple>,
1824 pub install_mirrors: PythonInstallMirrors,
1825 pub refresh: Refresh,
1826 pub settings: ResolverInstallerSettings,
1827 pub output_format: SyncFormat,
1828 pub malware_settings: MalwareCheckSettings,
1829}
1830
1831impl SyncSettings {
1832 pub fn resolve(
1834 args: SyncArgs,
1835 filesystem: Option<FilesystemOptions>,
1836 environment: EnvironmentOptions,
1837 ) -> anyhow::Result<Self> {
1838 let SyncArgs {
1839 extra,
1840 all_extras,
1841 no_extra,
1842 no_all_extras,
1843 dependency_groups:
1844 ProjectDependencyGroupsArgs {
1845 dev,
1846 no_dev,
1847 only_dev,
1848 group,
1849 no_group,
1850 no_default_groups,
1851 only_group,
1852 all_groups,
1853 },
1854 editable,
1855 no_editable,
1856 no_editable_package,
1857 inexact,
1858 exact,
1859 no_install_project,
1860 only_install_project,
1861 no_install_workspace,
1862 only_install_workspace,
1863 no_install_local,
1864 only_install_local,
1865 no_install_package,
1866 only_install_package,
1867 locked,
1868 no_locked,
1869 frozen,
1870 no_frozen,
1871 active,
1872 no_active,
1873 dry_run,
1874 installer,
1875 build,
1876 refresh,
1877 all_packages,
1878 package,
1879 script,
1880 python,
1881 python_platform,
1882 check,
1883 no_check,
1884 output_format,
1885 } = args;
1886 let filesystem_install_mirrors = filesystem
1887 .as_ref()
1888 .map(|fs| fs.install_mirrors.clone())
1889 .unwrap_or_default();
1890
1891 let malware_settings = MalwareCheckSettings::resolve(filesystem.as_ref(), &environment);
1892 let settings =
1893 resolve_resolver_installer_settings(installer, build, filesystem, &environment)?;
1894
1895 let check = flag(check, no_check, "check")?.unwrap_or_default();
1896 let dry_run = if check {
1897 DryRun::Check
1898 } else {
1899 DryRun::from_args(dry_run)
1900 };
1901
1902 let locked = resolve_lock_check(locked, no_locked, LockedFlag::Locked, environment.locked);
1904 let frozen = resolve_frozen(frozen, no_frozen, FrozenFlag::Frozen, environment.frozen);
1905
1906 let (locked, frozen) = resolve_lock_flags(locked, frozen)?;
1907
1908 let (dev, no_dev) = resolve_flag_pair(
1909 dev,
1910 no_dev,
1911 "dev",
1912 "no-dev",
1913 Some(environment.dev),
1914 Some(environment.no_dev),
1915 );
1916 let (editable, no_editable) = resolve_flag_pair(
1917 editable,
1918 no_editable,
1919 "editable",
1920 "no-editable",
1921 None,
1922 Some(environment.no_editable),
1923 );
1924
1925 let (no_install_project, only_install_project) = resolve_flag_pair(
1926 no_install_project,
1927 only_install_project,
1928 "no-install-project",
1929 "only-install-project",
1930 Some(environment.no_install_project),
1931 Some(environment.only_install_project),
1932 );
1933 let (no_install_workspace, only_install_workspace) = resolve_flag_pair(
1934 no_install_workspace,
1935 only_install_workspace,
1936 "no-install-workspace",
1937 "only-install-workspace",
1938 Some(environment.no_install_workspace),
1939 Some(environment.only_install_workspace),
1940 );
1941 let (no_install_local, only_install_local) = resolve_flag_pair(
1942 no_install_local,
1943 only_install_local,
1944 "no-install-local",
1945 "only-install-local",
1946 Some(environment.no_install_local),
1947 Some(environment.only_install_local),
1948 );
1949 check_conflicts(no_install_project, only_install_project)?;
1950 check_conflicts(no_install_workspace, only_install_workspace)?;
1951 check_conflicts(no_install_local, only_install_local)?;
1952 if script.is_some() {
1953 let script = Flag::from_cli("script");
1954 check_conflicts(no_install_project, script)?;
1955 check_conflicts(no_install_workspace, script)?;
1956 check_conflicts(no_install_local, script)?;
1957 }
1958 let no_install_project = no_install_project.is_enabled();
1959 let only_install_project = only_install_project.is_enabled();
1960 let no_install_workspace = no_install_workspace.is_enabled();
1961 let only_install_workspace = only_install_workspace.is_enabled();
1962 let no_install_local = no_install_local.is_enabled();
1963 let only_install_local = only_install_local.is_enabled();
1964
1965 Ok(Self {
1966 output_format,
1967 lock_check: locked,
1968 frozen,
1969 dry_run,
1970 script,
1971 active: flag(active, no_active, "active")?.into(),
1972 extras: ExtrasSpecification::from_args(
1973 extra.unwrap_or_default(),
1974 no_extra,
1975 false,
1977 vec![],
1979 flag(all_extras, no_all_extras, "all-extras")?.unwrap_or_default(),
1980 ),
1981 groups: DependencyGroups::from_args(
1982 DevMode::from_args(dev.into(), no_dev.into(), only_dev),
1983 group,
1984 if no_group.is_empty() {
1985 environment.no_group.clone().unwrap_or_default()
1986 } else {
1987 no_group
1988 },
1989 no_default_groups,
1990 only_group,
1991 all_groups,
1992 ),
1993 editable: EditableMode::from_args(
1994 flag(editable.into(), no_editable.into(), "editable")?,
1995 no_editable_package,
1996 ),
1997 install_options: InstallOptions::new(
1998 no_install_project,
1999 only_install_project,
2000 no_install_workspace,
2001 only_install_workspace,
2002 no_install_local,
2003 only_install_local,
2004 no_install_package,
2005 only_install_package,
2006 ),
2007 modifications: if flag(exact, inexact, "inexact")?.unwrap_or(true) {
2008 Modifications::Exact
2009 } else {
2010 Modifications::Sufficient
2011 },
2012 all_packages,
2013 package,
2014 python: python.and_then(Maybe::into_option),
2015 python_platform,
2016 refresh: Refresh::try_from(refresh)?,
2017 settings,
2018 install_mirrors: environment
2019 .install_mirrors
2020 .combine(filesystem_install_mirrors),
2021 malware_settings,
2022 })
2023 }
2024}
2025
2026#[derive(Debug, Clone)]
2028pub struct LockSettings {
2029 pub lock_check: LockCheck,
2030 pub frozen: Option<FrozenSource>,
2031 pub dry_run: DryRun,
2032 pub script: Option<PathBuf>,
2033 pub python: Option<String>,
2034 pub install_mirrors: PythonInstallMirrors,
2035 pub refresh: Refresh,
2036 pub settings: ResolverSettings,
2037}
2038
2039impl LockSettings {
2040 pub fn resolve(
2042 args: LockArgs,
2043 filesystem: Option<FilesystemOptions>,
2044 environment: EnvironmentOptions,
2045 ) -> anyhow::Result<Self> {
2046 let LockArgs {
2047 check,
2048 locked,
2049 no_locked,
2050 check_exists,
2051 frozen,
2052 no_frozen,
2053 dry_run,
2054 script,
2055 resolver,
2056 build,
2057 refresh,
2058 python,
2059 } = args;
2060
2061 let filesystem_install_mirrors = filesystem
2062 .as_ref()
2063 .map(|fs| fs.install_mirrors.clone())
2064 .unwrap_or_default();
2065
2066 let locked = resolve_lock_check(
2068 locked || check,
2069 no_locked,
2070 if check {
2071 LockedFlag::Check
2072 } else {
2073 LockedFlag::Locked
2074 },
2075 environment.locked,
2076 );
2077 let frozen = resolve_frozen(
2078 frozen || check_exists,
2079 no_frozen,
2080 if check_exists {
2081 FrozenFlag::CheckExists
2082 } else {
2083 FrozenFlag::Frozen
2084 },
2085 environment.frozen,
2086 );
2087
2088 let (locked, frozen) = resolve_lock_flags(locked, frozen)?;
2089
2090 Ok(Self {
2091 lock_check: locked,
2092 frozen,
2093 dry_run: DryRun::from_args(dry_run),
2094 script,
2095 python: python.and_then(Maybe::into_option),
2096 refresh: Refresh::try_from(refresh)?,
2097 settings: resolve_resolver_settings(resolver, build, filesystem, &environment)?,
2098 install_mirrors: environment
2099 .install_mirrors
2100 .combine(filesystem_install_mirrors),
2101 })
2102 }
2103}
2104
2105#[derive(Debug, Clone)]
2107pub struct UpgradeSettings {
2108 pub packages: Vec<PackageName>,
2109 pub exclude: Vec<PackageName>,
2110 pub install_mirrors: PythonInstallMirrors,
2111 pub settings: ResolverSettings,
2112}
2113
2114impl UpgradeSettings {
2115 pub fn resolve(
2117 args: UpgradeArgs,
2118 filesystem: Option<FilesystemOptions>,
2119 environment: EnvironmentOptions,
2120 ) -> anyhow::Result<Self> {
2121 let filesystem_install_mirrors = filesystem
2122 .as_ref()
2123 .map(|fs| fs.install_mirrors.clone())
2124 .unwrap_or_default();
2125 let (packages, exclude, options) =
2126 upgrade_options(args, configured_indexes(filesystem.as_ref()))?;
2127 let mut settings = combine_resolver_settings(options, filesystem, &environment);
2128 settings.upgrade = if packages.is_empty() {
2129 Upgrade::default()
2130 } else {
2131 Upgrade::from_packages(packages.clone())
2132 };
2133
2134 Ok(Self {
2135 packages,
2136 exclude,
2137 install_mirrors: environment
2138 .install_mirrors
2139 .combine(filesystem_install_mirrors),
2140 settings,
2141 })
2142 }
2143}
2144
2145#[derive(Debug, Clone)]
2147pub struct MetadataSettings {
2148 #[expect(dead_code)]
2149 script: Option<PathBuf>,
2150 pub lock_check: LockCheck,
2151 pub frozen: Option<FrozenSource>,
2152 pub sync: Option<Modifications>,
2153 pub active: ActiveEnvironment,
2154 pub python: Option<String>,
2155 pub install_mirrors: PythonInstallMirrors,
2156 pub refresh: Refresh,
2157 pub settings: ResolverSettings,
2158 pub malware_settings: MalwareCheckSettings,
2159}
2160
2161impl MetadataSettings {
2162 pub fn resolve(
2164 args: Box<MetadataArgs>,
2165 filesystem: Option<FilesystemOptions>,
2166 environment: EnvironmentOptions,
2167 ) -> anyhow::Result<Self> {
2168 let MetadataArgs {
2169 script,
2170 locked,
2171 no_locked,
2172 frozen,
2173 no_frozen,
2174 resolver,
2175 build,
2176 refresh,
2177 sync,
2178 exact,
2179 active,
2180 python,
2181 } = *args;
2182
2183 let filesystem_install_mirrors = filesystem
2184 .as_ref()
2185 .map(|fs| fs.install_mirrors.clone())
2186 .unwrap_or_default();
2187
2188 let locked = resolve_lock_check(locked, no_locked, LockedFlag::Locked, environment.locked);
2190 let frozen = resolve_frozen(frozen, no_frozen, FrozenFlag::Frozen, environment.frozen);
2191
2192 let (locked, frozen) = resolve_lock_flags(locked, frozen)?;
2193
2194 let malware_settings = MalwareCheckSettings::resolve(filesystem.as_ref(), &environment);
2195
2196 Ok(Self {
2197 script,
2198 lock_check: locked,
2199 frozen,
2200 sync: sync.then_some(if exact {
2201 Modifications::Exact
2202 } else {
2203 Modifications::Sufficient
2204 }),
2205 active: Some(active).into(),
2206 python: python.and_then(Maybe::into_option),
2207 refresh: Refresh::try_from(refresh)?,
2208 settings: resolve_resolver_settings(resolver, build, filesystem, &environment)?,
2209 install_mirrors: environment
2210 .install_mirrors
2211 .combine(filesystem_install_mirrors),
2212 malware_settings,
2213 })
2214 }
2215}
2216
2217#[expect(clippy::struct_excessive_bools)]
2219#[derive(Debug, Clone)]
2220pub struct AddSettings {
2221 pub lock_check: LockCheck,
2222 pub frozen: Option<FrozenSource>,
2223 pub active: ActiveEnvironment,
2224 pub no_sync: bool,
2225 pub packages: Vec<String>,
2226 pub requirements: Vec<RequirementsInput>,
2227 pub constraints: Vec<RequirementsInput>,
2228 pub marker: Option<MarkerTree>,
2229 pub dependency_type: DependencyType,
2230 pub editable: Option<EditableMode>,
2231 pub extras: Vec<ExtraName>,
2232 pub raw: bool,
2233 pub bounds: Option<AddBoundsKind>,
2234 pub rev: Option<String>,
2235 pub tag: Option<String>,
2236 pub branch: Option<String>,
2237 pub lfs: GitLfsSetting,
2238 pub package: Option<PackageName>,
2239 pub script: Option<PathBuf>,
2240 pub python: Option<String>,
2241 pub workspace: Option<bool>,
2242 pub no_install_project: bool,
2243 pub only_install_project: bool,
2244 pub no_install_workspace: bool,
2245 pub only_install_workspace: bool,
2246 pub no_install_local: bool,
2247 pub only_install_local: bool,
2248 pub no_install_package: Vec<PackageName>,
2249 pub only_install_package: Vec<PackageName>,
2250 pub install_mirrors: PythonInstallMirrors,
2251 pub refresh: Refresh,
2252 pub indexes: Vec<Index>,
2253 pub settings: ResolverInstallerSettings,
2254 pub malware_settings: MalwareCheckSettings,
2255}
2256
2257impl AddSettings {
2258 pub fn resolve(
2260 args: AddArgs,
2261 filesystem: Option<FilesystemOptions>,
2262 environment: EnvironmentOptions,
2263 ) -> anyhow::Result<Self> {
2264 let AddArgs {
2265 packages,
2266 requirements,
2267 constraints,
2268 marker,
2269 dev,
2270 optional,
2271 group,
2272 editable,
2273 no_editable,
2274 no_editable_package,
2275 extra,
2276 raw,
2277 bounds,
2278 rev,
2279 tag,
2280 branch,
2281 lfs,
2282 no_sync,
2283 locked,
2284 no_locked,
2285 frozen,
2286 no_frozen,
2287 active,
2288 no_active,
2289 installer,
2290 build,
2291 refresh,
2292 package,
2293 script,
2294 python,
2295 workspace,
2296 no_workspace,
2297 no_install_project,
2298 only_install_project,
2299 no_install_workspace,
2300 only_install_workspace,
2301 no_install_local,
2302 only_install_local,
2303 no_install_package,
2304 only_install_package,
2305 } = args;
2306
2307 let dev = dev || environment.dev.value == Some(true);
2309 let (editable, no_editable) = resolve_flag_pair(
2310 editable,
2311 no_editable,
2312 "editable",
2313 "no-editable",
2314 None,
2315 Some(environment.no_editable),
2316 );
2317
2318 let (no_install_project, only_install_project) = resolve_flag_pair(
2319 no_install_project,
2320 only_install_project,
2321 "no-install-project",
2322 "only-install-project",
2323 Some(environment.no_install_project),
2324 Some(environment.only_install_project),
2325 );
2326 let (no_install_workspace, only_install_workspace) = resolve_flag_pair(
2327 no_install_workspace,
2328 only_install_workspace,
2329 "no-install-workspace",
2330 "only-install-workspace",
2331 Some(environment.no_install_workspace),
2332 Some(environment.only_install_workspace),
2333 );
2334 let (no_install_local, only_install_local) = resolve_flag_pair(
2335 no_install_local,
2336 only_install_local,
2337 "no-install-local",
2338 "only-install-local",
2339 Some(environment.no_install_local),
2340 Some(environment.only_install_local),
2341 );
2342 check_conflicts(no_install_project, only_install_project)?;
2343 check_conflicts(no_install_workspace, only_install_workspace)?;
2344 check_conflicts(no_install_local, only_install_local)?;
2345
2346 let dependency_type = if let Some(extra) = optional {
2347 DependencyType::Optional(extra)
2348 } else if let Some(group) = group {
2349 DependencyType::Group(group)
2350 } else if dev {
2351 DependencyType::Dev
2352 } else {
2353 DependencyType::Production
2354 };
2355
2356 if installer
2358 .index_args
2359 .index_url
2360 .as_ref()
2361 .is_some_and(Maybe::is_some)
2362 {
2363 if script.is_some() {
2364 warn_user_once!(
2365 "Indexes specified via `--index-url` will not be persisted to the script; use `--default-index` instead."
2366 );
2367 } else {
2368 warn_user_once!(
2369 "Indexes specified via `--index-url` will not be persisted to the `pyproject.toml` file; use `--default-index` instead."
2370 );
2371 }
2372 }
2373
2374 if installer
2375 .index_args
2376 .extra_index_url
2377 .as_ref()
2378 .is_some_and(|extra_index_url| extra_index_url.iter().any(Maybe::is_some))
2379 {
2380 if script.is_some() {
2381 warn_user_once!(
2382 "Indexes specified via `--extra-index-url` will not be persisted to the script; use `--index` instead."
2383 );
2384 } else {
2385 warn_user_once!(
2386 "Indexes specified via `--extra-index-url` will not be persisted to the `pyproject.toml` file; use `--index` instead."
2387 );
2388 }
2389 }
2390
2391 let filesystem_install_mirrors = filesystem
2392 .as_ref()
2393 .map(|fs| fs.install_mirrors.clone())
2394 .unwrap_or_default();
2395
2396 let bounds = bounds.or(filesystem.as_ref().and_then(|fs| fs.add.add_bounds));
2397 let lfs = GitLfsSetting::new(lfs.then_some(true), environment.lfs);
2398
2399 let locked = resolve_lock_check(locked, no_locked, LockedFlag::Locked, environment.locked);
2401 let frozen = resolve_frozen(frozen, no_frozen, FrozenFlag::Frozen, environment.frozen);
2402 let no_sync = resolve_flag(no_sync, "no-sync", environment.no_sync);
2403
2404 let (locked, frozen) = resolve_lock_flags(locked, frozen)?;
2405
2406 check_conflicts(no_sync, frozen.map_or(Flag::Disabled, Flag::from))?;
2408
2409 let no_install_package_flag = if no_install_package.is_empty() {
2410 Flag::disabled()
2411 } else {
2412 Flag::from_cli("no-install-package")
2413 };
2414 let only_install_package_flag = if only_install_package.is_empty() {
2415 Flag::disabled()
2416 } else {
2417 Flag::from_cli("only-install-package")
2418 };
2419
2420 for install_flag in [
2421 no_install_project,
2422 no_install_workspace,
2423 no_install_local,
2424 only_install_project,
2425 only_install_workspace,
2426 only_install_local,
2427 no_install_package_flag,
2428 only_install_package_flag,
2429 ] {
2430 check_conflicts(install_flag, frozen.map_or(Flag::Disabled, Flag::from))?;
2431 check_conflicts(install_flag, no_sync)?;
2432 }
2433
2434 let no_install_project = no_install_project.is_enabled();
2435 let only_install_project = only_install_project.is_enabled();
2436 let no_install_workspace = no_install_workspace.is_enabled();
2437 let only_install_workspace = only_install_workspace.is_enabled();
2438 let no_install_local = no_install_local.is_enabled();
2439 let only_install_local = only_install_local.is_enabled();
2440
2441 let malware_settings = MalwareCheckSettings::resolve(filesystem.as_ref(), &environment);
2442 let active = flag(active, no_active, "active")?.into();
2443 let workspace = flag(workspace, no_workspace, "workspace")?;
2444 let editable = EditableMode::from_args(
2445 flag(editable.into(), no_editable.into(), "editable")?,
2446 no_editable_package,
2447 );
2448 let refresh = Refresh::try_from(refresh)?;
2449 let options =
2450 resolver_installer_options(installer, build, configured_indexes(filesystem.as_ref()))?;
2451 let indexes = options.indexes.index.clone().unwrap_or_default();
2452
2453 Ok(Self {
2454 lock_check: locked,
2455 frozen,
2456 active,
2457 no_sync: no_sync.is_enabled(),
2458 packages,
2459 requirements,
2460 constraints: constraints
2461 .into_iter()
2462 .filter_map(Maybe::into_option)
2463 .collect(),
2464 marker,
2465 dependency_type,
2466 raw,
2467 bounds,
2468 rev,
2469 tag,
2470 branch,
2471 lfs,
2472 package,
2473 script,
2474 python: python.and_then(Maybe::into_option),
2475 workspace,
2476 no_install_project,
2477 only_install_project,
2478 no_install_workspace,
2479 only_install_workspace,
2480 no_install_local,
2481 only_install_local,
2482 no_install_package,
2483 only_install_package,
2484 editable,
2485 extras: extra.unwrap_or_default(),
2486 refresh,
2487 indexes,
2488 settings: combine_resolver_installer_settings(options, filesystem, &environment),
2489 install_mirrors: environment
2490 .install_mirrors
2491 .combine(filesystem_install_mirrors),
2492 malware_settings,
2493 })
2494 }
2495}
2496
2497#[derive(Debug, Clone)]
2499pub struct RemoveSettings {
2500 pub lock_check: LockCheck,
2501 pub frozen: Option<FrozenSource>,
2502 pub active: ActiveEnvironment,
2503 pub no_sync: bool,
2504 pub packages: Vec<PackageName>,
2505 pub dependency_type: DependencyType,
2506 pub package: Option<PackageName>,
2507 pub script: Option<PathBuf>,
2508 pub python: Option<String>,
2509 pub install_mirrors: PythonInstallMirrors,
2510 pub refresh: Refresh,
2511 pub settings: ResolverInstallerSettings,
2512 pub malware_settings: MalwareCheckSettings,
2513}
2514
2515impl RemoveSettings {
2516 pub fn resolve(
2518 args: RemoveArgs,
2519 filesystem: Option<FilesystemOptions>,
2520 environment: EnvironmentOptions,
2521 ) -> anyhow::Result<Self> {
2522 let RemoveArgs {
2523 dev,
2524 optional,
2525 packages,
2526 group,
2527 no_sync,
2528 locked,
2529 no_locked,
2530 frozen,
2531 no_frozen,
2532 active,
2533 no_active,
2534 installer,
2535 build,
2536 refresh,
2537 package,
2538 script,
2539 python,
2540 } = args;
2541
2542 let dev = dev || environment.dev.value == Some(true);
2544
2545 let dependency_type = if let Some(extra) = optional {
2546 DependencyType::Optional(extra)
2547 } else if let Some(group) = group {
2548 DependencyType::Group(group)
2549 } else if dev {
2550 DependencyType::Dev
2551 } else {
2552 DependencyType::Production
2553 };
2554
2555 let filesystem_install_mirrors = filesystem
2556 .as_ref()
2557 .map(|fs| fs.install_mirrors.clone())
2558 .unwrap_or_default();
2559
2560 let packages = packages
2561 .into_iter()
2562 .map(|requirement| requirement.name)
2563 .collect();
2564
2565 let locked = resolve_lock_check(locked, no_locked, LockedFlag::Locked, environment.locked);
2567 let frozen = resolve_frozen(frozen, no_frozen, FrozenFlag::Frozen, environment.frozen);
2568 let no_sync = resolve_flag(no_sync, "no-sync", environment.no_sync);
2569
2570 let (locked, frozen) = resolve_lock_flags(locked, frozen)?;
2571
2572 check_conflicts(no_sync, frozen.map_or(Flag::Disabled, Flag::from))?;
2574
2575 let malware_settings = MalwareCheckSettings::resolve(filesystem.as_ref(), &environment);
2576
2577 Ok(Self {
2578 lock_check: locked,
2579 frozen,
2580 active: flag(active, no_active, "active")?.into(),
2581 no_sync: no_sync.is_enabled(),
2582 packages,
2583 dependency_type,
2584 package,
2585 script,
2586 python: python.and_then(Maybe::into_option),
2587 refresh: Refresh::try_from(refresh)?,
2588 settings: resolve_resolver_installer_settings(
2589 installer,
2590 build,
2591 filesystem,
2592 &environment,
2593 )?,
2594 install_mirrors: environment
2595 .install_mirrors
2596 .combine(filesystem_install_mirrors),
2597 malware_settings,
2598 })
2599 }
2600}
2601
2602#[derive(Debug, Clone)]
2604pub struct VersionSettings {
2605 pub value: Option<String>,
2606 pub bump: Vec<VersionBumpSpec>,
2607 pub short: bool,
2608 pub output_format: VersionFormat,
2609 pub dry_run: bool,
2610 pub lock_check: LockCheck,
2611 pub frozen: Option<FrozenSource>,
2612 pub active: ActiveEnvironment,
2613 pub no_sync: bool,
2614 pub package: Option<PackageName>,
2615 pub python: Option<String>,
2616 pub install_mirrors: PythonInstallMirrors,
2617 pub refresh: Refresh,
2618 pub settings: ResolverInstallerSettings,
2619 pub malware_settings: MalwareCheckSettings,
2620}
2621
2622impl VersionSettings {
2623 pub fn resolve(
2625 args: VersionArgs,
2626 filesystem: Option<FilesystemOptions>,
2627 environment: EnvironmentOptions,
2628 ) -> anyhow::Result<Self> {
2629 let VersionArgs {
2630 value,
2631 bump,
2632 short,
2633 output_format,
2634 dry_run,
2635 no_sync,
2636 locked,
2637 no_locked,
2638 frozen,
2639 no_frozen,
2640 active,
2641 no_active,
2642 installer,
2643 build,
2644 refresh,
2645 package,
2646 python,
2647 } = args;
2648
2649 let filesystem_install_mirrors = filesystem
2650 .as_ref()
2651 .map(|fs| fs.install_mirrors.clone())
2652 .unwrap_or_default();
2653
2654 let locked = resolve_lock_check(locked, no_locked, LockedFlag::Locked, environment.locked);
2656 let frozen = resolve_frozen(frozen, no_frozen, FrozenFlag::Frozen, environment.frozen);
2657 let no_sync = resolve_flag(no_sync, "no-sync", environment.no_sync);
2658
2659 let (locked, frozen) = resolve_lock_flags(locked, frozen)?;
2660
2661 check_conflicts(no_sync, frozen.map_or(Flag::Disabled, Flag::from))?;
2663
2664 let malware_settings = MalwareCheckSettings::resolve(filesystem.as_ref(), &environment);
2665
2666 Ok(Self {
2667 value,
2668 bump,
2669 short,
2670 output_format,
2671 dry_run,
2672 lock_check: locked,
2673 frozen,
2674 active: flag(active, no_active, "active")?.into(),
2675 no_sync: no_sync.is_enabled(),
2676 package,
2677 python: python.and_then(Maybe::into_option),
2678 refresh: Refresh::try_from(refresh)?,
2679 settings: resolve_resolver_installer_settings(
2680 installer,
2681 build,
2682 filesystem,
2683 &environment,
2684 )?,
2685 install_mirrors: environment
2686 .install_mirrors
2687 .combine(filesystem_install_mirrors),
2688 malware_settings,
2689 })
2690 }
2691}
2692
2693#[derive(Debug, Clone)]
2695pub struct TreeSettings {
2696 pub groups: DependencyGroups,
2697 pub lock_check: LockCheck,
2698 pub frozen: Option<FrozenSource>,
2699 pub universal: bool,
2700 pub format: TreeFormat,
2701 pub depth: u8,
2702 pub prune: Vec<PackageName>,
2703 pub package: Vec<PackageName>,
2704 pub no_dedupe: bool,
2705 pub invert: bool,
2706 pub outdated: bool,
2707 pub show_sizes: bool,
2708 pub script: Option<PathBuf>,
2709 pub python_version: Option<PythonVersion>,
2710 pub python_platform: Option<TargetTriple>,
2711 pub python: Option<String>,
2712 pub install_mirrors: PythonInstallMirrors,
2713 pub resolver: ResolverSettings,
2714}
2715
2716impl TreeSettings {
2717 pub fn resolve(
2719 args: TreeArgs,
2720 filesystem: Option<FilesystemOptions>,
2721 environment: EnvironmentOptions,
2722 ) -> anyhow::Result<Self> {
2723 let TreeArgs {
2724 tree,
2725 universal,
2726 format,
2727 dependency_groups:
2728 ProjectDependencyGroupsArgs {
2729 dev,
2730 no_dev,
2731 only_dev,
2732 group,
2733 no_group,
2734 no_default_groups,
2735 only_group,
2736 all_groups,
2737 },
2738 locked,
2739 no_locked,
2740 frozen,
2741 no_frozen,
2742 build,
2743 resolver,
2744 script,
2745 python_version,
2746 python_platform,
2747 python,
2748 } = args;
2749
2750 let filesystem_install_mirrors = filesystem
2751 .as_ref()
2752 .map(|fs| fs.install_mirrors.clone())
2753 .unwrap_or_default();
2754
2755 let locked = resolve_lock_check(locked, no_locked, LockedFlag::Locked, environment.locked);
2757 let frozen = resolve_frozen(frozen, no_frozen, FrozenFlag::Frozen, environment.frozen);
2758
2759 let (locked, frozen) = resolve_lock_flags(locked, frozen)?;
2760
2761 let (dev, no_dev) = resolve_flag_pair(
2762 dev,
2763 no_dev,
2764 "dev",
2765 "no-dev",
2766 Some(environment.dev),
2767 Some(environment.no_dev),
2768 );
2769
2770 Ok(Self {
2771 groups: DependencyGroups::from_args(
2772 DevMode::from_args(dev.into(), no_dev.into(), only_dev),
2773 group,
2774 if no_group.is_empty() {
2775 environment.no_group.clone().unwrap_or_default()
2776 } else {
2777 no_group
2778 },
2779 no_default_groups,
2780 only_group,
2781 all_groups,
2782 ),
2783 lock_check: locked,
2784 frozen,
2785 universal,
2786 format,
2787 depth: tree.depth,
2788 prune: tree.prune,
2789 package: tree.package,
2790 no_dedupe: tree.no_dedupe,
2791 invert: tree.invert,
2792 outdated: tree.outdated,
2793 show_sizes: tree.show_sizes,
2794 script,
2795 python_version,
2796 python_platform,
2797 python: python.and_then(Maybe::into_option),
2798 resolver: resolve_resolver_settings(resolver, build, filesystem, &environment)?,
2799 install_mirrors: environment
2800 .install_mirrors
2801 .combine(filesystem_install_mirrors),
2802 })
2803 }
2804}
2805
2806#[expect(clippy::struct_excessive_bools)]
2808#[derive(Debug, Clone)]
2809pub struct ExportSettings {
2810 pub format: Option<ExportFormat>,
2811 pub all_packages: bool,
2812 pub package: Vec<PackageName>,
2813 pub prune: Vec<PackageName>,
2814 pub extras: ExtrasSpecification,
2815 pub groups: DependencyGroups,
2816 pub editable: Option<EditableMode>,
2817 pub hashes: bool,
2818 pub install_options: InstallOptions,
2819 pub batch: Option<PathBuf>,
2820 pub output_file: Option<PathBuf>,
2821 pub lock_check: LockCheck,
2822 pub frozen: Option<FrozenSource>,
2823 pub include_annotations: bool,
2824 pub include_header: bool,
2825 pub include_index_url: bool,
2826 pub include_find_links: bool,
2827 pub script: Option<PathBuf>,
2828 pub python: Option<String>,
2829 pub install_mirrors: PythonInstallMirrors,
2830 pub refresh: Refresh,
2831 pub settings: ResolverSettings,
2832}
2833
2834impl ExportSettings {
2835 pub fn resolve(
2837 args: ExportArgs,
2838 filesystem: Option<FilesystemOptions>,
2839 environment: EnvironmentOptions,
2840 ) -> anyhow::Result<Self> {
2841 let ExportArgs {
2842 format,
2843 all_packages,
2844 package,
2845 prune,
2846 extra,
2847 all_extras,
2848 no_extra,
2849 no_all_extras,
2850 dependency_groups:
2851 ProjectDependencyGroupsArgs {
2852 dev,
2853 no_dev,
2854 only_dev,
2855 group,
2856 no_group,
2857 no_default_groups,
2858 only_group,
2859 all_groups,
2860 },
2861 annotate,
2862 no_annotate,
2863 header,
2864 no_header,
2865 emit_index_url,
2866 no_emit_index_url,
2867 emit_find_links,
2868 no_emit_find_links,
2869 editable,
2870 no_editable,
2871 no_editable_package,
2872 hashes,
2873 no_hashes,
2874 batch,
2875 output_file,
2876 no_emit_project,
2877 only_emit_project,
2878 no_emit_workspace,
2879 only_emit_workspace,
2880 no_emit_local,
2881 only_emit_local,
2882 no_emit_package,
2883 only_emit_package,
2884 locked,
2885 no_locked,
2886 frozen: frozen_cli,
2887 no_frozen,
2888 resolver,
2889 build,
2890 refresh,
2891 script,
2892 python,
2893 } = args;
2894 let filesystem_install_mirrors = filesystem
2895 .as_ref()
2896 .map(|fs| fs.install_mirrors.clone())
2897 .unwrap_or_default();
2898
2899 let locked = resolve_lock_check(locked, no_locked, LockedFlag::Locked, environment.locked);
2901 let frozen = resolve_frozen(
2902 frozen_cli,
2903 no_frozen,
2904 FrozenFlag::Frozen,
2905 environment.frozen,
2906 );
2907
2908 let (locked, frozen) = resolve_lock_flags(locked, frozen)?;
2909
2910 let (dev, no_dev) = resolve_flag_pair(
2911 dev,
2912 no_dev,
2913 "dev",
2914 "no-dev",
2915 Some(environment.dev),
2916 Some(environment.no_dev),
2917 );
2918 let (editable, no_editable) = resolve_flag_pair(
2919 editable,
2920 no_editable,
2921 "editable",
2922 "no-editable",
2923 None,
2924 Some(environment.no_editable),
2925 );
2926
2927 Ok(Self {
2928 format,
2929 all_packages,
2930 package,
2931 prune,
2932 extras: ExtrasSpecification::from_args(
2933 extra.unwrap_or_default(),
2934 no_extra,
2935 false,
2937 vec![],
2939 flag(all_extras, no_all_extras, "all-extras")?.unwrap_or_default(),
2940 ),
2941 groups: DependencyGroups::from_args(
2942 DevMode::from_args(dev.into(), no_dev.into(), only_dev),
2943 group,
2944 if no_group.is_empty() {
2945 environment.no_group.clone().unwrap_or_default()
2946 } else {
2947 no_group
2948 },
2949 no_default_groups,
2950 only_group,
2951 all_groups,
2952 ),
2953 editable: EditableMode::from_args(
2954 flag(editable.into(), no_editable.into(), "editable")?,
2955 no_editable_package,
2956 ),
2957 hashes: flag(hashes, no_hashes, "hashes")?.unwrap_or(true),
2958 install_options: InstallOptions::new(
2959 no_emit_project,
2960 only_emit_project,
2961 no_emit_workspace,
2962 only_emit_workspace,
2963 no_emit_local,
2964 only_emit_local,
2965 no_emit_package,
2966 only_emit_package,
2967 ),
2968 batch,
2969 output_file,
2970 lock_check: locked,
2971 frozen,
2972 include_annotations: flag(annotate, no_annotate, "annotate")?.unwrap_or(true),
2973 include_header: flag(header, no_header, "header")?.unwrap_or(true),
2974 include_index_url: flag(emit_index_url, no_emit_index_url, "emit-index-url")?
2975 .unwrap_or(false),
2976 include_find_links: flag(emit_find_links, no_emit_find_links, "emit-find-links")?
2977 .unwrap_or(false),
2978 script,
2979 python: python.and_then(Maybe::into_option),
2980 refresh: Refresh::try_from(refresh)?,
2981 settings: resolve_resolver_settings(resolver, build, filesystem, &environment)?,
2982 install_mirrors: environment
2983 .install_mirrors
2984 .combine(filesystem_install_mirrors),
2985 })
2986 }
2987}
2988
2989#[derive(Debug, Clone)]
2991pub struct FormatSettings {
2992 pub ruff_path: Option<PathBuf>,
2993 pub check: bool,
2994 pub diff: bool,
2995 pub extra_args: Vec<String>,
2996 pub version: Option<String>,
2997 pub exclude_newer: Option<jiff::Timestamp>,
2998 pub no_project: bool,
2999 pub show_version: bool,
3000}
3001
3002impl FormatSettings {
3003 pub fn resolve(
3005 args: FormatArgs,
3006 _filesystem: Option<FilesystemOptions>,
3007 environment: EnvironmentOptions,
3008 ) -> Self {
3009 let FormatArgs {
3010 check,
3011 diff,
3012 extra_args,
3013 version,
3014 exclude_newer,
3015 no_project,
3016 show_version,
3017 } = args;
3018
3019 Self {
3020 ruff_path: environment.ruff_path,
3021 check,
3022 diff,
3023 extra_args,
3024 version,
3025 exclude_newer: exclude_newer
3026 .and_then(ExcludeNewerOverride::into_value)
3027 .map(|value| value.timestamp()),
3028 no_project,
3029 show_version,
3030 }
3031 }
3032}
3033
3034#[derive(Debug, Clone)]
3036pub struct CheckSettings {
3037 pub ty_path: Option<PathBuf>,
3038 #[expect(dead_code)]
3039 script: Option<PathBuf>,
3040 pub fix: bool,
3041 pub all_packages: bool,
3042 pub package: Vec<PackageName>,
3043 pub extras: ExtrasSpecification,
3044 pub groups: DependencyGroups,
3045 pub lock_check: LockCheck,
3046 pub frozen: Option<FrozenSource>,
3047 pub no_sync: bool,
3048 pub no_install_project: bool,
3049 pub isolated: bool,
3050 pub python: Option<String>,
3051 pub install_mirrors: PythonInstallMirrors,
3052 pub refresh: Refresh,
3053 pub settings: ResolverInstallerSettings,
3054 pub ty_version: Option<String>,
3055 pub show_version: bool,
3056 pub show_command: bool,
3057 pub no_project: bool,
3058 pub malware_settings: MalwareCheckSettings,
3059}
3060
3061impl CheckSettings {
3062 pub fn resolve(
3064 args: CheckArgs,
3065 filesystem: Option<FilesystemOptions>,
3066 environment: EnvironmentOptions,
3067 ) -> anyhow::Result<Self> {
3068 let CheckArgs {
3069 fix,
3070 all_packages,
3071 package,
3072 script,
3073 extra,
3074 all_extras,
3075 no_extra,
3076 no_all_extras,
3077 dependency_groups:
3078 ProjectDependencyGroupsArgs {
3079 dev,
3080 no_dev,
3081 only_dev,
3082 group,
3083 no_group,
3084 no_default_groups,
3085 only_group,
3086 all_groups,
3087 },
3088 locked,
3089 no_locked,
3090 frozen,
3091 no_frozen,
3092 no_sync,
3093 no_install_project,
3094 isolated,
3095 python,
3096 ty_version,
3097 show_version,
3098 show_command,
3099 no_project,
3100 installer,
3101 build,
3102 refresh,
3103 } = args;
3104
3105 let filesystem_install_mirrors = filesystem
3106 .as_ref()
3107 .map(|fs| fs.install_mirrors.clone())
3108 .unwrap_or_default();
3109
3110 let locked = resolve_lock_check(locked, no_locked, LockedFlag::Locked, environment.locked);
3111 let frozen = resolve_frozen(frozen, no_frozen, FrozenFlag::Frozen, environment.frozen);
3112 let no_sync = resolve_flag(no_sync, "no-sync", environment.no_sync);
3113 let no_install_project = resolve_flag(
3114 no_install_project,
3115 "no-install-project",
3116 environment.no_install_project,
3117 );
3118 let isolated = resolve_flag(isolated, "isolated", environment.isolated).is_enabled();
3119 let (locked, frozen) = resolve_lock_flags(locked, frozen)?;
3120 check_conflicts(no_install_project, no_sync)?;
3121 if script.is_some() {
3122 check_conflicts(no_install_project, Flag::from_cli("script"))?;
3123 }
3124 if no_project {
3125 check_conflicts(no_install_project, Flag::from_cli("no-project"))?;
3126 }
3127
3128 let (dev, no_dev) = resolve_flag_pair(
3129 dev,
3130 no_dev,
3131 "dev",
3132 "no-dev",
3133 Some(environment.dev),
3134 Some(environment.no_dev),
3135 );
3136 let malware_settings = MalwareCheckSettings::resolve(filesystem.as_ref(), &environment);
3137 let settings =
3138 resolve_resolver_installer_settings(installer, build, filesystem, &environment)?;
3139 Ok(Self {
3140 ty_path: environment.ty_path,
3141 script,
3142 fix,
3143 all_packages,
3144 package,
3145 extras: ExtrasSpecification::from_args(
3146 extra.unwrap_or_default(),
3147 no_extra,
3148 false,
3149 vec![],
3150 flag(all_extras, no_all_extras, "all-extras")?.unwrap_or_default(),
3151 ),
3152 groups: DependencyGroups::from_args(
3153 DevMode::from_args(dev.into(), no_dev.into(), only_dev),
3154 group,
3155 if no_group.is_empty() {
3156 environment.no_group.clone().unwrap_or_default()
3157 } else {
3158 no_group
3159 },
3160 no_default_groups,
3161 only_group,
3162 all_groups,
3163 ),
3164 lock_check: locked,
3165 frozen,
3166 no_sync: no_sync.is_enabled(),
3167 no_install_project: no_install_project.is_enabled(),
3168 isolated,
3169 python: python.and_then(Maybe::into_option),
3170 install_mirrors: environment
3171 .install_mirrors
3172 .combine(filesystem_install_mirrors),
3173 refresh: Refresh::try_from(refresh)?,
3174 settings,
3175 ty_version,
3176 show_version,
3177 show_command,
3178 no_project,
3179 malware_settings,
3180 })
3181 }
3182}
3183
3184#[derive(Debug, Clone)]
3186pub struct AuditSettings {
3187 pub extras: ExtrasSpecification,
3188 pub groups: DependencyGroups,
3189 pub lock_check: LockCheck,
3190 pub frozen: Option<FrozenSource>,
3191 pub python_version: Option<PythonVersion>,
3192 pub python_platform: Option<TargetTriple>,
3193 pub install_mirrors: PythonInstallMirrors,
3194 pub settings: ResolverSettings,
3195 pub output_format: AuditOutputFormat,
3196 pub service_format: VulnerabilityServiceFormat,
3197 pub service_url: Option<DisplaySafeUrl>,
3198 pub ignore: Vec<VulnerabilityID>,
3199 pub ignore_until_fixed: Vec<VulnerabilityID>,
3200}
3201
3202impl AuditSettings {
3203 pub fn resolve(
3205 args: AuditArgs,
3206 filesystem: Option<FilesystemOptions>,
3207 environment: EnvironmentOptions,
3208 ) -> anyhow::Result<Self> {
3209 let AuditArgs {
3210 no_extra,
3211 no_dev,
3212 no_group,
3213 no_default_groups,
3214 only_group,
3215 only_dev,
3216 script: _,
3217 python_version,
3218 python_platform,
3219 locked,
3220 no_locked,
3221 frozen,
3222 no_frozen,
3223 audit:
3224 AuditCommonArgs {
3225 offline: _,
3226 output_format,
3227 ignore,
3228 ignore_until_fixed,
3229 service_format,
3230 service_url,
3231 },
3232 build,
3233 resolver,
3234 } = args;
3235
3236 let filesystem_install_mirrors = filesystem
3237 .as_ref()
3238 .map(|fs| fs.install_mirrors.clone())
3239 .unwrap_or_default();
3240
3241 let filesystem_audit = filesystem
3242 .as_ref()
3243 .and_then(|fs| fs.audit.clone())
3244 .unwrap_or_default();
3245
3246 let no_dev = no_dev || environment.no_dev.value == Some(true);
3247
3248 let locked = resolve_lock_check(locked, no_locked, LockedFlag::Locked, environment.locked);
3250 let frozen = resolve_frozen(frozen, no_frozen, FrozenFlag::Frozen, environment.frozen);
3251
3252 let (locked, frozen) = resolve_lock_flags(locked, frozen)?;
3253
3254 let all_groups = only_group.is_empty() && !only_dev && !no_default_groups;
3257
3258 Ok(Self {
3259 extras: ExtrasSpecification::from_args(
3260 vec![],
3261 no_extra,
3262 false,
3264 vec![],
3266 true,
3267 ),
3268 groups: DependencyGroups::from_args(
3269 DevMode::from_args(all_groups, no_dev, only_dev),
3270 vec![],
3271 if no_group.is_empty() {
3272 environment.no_group.clone().unwrap_or_default()
3273 } else {
3274 no_group
3275 },
3276 no_default_groups,
3277 only_group,
3278 all_groups,
3279 ),
3280 lock_check: locked,
3281 frozen,
3282 python_version,
3283 python_platform,
3284 settings: resolve_resolver_settings(resolver, build, filesystem, &environment)?,
3285 install_mirrors: environment
3286 .install_mirrors
3287 .combine(filesystem_install_mirrors),
3288 output_format,
3289 service_format,
3290 service_url,
3291 ignore: {
3292 let config_ignore = filesystem_audit.ignore.unwrap_or_default();
3293 let mut merged = ignore;
3294 merged.extend(config_ignore);
3295 merged.into_iter().map(VulnerabilityID::new).collect()
3296 },
3297 ignore_until_fixed: {
3298 let config_ignore_until_fixed =
3299 filesystem_audit.ignore_until_fixed.unwrap_or_default();
3300 let mut merged = ignore_until_fixed;
3301 merged.extend(config_ignore_until_fixed);
3302 merged.into_iter().map(VulnerabilityID::new).collect()
3303 },
3304 })
3305 }
3306}
3307
3308fn workspace_overrides(filesystem: Option<&FilesystemOptions>) -> Vec<Override<Requirement>> {
3309 let mut overrides = Vec::new();
3310 for dependency in filesystem
3311 .and_then(|configuration| configuration.override_dependencies.as_ref())
3312 .into_iter()
3313 .flatten()
3314 {
3315 match dependency {
3316 OverrideDependency::Requirement(requirement) => {
3317 overrides.push(Override::Requirement(Requirement::from(
3318 requirement
3319 .clone()
3320 .with_origin(RequirementOrigin::Workspace),
3321 )));
3322 }
3323 OverrideDependency::Package(package) => {
3324 overrides.push(Override::Package(PackageOverride {
3325 package: package.package.clone(),
3326 dependencies: package
3327 .dependencies
3328 .iter()
3329 .cloned()
3330 .map(|requirement| {
3331 Requirement::from(requirement.with_origin(RequirementOrigin::Workspace))
3332 })
3333 .collect(),
3334 }));
3335 }
3336 }
3337 }
3338 overrides
3339}
3340
3341#[derive(Debug, Clone)]
3343pub struct PipCompileSettings {
3344 pub format: Option<PipCompileFormat>,
3345 pub src_file: Vec<RequirementsInput>,
3346 pub constraints: Vec<RequirementsInput>,
3347 pub overrides: Vec<RequirementsInput>,
3348 pub excludes: Vec<RequirementsInput>,
3349 pub build_constraints: Vec<RequirementsInput>,
3350 pub constraints_from_workspace: Vec<Requirement>,
3351 pub overrides_from_workspace: Vec<Override<Requirement>>,
3352 pub excludes_from_workspace: Vec<ExcludeDependency>,
3353 pub build_constraints_from_workspace: Vec<NameRequirementSpecification>,
3354 pub environments: SupportedEnvironments,
3355 pub required_environments: SupportedEnvironments,
3356 pub minimum_libc_version: Option<MinimumLibcVersion>,
3357 pub refresh: Refresh,
3358 pub settings: PipSettings,
3359}
3360
3361impl PipCompileSettings {
3362 pub fn resolve(
3364 args: PipCompileArgs,
3365 filesystem: Option<FilesystemOptions>,
3366 environment: EnvironmentOptions,
3367 ) -> anyhow::Result<Self> {
3368 let PipCompileArgs {
3369 src_file,
3370 constraints:
3371 DependencyConstraintsArgs {
3372 constraints,
3373 overrides,
3374 excludes,
3375 build_constraints,
3376 },
3377 extra,
3378 all_extras,
3379 no_all_extras,
3380 refresh,
3381 no_deps,
3382 deps,
3383 group,
3384 output_file,
3385 format,
3386 no_strip_extras,
3387 strip_extras,
3388 no_strip_markers,
3389 strip_markers,
3390 no_annotate,
3391 annotate,
3392 no_header,
3393 header,
3394 annotation_style,
3395 custom_compile_command,
3396 resolver,
3397 python,
3398 system,
3399 no_system,
3400 generate_hashes,
3401 no_generate_hashes,
3402 no_build,
3403 build,
3404 no_binary,
3405 only_binary,
3406 python_version,
3407 python_platform,
3408 universal,
3409 no_universal,
3410 no_emit_package,
3411 emit_index_url,
3412 no_emit_index_url,
3413 emit_find_links,
3414 no_emit_find_links,
3415 emit_build_options,
3416 no_emit_build_options,
3417 emit_marker_expression,
3418 no_emit_marker_expression,
3419 emit_index_annotation,
3420 no_emit_index_annotation,
3421 torch_backend,
3422 compat_args: _,
3423 } = args;
3424
3425 let constraints_from_workspace = if let Some(configuration) = &filesystem {
3426 configuration
3427 .constraint_dependencies
3428 .clone()
3429 .unwrap_or_default()
3430 .into_iter()
3431 .map(|requirement| {
3432 Requirement::from(requirement.with_origin(RequirementOrigin::Workspace))
3433 })
3434 .collect()
3435 } else {
3436 Vec::new()
3437 };
3438
3439 let overrides_from_workspace = workspace_overrides(filesystem.as_ref());
3440
3441 let excludes_from_workspace = if let Some(configuration) = &filesystem {
3442 configuration
3443 .exclude_dependencies
3444 .clone()
3445 .unwrap_or_default()
3446 } else {
3447 Vec::new()
3448 };
3449
3450 let build_constraints_from_workspace = if let Some(configuration) = &filesystem {
3451 configuration
3452 .build_constraint_dependencies
3453 .clone()
3454 .unwrap_or_default()
3455 .into_iter()
3456 .map(|requirement| {
3457 let (requirement, hashes) = requirement.into_parts();
3458 NameRequirementSpecification {
3459 requirement: Requirement::from(
3460 requirement.with_origin(RequirementOrigin::Workspace),
3461 ),
3462 hashes,
3463 }
3464 })
3465 .collect()
3466 } else {
3467 Vec::new()
3468 };
3469
3470 let environments = if let Some(configuration) = &filesystem {
3471 configuration.environments.clone().unwrap_or_default()
3472 } else {
3473 SupportedEnvironments::default()
3474 };
3475
3476 let required_environments = if let Some(configuration) = &filesystem {
3477 configuration
3478 .required_environments
3479 .clone()
3480 .unwrap_or_default()
3481 } else {
3482 SupportedEnvironments::default()
3483 };
3484
3485 let minimum_libc_version = filesystem
3486 .as_ref()
3487 .and_then(|configuration| configuration.minimum_libc_version);
3488
3489 Ok(Self {
3490 format,
3491 src_file,
3492 constraints: constraints
3493 .into_iter()
3494 .filter_map(Maybe::into_option)
3495 .collect(),
3496 build_constraints: build_constraints
3497 .into_iter()
3498 .filter_map(Maybe::into_option)
3499 .collect(),
3500 overrides: overrides
3501 .into_iter()
3502 .filter_map(Maybe::into_option)
3503 .collect(),
3504 excludes: excludes
3505 .into_iter()
3506 .filter_map(Maybe::into_option)
3507 .collect(),
3508 constraints_from_workspace,
3509 overrides_from_workspace,
3510 excludes_from_workspace,
3511 build_constraints_from_workspace,
3512 environments,
3513 required_environments,
3514 minimum_libc_version,
3515 refresh: Refresh::try_from(refresh)?,
3516 settings: PipSettings::combine(
3517 PipOptions {
3518 python: python.and_then(Maybe::into_option),
3519 system: flag(system, no_system, "system")?,
3520 no_build: flag(no_build, build, "build")?,
3521 no_binary,
3522 only_binary,
3523 extra,
3524 all_extras: flag(all_extras, no_all_extras, "all-extras")?,
3525 no_deps: flag(no_deps, deps, "deps")?,
3526 group: Some(group),
3527 output_file,
3528 no_strip_extras: flag(no_strip_extras, strip_extras, "strip-extras")?,
3529 no_strip_markers: flag(no_strip_markers, strip_markers, "strip-markers")?,
3530 no_annotate: flag(no_annotate, annotate, "annotate")?,
3531 no_header: flag(no_header, header, "header")?,
3532 custom_compile_command,
3533 generate_hashes: flag(generate_hashes, no_generate_hashes, "generate-hashes")?,
3534 python_version,
3535 python_platform,
3536 universal: flag(universal, no_universal, "universal")?,
3537 no_emit_package,
3538 emit_index_url: flag(emit_index_url, no_emit_index_url, "emit-index-url")?,
3539 emit_find_links: flag(emit_find_links, no_emit_find_links, "emit-find-links")?,
3540 emit_build_options: flag(
3541 emit_build_options,
3542 no_emit_build_options,
3543 "emit-build-options",
3544 )?,
3545 emit_marker_expression: flag(
3546 emit_marker_expression,
3547 no_emit_marker_expression,
3548 "emit-marker-expression",
3549 )?,
3550 emit_index_annotation: flag(
3551 emit_index_annotation,
3552 no_emit_index_annotation,
3553 "emit-index-annotation",
3554 )?,
3555 annotation_style,
3556 torch_backend,
3557 ..resolver.into_pip_options(configured_indexes(filesystem.as_ref()))?
3558 },
3559 filesystem,
3560 environment,
3561 ),
3562 })
3563 }
3564}
3565
3566#[derive(Debug, Clone)]
3568pub struct PipSyncSettings {
3569 pub src_file: Vec<RequirementsInput>,
3570 pub constraints: Vec<RequirementsInput>,
3571 pub build_constraints: Vec<RequirementsInput>,
3572 pub dry_run: DryRun,
3573 pub output_format: PipInstallFormat,
3574 pub refresh: Refresh,
3575 pub settings: PipSettings,
3576}
3577
3578impl PipSyncSettings {
3579 pub fn resolve(
3581 args: Box<PipSyncArgs>,
3582 filesystem: Option<FilesystemOptions>,
3583 environment: EnvironmentOptions,
3584 ) -> anyhow::Result<Self> {
3585 let PipSyncArgs {
3586 src_file,
3587 constraints,
3588 build_constraints,
3589 extra,
3590 all_extras,
3591 no_all_extras,
3592 group,
3593 installer,
3594 refresh,
3595 hash_checking:
3596 HashCheckingArgs {
3597 require_hashes,
3598 no_require_hashes,
3599 verify_hashes,
3600 no_verify_hashes,
3601 },
3602 python,
3603 system,
3604 no_system,
3605 break_system_packages,
3606 no_break_system_packages,
3607 target,
3608 prefix,
3609 allow_empty_requirements,
3610 no_allow_empty_requirements,
3611 no_build,
3612 build,
3613 no_binary,
3614 only_binary,
3615 python_version,
3616 python_platform,
3617 strict,
3618 no_strict,
3619 dry_run,
3620 output_format,
3621 torch_backend,
3622 compat_args: _,
3623 check,
3624 } = *args;
3625
3626 Ok(Self {
3627 src_file,
3628 constraints: constraints
3629 .into_iter()
3630 .filter_map(Maybe::into_option)
3631 .collect(),
3632 build_constraints: build_constraints
3633 .into_iter()
3634 .filter_map(Maybe::into_option)
3635 .collect(),
3636 dry_run: if check {
3637 DryRun::Check
3638 } else {
3639 DryRun::from_args(dry_run)
3640 },
3641 output_format,
3642 refresh: Refresh::try_from(refresh)?,
3643 settings: PipSettings::combine(
3644 PipOptions {
3645 python: python.and_then(Maybe::into_option),
3646 system: flag(system, no_system, "system")?,
3647 break_system_packages: flag(
3648 break_system_packages,
3649 no_break_system_packages,
3650 "break-system-packages",
3651 )?,
3652 target,
3653 prefix,
3654 require_hashes: flag(require_hashes, no_require_hashes, "require-hashes")?,
3655 verify_hashes: flag(verify_hashes, no_verify_hashes, "verify-hashes")?,
3656 no_build: flag(no_build, build, "build")?,
3657 no_binary,
3658 only_binary,
3659 allow_empty_requirements: flag(
3660 allow_empty_requirements,
3661 no_allow_empty_requirements,
3662 "allow-empty-requirements",
3663 )?,
3664 python_version,
3665 python_platform,
3666 strict: flag(strict, no_strict, "strict")?,
3667 extra,
3668 all_extras: flag(all_extras, no_all_extras, "all-extras")?,
3669 group: Some(group),
3670 torch_backend,
3671 ..installer.into_pip_options(configured_indexes(filesystem.as_ref()))?
3672 },
3673 filesystem,
3674 environment,
3675 ),
3676 })
3677 }
3678}
3679
3680#[derive(Debug, Clone)]
3682pub struct PipInstallSettings {
3683 pub package: Vec<String>,
3684 pub requirements: Vec<RequirementsInput>,
3685 pub editables: Vec<String>,
3686 pub editable: Option<EditableMode>,
3687 pub constraints: Vec<RequirementsInput>,
3688 pub overrides: Vec<RequirementsInput>,
3689 pub excludes: Vec<RequirementsInput>,
3690 pub build_constraints: Vec<RequirementsInput>,
3691 pub dry_run: DryRun,
3692 pub output_format: PipInstallFormat,
3693 pub constraints_from_workspace: Vec<Requirement>,
3694 pub overrides_from_workspace: Vec<Override<Requirement>>,
3695 pub excludes_from_workspace: Vec<ExcludeDependency>,
3696 pub build_constraints_from_workspace: Vec<NameRequirementSpecification>,
3697 pub modifications: Modifications,
3698 pub refresh: Refresh,
3699 pub settings: PipSettings,
3700}
3701
3702impl PipInstallSettings {
3703 pub fn resolve(
3705 args: PipInstallArgs,
3706 filesystem: Option<FilesystemOptions>,
3707 environment: EnvironmentOptions,
3708 ) -> anyhow::Result<Self> {
3709 let PipInstallArgs {
3710 package,
3711 requirements,
3712 editable,
3713 no_editable,
3714 no_editable_package,
3715 constraints:
3716 DependencyConstraintsArgs {
3717 constraints,
3718 overrides,
3719 excludes,
3720 build_constraints,
3721 },
3722 extra,
3723 all_extras,
3724 no_all_extras,
3725 installer,
3726 refresh,
3727 no_deps,
3728 deps,
3729 group,
3730 hash_checking:
3731 HashCheckingArgs {
3732 require_hashes,
3733 no_require_hashes,
3734 verify_hashes,
3735 no_verify_hashes,
3736 },
3737 python,
3738 system,
3739 no_system,
3740 break_system_packages,
3741 no_break_system_packages,
3742 target,
3743 prefix,
3744 no_build,
3745 build,
3746 no_binary,
3747 only_binary,
3748 python_version,
3749 python_platform,
3750 inexact,
3751 exact,
3752 strict,
3753 no_strict,
3754 dry_run,
3755 output_format,
3756 torch_backend,
3757 compat_args: _,
3758 check,
3759 } = args;
3760
3761 let constraints_from_workspace = if let Some(configuration) = &filesystem {
3762 configuration
3763 .constraint_dependencies
3764 .clone()
3765 .unwrap_or_default()
3766 .into_iter()
3767 .map(|requirement| {
3768 Requirement::from(requirement.with_origin(RequirementOrigin::Workspace))
3769 })
3770 .collect()
3771 } else {
3772 Vec::new()
3773 };
3774
3775 let overrides_from_workspace = workspace_overrides(filesystem.as_ref());
3776
3777 let excludes_from_workspace = if let Some(configuration) = &filesystem {
3778 configuration
3779 .exclude_dependencies
3780 .clone()
3781 .unwrap_or_default()
3782 } else {
3783 Vec::new()
3784 };
3785
3786 let build_constraints_from_workspace = if let Some(configuration) = &filesystem {
3787 configuration
3788 .build_constraint_dependencies
3789 .clone()
3790 .unwrap_or_default()
3791 .into_iter()
3792 .map(|requirement| {
3793 let (requirement, hashes) = requirement.into_parts();
3794 NameRequirementSpecification {
3795 requirement: Requirement::from(
3796 requirement.with_origin(RequirementOrigin::Workspace),
3797 ),
3798 hashes,
3799 }
3800 })
3801 .collect()
3802 } else {
3803 Vec::new()
3804 };
3805
3806 Ok(Self {
3807 package,
3808 requirements,
3809 editables: editable,
3810 constraints: constraints
3811 .into_iter()
3812 .filter_map(Maybe::into_option)
3813 .collect(),
3814 overrides: overrides
3815 .into_iter()
3816 .filter_map(Maybe::into_option)
3817 .collect(),
3818 excludes: excludes
3819 .into_iter()
3820 .filter_map(Maybe::into_option)
3821 .collect(),
3822 build_constraints: build_constraints
3823 .into_iter()
3824 .filter_map(Maybe::into_option)
3825 .collect(),
3826 dry_run: if check {
3827 DryRun::Check
3828 } else {
3829 DryRun::from_args(dry_run)
3830 },
3831 output_format,
3832 constraints_from_workspace,
3833 overrides_from_workspace,
3834 excludes_from_workspace,
3835 build_constraints_from_workspace,
3836 modifications: if flag(exact, inexact, "inexact")?.unwrap_or(false) {
3837 Modifications::Exact
3838 } else {
3839 Modifications::Sufficient
3840 },
3841 editable: EditableMode::from_args(
3842 if no_editable || environment.no_editable.value == Some(true) {
3843 Some(false)
3844 } else {
3845 None
3846 },
3847 no_editable_package,
3848 ),
3849 refresh: Refresh::try_from(refresh)?,
3850 settings: PipSettings::combine(
3851 PipOptions {
3852 python: python.and_then(Maybe::into_option),
3853 system: flag(system, no_system, "system")?,
3854 break_system_packages: flag(
3855 break_system_packages,
3856 no_break_system_packages,
3857 "break-system-packages",
3858 )?,
3859 target,
3860 prefix,
3861 no_build: flag(no_build, build, "build")?,
3862 no_binary,
3863 only_binary,
3864 strict: flag(strict, no_strict, "strict")?,
3865 extra,
3866 all_extras: flag(all_extras, no_all_extras, "all-extras")?,
3867 group: Some(group),
3868 no_deps: flag(no_deps, deps, "deps")?,
3869 python_version,
3870 python_platform,
3871 require_hashes: flag(require_hashes, no_require_hashes, "require-hashes")?,
3872 verify_hashes: flag(verify_hashes, no_verify_hashes, "verify-hashes")?,
3873 torch_backend,
3874 ..installer.into_pip_options(configured_indexes(filesystem.as_ref()))?
3875 },
3876 filesystem,
3877 environment,
3878 ),
3879 })
3880 }
3881}
3882
3883#[derive(Debug, Clone)]
3885pub struct PipUninstallSettings {
3886 pub package: Vec<String>,
3887 pub requirements: Vec<RequirementsInput>,
3888 pub dry_run: DryRun,
3889 pub settings: PipSettings,
3890}
3891
3892impl PipUninstallSettings {
3893 pub fn resolve(
3895 args: PipUninstallArgs,
3896 filesystem: Option<FilesystemOptions>,
3897 environment: EnvironmentOptions,
3898 ) -> anyhow::Result<Self> {
3899 let PipUninstallArgs {
3900 package,
3901 requirements,
3902 python,
3903 keyring_provider,
3904 system,
3905 no_system,
3906 break_system_packages,
3907 no_break_system_packages,
3908 target,
3909 prefix,
3910 dry_run,
3911 compat_args: _,
3912 } = args;
3913
3914 Ok(Self {
3915 package,
3916 requirements,
3917 dry_run: DryRun::from_args(dry_run),
3918 settings: PipSettings::combine(
3919 PipOptions {
3920 python: python.and_then(Maybe::into_option),
3921 system: flag(system, no_system, "system")?,
3922 break_system_packages: flag(
3923 break_system_packages,
3924 no_break_system_packages,
3925 "break-system-packages",
3926 )?,
3927 target,
3928 prefix,
3929 keyring_provider,
3930 ..PipOptions::default()
3931 },
3932 filesystem,
3933 environment,
3934 ),
3935 })
3936 }
3937}
3938
3939#[derive(Debug, Clone)]
3941pub struct PipFreezeSettings {
3942 pub exclude_editable: bool,
3943 pub exclude: FxHashSet<PackageName>,
3944 pub paths: Option<Vec<PathBuf>>,
3945 pub settings: PipSettings,
3946}
3947
3948impl PipFreezeSettings {
3949 pub fn resolve(
3951 args: PipFreezeArgs,
3952 filesystem: Option<FilesystemOptions>,
3953 environment: EnvironmentOptions,
3954 ) -> anyhow::Result<Self> {
3955 let PipFreezeArgs {
3956 exclude_editable,
3957 exclude,
3958 strict,
3959 no_strict,
3960 python,
3961 paths,
3962 system,
3963 no_system,
3964 target,
3965 prefix,
3966 compat_args: _,
3967 } = args;
3968
3969 Ok(Self {
3970 exclude_editable,
3971 exclude: exclude.into_iter().collect(),
3972 paths,
3973 settings: PipSettings::combine(
3974 PipOptions {
3975 python: python.and_then(Maybe::into_option),
3976 system: flag(system, no_system, "system")?,
3977 strict: flag(strict, no_strict, "strict")?,
3978 target,
3979 prefix,
3980 ..PipOptions::default()
3981 },
3982 filesystem,
3983 environment,
3984 ),
3985 })
3986 }
3987}
3988
3989#[derive(Debug, Clone)]
3991pub struct PipListSettings {
3992 pub editable: Option<bool>,
3993 pub exclude: FxHashSet<PackageName>,
3994 pub format: ListFormat,
3995 pub outdated: bool,
3996 pub settings: PipSettings,
3997}
3998
3999impl PipListSettings {
4000 pub fn resolve(
4002 args: PipListArgs,
4003 filesystem: Option<FilesystemOptions>,
4004 environment: EnvironmentOptions,
4005 ) -> anyhow::Result<Self> {
4006 let PipListArgs {
4007 editable,
4008 exclude_editable,
4009 exclude,
4010 format,
4011 outdated,
4012 no_outdated,
4013 strict,
4014 no_strict,
4015 fetch,
4016 python,
4017 system,
4018 no_system,
4019 target,
4020 prefix,
4021 compat_args: _,
4022 } = args;
4023
4024 Ok(Self {
4025 editable: flag(editable, exclude_editable, "exclude-editable")?,
4026 exclude: exclude.into_iter().collect(),
4027 format,
4028 outdated: flag(outdated, no_outdated, "outdated")?.unwrap_or(false),
4029 settings: PipSettings::combine(
4030 PipOptions {
4031 python: python.and_then(Maybe::into_option),
4032 system: flag(system, no_system, "system")?,
4033 strict: flag(strict, no_strict, "strict")?,
4034 target,
4035 prefix,
4036 ..fetch.into_pip_options(configured_indexes(filesystem.as_ref()))?
4037 },
4038 filesystem,
4039 environment,
4040 ),
4041 })
4042 }
4043}
4044
4045#[derive(Debug, Clone)]
4047pub struct PipShowSettings {
4048 pub package: Vec<PackageName>,
4049 pub files: bool,
4050 pub settings: PipSettings,
4051}
4052
4053impl PipShowSettings {
4054 pub fn resolve(
4056 args: PipShowArgs,
4057 filesystem: Option<FilesystemOptions>,
4058 environment: EnvironmentOptions,
4059 ) -> anyhow::Result<Self> {
4060 let PipShowArgs {
4061 package,
4062 strict,
4063 no_strict,
4064 files,
4065 python,
4066 system,
4067 no_system,
4068 target,
4069 prefix,
4070 compat_args: _,
4071 } = args;
4072
4073 Ok(Self {
4074 package,
4075 files,
4076 settings: PipSettings::combine(
4077 PipOptions {
4078 python: python.and_then(Maybe::into_option),
4079 system: flag(system, no_system, "system")?,
4080 strict: flag(strict, no_strict, "strict")?,
4081 target,
4082 prefix,
4083 ..PipOptions::default()
4084 },
4085 filesystem,
4086 environment,
4087 ),
4088 })
4089 }
4090}
4091
4092#[derive(Debug, Clone)]
4094pub struct PipTreeSettings {
4095 pub show_version_specifiers: bool,
4096 pub depth: u8,
4097 pub prune: Vec<PackageName>,
4098 pub package: Vec<PackageName>,
4099 pub no_dedupe: bool,
4100 pub invert: bool,
4101 pub outdated: bool,
4102 pub settings: PipSettings,
4103}
4104
4105impl PipTreeSettings {
4106 pub fn resolve(
4108 args: PipTreeArgs,
4109 filesystem: Option<FilesystemOptions>,
4110 environment: EnvironmentOptions,
4111 ) -> anyhow::Result<Self> {
4112 let PipTreeArgs {
4113 show_version_specifiers,
4114 tree,
4115 strict,
4116 no_strict,
4117 fetch,
4118 python,
4119 system,
4120 no_system,
4121 compat_args: _,
4122 } = args;
4123
4124 Ok(Self {
4125 show_version_specifiers,
4126 depth: tree.depth,
4127 prune: tree.prune,
4128 no_dedupe: tree.no_dedupe,
4129 invert: tree.invert,
4130 package: tree.package,
4131 outdated: tree.outdated,
4132 settings: PipSettings::combine(
4133 PipOptions {
4134 python: python.and_then(Maybe::into_option),
4135 system: flag(system, no_system, "system")?,
4136 strict: flag(strict, no_strict, "strict")?,
4137 ..fetch.into_pip_options(configured_indexes(filesystem.as_ref()))?
4138 },
4139 filesystem,
4140 environment,
4141 ),
4142 })
4143 }
4144}
4145
4146#[derive(Debug, Clone)]
4148pub struct PipCheckSettings {
4149 pub settings: PipSettings,
4150}
4151
4152impl PipCheckSettings {
4153 pub fn resolve(
4155 args: PipCheckArgs,
4156 filesystem: Option<FilesystemOptions>,
4157 environment: EnvironmentOptions,
4158 ) -> anyhow::Result<Self> {
4159 let PipCheckArgs {
4160 python,
4161 system,
4162 no_system,
4163 python_version,
4164 python_platform,
4165 } = args;
4166
4167 Ok(Self {
4168 settings: PipSettings::combine(
4169 PipOptions {
4170 python: python.and_then(Maybe::into_option),
4171 system: flag(system, no_system, "system")?,
4172 python_version,
4173 python_platform,
4174 ..PipOptions::default()
4175 },
4176 filesystem,
4177 environment,
4178 ),
4179 })
4180 }
4181}
4182
4183#[derive(Debug, Clone)]
4185pub struct BuildSettings {
4186 pub skip_dependency_check: bool,
4187 pub src: Option<PathBuf>,
4188 pub package: Option<PackageName>,
4189 pub all_packages: bool,
4190 pub out_dir: Option<PathBuf>,
4191 pub sdist: bool,
4192 pub wheel: bool,
4193 pub list: bool,
4194 pub build_logs: bool,
4195 pub gitignore: bool,
4196 pub force_pep517: bool,
4197 pub clear: bool,
4198 pub build_constraints: Vec<RequirementsInput>,
4199 pub build_constraints_from_workspace: Vec<NameRequirementSpecification>,
4200 pub hash_checking: Option<HashCheckingMode>,
4201 pub python: Option<String>,
4202 pub install_mirrors: PythonInstallMirrors,
4203 pub refresh: Refresh,
4204 pub settings: ResolverSettings,
4205}
4206
4207impl BuildSettings {
4208 pub fn resolve(
4210 args: BuildArgs,
4211 filesystem: Option<FilesystemOptions>,
4212 environment: EnvironmentOptions,
4213 ) -> anyhow::Result<Self> {
4214 let BuildArgs {
4215 skip_dependency_check,
4216 src,
4217 out_dir,
4218 package,
4219 all_packages,
4220 sdist,
4221 wheel,
4222 list,
4223 force_pep517,
4224 clear,
4225 build_constraints,
4226 hash_checking:
4227 HashCheckingArgs {
4228 require_hashes,
4229 no_require_hashes,
4230 verify_hashes,
4231 no_verify_hashes,
4232 },
4233 build_logs,
4234 no_build_logs,
4235 create_gitignore,
4236 no_create_gitignore,
4237 python,
4238 build,
4239 refresh,
4240 resolver,
4241 } = args;
4242 let filesystem_install_mirrors = match &filesystem {
4243 Some(fs) => fs.install_mirrors.clone(),
4244 None => PythonInstallMirrors::default(),
4245 };
4246 let build_constraints_from_workspace = if let Some(configuration) = &filesystem {
4247 configuration
4248 .build_constraint_dependencies
4249 .clone()
4250 .unwrap_or_default()
4251 .into_iter()
4252 .map(|requirement| {
4253 let (requirement, hashes) = requirement.into_parts();
4254 NameRequirementSpecification {
4255 requirement: Requirement::from(
4256 requirement.with_origin(RequirementOrigin::Workspace),
4257 ),
4258 hashes,
4259 }
4260 })
4261 .collect()
4262 } else {
4263 Vec::new()
4264 };
4265
4266 Ok(Self {
4267 skip_dependency_check,
4268 src,
4269 package,
4270 all_packages,
4271 out_dir,
4272 sdist,
4273 wheel,
4274 list,
4275 build_logs: flag(build_logs, no_build_logs, "build-logs")?.unwrap_or(true),
4276 force_pep517,
4277 clear,
4278 gitignore: flag(create_gitignore, no_create_gitignore, "create-gitignore")?
4279 .unwrap_or(true),
4280 build_constraints: build_constraints
4281 .into_iter()
4282 .filter_map(Maybe::into_option)
4283 .collect(),
4284 build_constraints_from_workspace,
4285 hash_checking: HashCheckingMode::from_args(
4286 flag(require_hashes, no_require_hashes, "require-hashes")?,
4287 flag(verify_hashes, no_verify_hashes, "verify-hashes")?,
4288 ),
4289 python: python.and_then(Maybe::into_option),
4290 refresh: Refresh::try_from(refresh)?,
4291 settings: resolve_resolver_settings(resolver, build, filesystem, &environment)?,
4292 install_mirrors: environment
4293 .install_mirrors
4294 .combine(filesystem_install_mirrors),
4295 })
4296 }
4297}
4298
4299#[derive(Debug, Clone)]
4301pub struct VenvSettings {
4302 pub seed: bool,
4303 pub allow_existing: bool,
4304 pub clear: bool,
4305 pub force: bool,
4306 pub no_clear: bool,
4307 pub path: Option<PathBuf>,
4308 pub prompt: Option<String>,
4309 pub system_site_packages: bool,
4310 pub relocatable: bool,
4311 pub no_relocatable: bool,
4312 pub no_project: bool,
4313 pub refresh: Refresh,
4314 pub settings: PipSettings,
4315}
4316
4317impl VenvSettings {
4318 pub fn resolve(
4320 args: VenvArgs,
4321 filesystem: Option<FilesystemOptions>,
4322 environment: EnvironmentOptions,
4323 ) -> anyhow::Result<Self> {
4324 let VenvArgs {
4325 python,
4326 system,
4327 no_system,
4328 seed,
4329 allow_existing,
4330 clear,
4331 force,
4332 no_clear,
4333 path,
4334 prompt,
4335 system_site_packages,
4336 relocatable,
4337 no_relocatable,
4338 index_args,
4339 registry_client:
4340 RegistryClientArgs {
4341 index_strategy,
4342 keyring_provider,
4343 },
4344 exclude_newer:
4345 PackageExcludeNewerArgs {
4346 exclude_newer: ExcludeNewerArgs { exclude_newer },
4347 exclude_newer_package,
4348 },
4349 no_project,
4350 link_mode,
4351 refresh,
4352 compat_args: _,
4353 } = args;
4354
4355 let seed = seed || environment.venv_seed.value == Some(true);
4357 let (clear, no_clear) = resolve_flag_pair(
4358 clear,
4359 no_clear,
4360 "clear",
4361 "no-clear",
4362 Some(environment.venv_clear),
4363 None,
4364 );
4365 let (relocatable, no_relocatable) = resolve_flag_pair(
4366 relocatable,
4367 no_relocatable,
4368 "relocatable",
4369 "no-relocatable",
4370 Some(environment.venv_relocatable),
4371 None,
4372 );
4373
4374 Ok(Self {
4375 seed,
4376 allow_existing,
4377 clear: clear.into(),
4378 force,
4379 no_clear: no_clear.into(),
4380 path,
4381 prompt,
4382 system_site_packages,
4383 no_project,
4384 relocatable: relocatable.into(),
4385 no_relocatable: no_relocatable.into(),
4386 refresh: Refresh::try_from(refresh)?,
4387 settings: PipSettings::combine(
4388 PipOptions {
4389 python: python.and_then(Maybe::into_option),
4390 system: flag(system, no_system, "system")?,
4391 index_strategy,
4392 keyring_provider,
4393 exclude_newer,
4394 exclude_newer_package: exclude_newer_package
4395 .map(ExcludeNewerPackage::from_iter),
4396 link_mode,
4397 ..index_args.into_pip_options(configured_indexes(filesystem.as_ref()))?
4398 },
4399 filesystem,
4400 environment,
4401 ),
4402 })
4403 }
4404}
4405
4406fn configured_indexes(filesystem: Option<&FilesystemOptions>) -> &[Index] {
4408 filesystem
4409 .and_then(|options| options.top_level.index.as_deref())
4410 .unwrap_or_default()
4411}
4412
4413fn resolve_resolver_settings(
4415 args: ResolverArgs,
4416 build: BuildOptionsArgs,
4417 filesystem: Option<FilesystemOptions>,
4418 environment: &EnvironmentOptions,
4419) -> Result<ResolverSettings> {
4420 let args = resolver_options(args, build, configured_indexes(filesystem.as_ref()))?;
4421
4422 Ok(combine_resolver_settings(args, filesystem, environment))
4423}
4424
4425fn combine_resolver_settings(
4427 mut args: ResolverOptions,
4428 filesystem: Option<FilesystemOptions>,
4429 environment: &EnvironmentOptions,
4430) -> ResolverSettings {
4431 args.no_binary_package = args
4432 .no_binary_package
4433 .or(environment.no_binary_package.clone());
4434 args.no_build_package = args
4435 .no_build_package
4436 .or(environment.no_build_package.clone());
4437 args.no_sources_package = args
4438 .no_sources_package
4439 .or(environment.no_sources_package.clone());
4440
4441 let options = args.combine(ResolverOptions::from(
4444 filesystem
4445 .map(FilesystemOptions::into_options)
4446 .map(|options| options.top_level)
4447 .unwrap_or_default(),
4448 ));
4449
4450 ResolverSettings {
4451 cuda_driver_version: environment.cuda_driver_version.clone(),
4452 amd_gpu_architecture: environment.amd_gpu_architecture,
4453 ..ResolverSettings::from(options)
4454 }
4455}
4456
4457fn resolve_resolver_installer_settings(
4459 args: ResolverInstallerArgs,
4460 build: BuildOptionsArgs,
4461 filesystem: Option<FilesystemOptions>,
4462 environment: &EnvironmentOptions,
4463) -> Result<ResolverInstallerSettings> {
4464 let args = resolver_installer_options(args, build, configured_indexes(filesystem.as_ref()))?;
4465
4466 Ok(combine_resolver_installer_settings(
4467 args,
4468 filesystem,
4469 environment,
4470 ))
4471}
4472
4473fn combine_resolver_installer_settings(
4475 args: ResolverInstallerOptions,
4476 filesystem: Option<FilesystemOptions>,
4477 environment: &EnvironmentOptions,
4478) -> ResolverInstallerSettings {
4479 let options = resolver_installer_options_with_environment(args, environment).combine(
4480 ResolverInstallerOptions::from(
4481 filesystem
4482 .map(FilesystemOptions::into_options)
4483 .map(|options| options.top_level)
4484 .unwrap_or_default(),
4485 ),
4486 );
4487
4488 let base = ResolverInstallerSettings::from(options);
4489 ResolverInstallerSettings {
4490 resolver: ResolverSettings {
4491 cuda_driver_version: environment.cuda_driver_version.clone(),
4492 amd_gpu_architecture: environment.amd_gpu_architecture,
4493 ..base.resolver
4494 },
4495 ..base
4496 }
4497}
4498
4499fn resolver_installer_options_with_environment(
4500 mut options: ResolverInstallerOptions,
4501 environment: &EnvironmentOptions,
4502) -> ResolverInstallerOptions {
4503 options.no_binary_package = options
4504 .no_binary_package
4505 .or(environment.no_binary_package.clone());
4506 options.no_build_package = options
4507 .no_build_package
4508 .or(environment.no_build_package.clone());
4509 options.no_sources_package = options
4510 .no_sources_package
4511 .or(environment.no_sources_package.clone());
4512 options
4513}
4514
4515#[derive(Debug, Clone)]
4520pub struct PipSettings {
4521 pub index_locations: IndexLocations,
4522 pub python: Option<String>,
4523 pub install_mirrors: PythonInstallMirrors,
4524 pub system: bool,
4525 pub extras: ExtrasSpecification,
4526 pub groups: Vec<PipGroupName>,
4527 pub break_system_packages: bool,
4528 pub target: Option<Target>,
4529 pub prefix: Option<Prefix>,
4530 pub index_strategy: IndexStrategy,
4531 pub keyring_provider: KeyringProviderType,
4532 pub torch_backend: Option<TorchMode>,
4533 pub cuda_driver_version: Option<Version>,
4534 pub amd_gpu_architecture: Option<AmdGpuArchitecture>,
4535 pub build_isolation: BuildIsolation,
4536 pub extra_build_dependencies: ExtraBuildDependencies,
4537 pub extra_build_variables: ExtraBuildVariables,
4538 pub build_options: BuildOptions,
4539 pub allow_empty_requirements: bool,
4540 pub strict: bool,
4541 pub dependency_mode: DependencyMode,
4542 pub resolution: ResolutionMode,
4543 pub prerelease: Prerelease,
4544 pub fork_strategy: ForkStrategy,
4545 pub dependency_metadata: DependencyMetadata,
4546 pub output_file: Option<PathBuf>,
4547 pub no_strip_extras: bool,
4548 pub no_strip_markers: bool,
4549 pub no_annotate: bool,
4550 pub no_header: bool,
4551 pub custom_compile_command: Option<String>,
4552 pub generate_hashes: bool,
4553 pub config_setting: ConfigSettings,
4554 pub config_settings_package: PackageConfigSettings,
4555 pub python_version: Option<PythonVersion>,
4556 pub python_platform: Option<TargetTriple>,
4557 pub universal: bool,
4558 pub exclude_newer: ExcludeNewer,
4559 pub no_emit_package: Vec<PackageName>,
4560 pub emit_index_url: bool,
4561 pub emit_find_links: bool,
4562 pub emit_build_options: bool,
4563 pub emit_marker_expression: bool,
4564 pub emit_index_annotation: bool,
4565 pub annotation_style: AnnotationStyle,
4566 pub link_mode: LinkMode,
4567 pub compile_bytecode: bool,
4568 pub sources: NoSources,
4569 pub hash_checking: Option<HashCheckingMode>,
4570 pub upgrade: Upgrade,
4571 pub reinstall: Reinstall,
4572}
4573
4574impl PipSettings {
4575 fn combine(
4577 args: PipOptions,
4578 filesystem: Option<FilesystemOptions>,
4579 environment: EnvironmentOptions,
4580 ) -> Self {
4581 let Options {
4582 top_level,
4583 pip,
4584 install_mirrors: filesystem_install_mirrors,
4585 ..
4586 } = filesystem
4587 .map(FilesystemOptions::into_options)
4588 .unwrap_or_default();
4589
4590 let PipOptions {
4591 python,
4592 system,
4593 break_system_packages,
4594 target,
4595 prefix,
4596 index,
4597 index_url,
4598 extra_index_url,
4599 no_index,
4600 find_links,
4601 index_strategy,
4602 torch_backend,
4603 keyring_provider,
4604 no_build,
4605 no_binary,
4606 only_binary,
4607 no_build_isolation,
4608 no_build_isolation_package,
4609 extra_build_dependencies,
4610 extra_build_variables,
4611 strict,
4612 extra,
4613 all_extras,
4614 no_extra,
4615 group,
4616 no_deps,
4617 allow_empty_requirements,
4618 resolution,
4619 prerelease,
4620 prerelease_package: _,
4621 fork_strategy,
4622 dependency_metadata,
4623 output_file,
4624 no_strip_extras,
4625 no_strip_markers,
4626 no_annotate,
4627 no_header,
4628 custom_compile_command,
4629 generate_hashes,
4630 config_settings,
4631 config_settings_package,
4632 python_version,
4633 python_platform,
4634 universal,
4635 exclude_newer,
4636 no_emit_package,
4637 emit_index_url,
4638 emit_find_links,
4639 emit_build_options,
4640 emit_marker_expression,
4641 emit_index_annotation,
4642 annotation_style,
4643 link_mode,
4644 compile_bytecode,
4645 require_hashes,
4646 verify_hashes,
4647 no_sources,
4648 no_sources_package,
4649 upgrade,
4650 upgrade_package,
4651 reinstall,
4652 reinstall_package,
4653 exclude_newer_package,
4654 } = pip.unwrap_or_default();
4655
4656 let ResolverInstallerSchema {
4657 index: top_level_index,
4658 index_url: top_level_index_url,
4659 extra_index_url: top_level_extra_index_url,
4660 no_index: top_level_no_index,
4661 find_links: top_level_find_links,
4662 index_strategy: top_level_index_strategy,
4663 keyring_provider: top_level_keyring_provider,
4664 resolution: top_level_resolution,
4665 prerelease: top_level_prerelease,
4666 prerelease_package: top_level_prerelease_package,
4667 fork_strategy: top_level_fork_strategy,
4668 dependency_metadata: top_level_dependency_metadata,
4669 config_settings: top_level_config_settings,
4670 config_settings_package: top_level_config_settings_package,
4671 no_build_isolation: top_level_no_build_isolation,
4672 no_build_isolation_package: top_level_no_build_isolation_package,
4673 extra_build_dependencies: top_level_extra_build_dependencies,
4674 extra_build_variables: top_level_extra_build_variables,
4675 exclude_newer: top_level_exclude_newer,
4676 link_mode: top_level_link_mode,
4677 compile_bytecode: top_level_compile_bytecode,
4678 no_sources: top_level_no_sources,
4679 no_sources_package: top_level_no_sources_package,
4680 upgrade: top_level_upgrade,
4681 upgrade_package: top_level_upgrade_package,
4682 reinstall: top_level_reinstall,
4683 reinstall_package: top_level_reinstall_package,
4684 no_build: top_level_no_build,
4685 no_build_package: top_level_no_build_package,
4686 no_binary: top_level_no_binary,
4687 no_binary_package: top_level_no_binary_package,
4688 exclude_newer_package: top_level_exclude_newer_package,
4689 torch_backend: top_level_torch_backend,
4690 } = top_level;
4691
4692 let index = index.combine(top_level_index);
4697 let no_index = no_index.combine(top_level_no_index);
4698 let index_url = index_url.combine(top_level_index_url);
4699 let extra_index_url = extra_index_url.combine(top_level_extra_index_url);
4700 let find_links = find_links.combine(top_level_find_links);
4701 let index_strategy = index_strategy.combine(top_level_index_strategy);
4702 let keyring_provider = keyring_provider.combine(top_level_keyring_provider);
4703 let resolution = resolution.combine(top_level_resolution);
4704 let prerelease = prerelease.combine(top_level_prerelease);
4705 let prerelease_package = args
4706 .prerelease_package
4707 .combine(top_level_prerelease_package)
4708 .unwrap_or_default();
4709 let fork_strategy = fork_strategy.combine(top_level_fork_strategy);
4710 let dependency_metadata = dependency_metadata.combine(top_level_dependency_metadata);
4711 let config_settings = config_settings.combine(top_level_config_settings);
4712 let config_settings_package =
4713 config_settings_package.combine(top_level_config_settings_package);
4714 let no_build_isolation = no_build_isolation.combine(top_level_no_build_isolation);
4715 let no_build_isolation_package =
4716 no_build_isolation_package.combine(top_level_no_build_isolation_package);
4717 let extra_build_dependencies =
4718 extra_build_dependencies.combine(top_level_extra_build_dependencies);
4719 let extra_build_variables = extra_build_variables.combine(top_level_extra_build_variables);
4720 let exclude_newer = args
4721 .exclude_newer
4722 .combine(exclude_newer)
4723 .combine(top_level_exclude_newer);
4724 let exclude_newer_package = args
4725 .exclude_newer_package
4726 .combine(exclude_newer_package)
4727 .combine(top_level_exclude_newer_package)
4728 .unwrap_or_default();
4729 let link_mode = link_mode.combine(top_level_link_mode);
4730 let compile_bytecode = compile_bytecode.combine(top_level_compile_bytecode);
4731 let no_sources = no_sources.combine(top_level_no_sources);
4732 let no_sources_package = no_sources_package.combine(top_level_no_sources_package);
4733 let upgrade = upgrade.combine(top_level_upgrade);
4734 let upgrade_package = upgrade_package.combine(top_level_upgrade_package);
4735 let reinstall = reinstall.combine(top_level_reinstall);
4736 let reinstall_package = reinstall_package.combine(top_level_reinstall_package);
4737 let torch_backend = torch_backend.combine(top_level_torch_backend);
4738 let args_no_sources_package = args
4739 .no_sources_package
4740 .or(environment.no_sources_package.clone());
4741
4742 Self {
4743 index_locations: IndexLocations::new(
4744 args.index
4745 .into_iter()
4746 .flatten()
4747 .chain(args.extra_index_url.into_iter().flatten().map(Index::from))
4748 .chain(args.index_url.into_iter().map(Index::from))
4749 .chain(index.into_iter().flatten())
4750 .chain(extra_index_url.into_iter().flatten().map(Index::from))
4751 .chain(index_url.into_iter().map(Index::from))
4752 .collect(),
4753 args.find_links
4754 .combine(find_links)
4755 .into_iter()
4756 .flatten()
4757 .map(Index::from)
4758 .collect(),
4759 args.no_index.combine(no_index).unwrap_or_default(),
4760 ),
4761 extras: ExtrasSpecification::from_args(
4762 args.extra.combine(extra).unwrap_or_default(),
4763 args.no_extra.combine(no_extra).unwrap_or_default(),
4764 false,
4766 vec![],
4768 args.all_extras.combine(all_extras).unwrap_or_default(),
4769 ),
4770
4771 groups: args.group.combine(group).unwrap_or_default(),
4772 dependency_mode: if args.no_deps.combine(no_deps).unwrap_or_default() {
4773 DependencyMode::Direct
4774 } else {
4775 DependencyMode::Transitive
4776 },
4777 resolution: args.resolution.combine(resolution).unwrap_or_default(),
4778 prerelease: resolve_prerelease(
4779 args.prerelease.combine(prerelease).unwrap_or_default(),
4780 prerelease_package,
4781 ),
4782 fork_strategy: args
4783 .fork_strategy
4784 .combine(fork_strategy)
4785 .unwrap_or_default(),
4786 dependency_metadata: DependencyMetadata::from_entries(
4787 args.dependency_metadata
4788 .combine(dependency_metadata)
4789 .unwrap_or_default(),
4790 ),
4791 output_file: args.output_file.combine(output_file),
4792 no_strip_extras: args
4793 .no_strip_extras
4794 .combine(no_strip_extras)
4795 .unwrap_or_default(),
4796 no_strip_markers: args
4797 .no_strip_markers
4798 .combine(no_strip_markers)
4799 .unwrap_or_default(),
4800 no_annotate: args.no_annotate.combine(no_annotate).unwrap_or_default(),
4801 no_header: args.no_header.combine(no_header).unwrap_or_default(),
4802 custom_compile_command: args.custom_compile_command.combine(custom_compile_command),
4803 annotation_style: args
4804 .annotation_style
4805 .combine(annotation_style)
4806 .unwrap_or_default(),
4807 index_strategy: args
4808 .index_strategy
4809 .combine(index_strategy)
4810 .unwrap_or_default(),
4811 keyring_provider: args
4812 .keyring_provider
4813 .combine(keyring_provider)
4814 .unwrap_or_default(),
4815 generate_hashes: args
4816 .generate_hashes
4817 .combine(generate_hashes)
4818 .unwrap_or_default(),
4819 allow_empty_requirements: args
4820 .allow_empty_requirements
4821 .combine(allow_empty_requirements)
4822 .unwrap_or_default(),
4823 build_isolation: BuildIsolation::from_args(
4824 args.no_build_isolation,
4825 args.no_build_isolation_package.unwrap_or_default(),
4826 )
4827 .combine(BuildIsolation::from_args(
4828 no_build_isolation,
4829 no_build_isolation_package.unwrap_or_default(),
4830 ))
4831 .unwrap_or_default(),
4832 extra_build_dependencies: args
4833 .extra_build_dependencies
4834 .combine(extra_build_dependencies)
4835 .unwrap_or_default(),
4836 extra_build_variables: args
4837 .extra_build_variables
4838 .combine(extra_build_variables)
4839 .unwrap_or_default(),
4840 config_setting: args
4841 .config_settings
4842 .combine(config_settings)
4843 .unwrap_or_default(),
4844 config_settings_package: args
4845 .config_settings_package
4846 .combine(config_settings_package)
4847 .unwrap_or_default(),
4848 torch_backend: args.torch_backend.combine(torch_backend),
4849 cuda_driver_version: environment.cuda_driver_version.clone(),
4850 amd_gpu_architecture: environment.amd_gpu_architecture,
4851 python_version: args.python_version.combine(python_version),
4852 python_platform: args.python_platform.combine(python_platform),
4853 universal: args.universal.combine(universal).unwrap_or_default(),
4854 exclude_newer: ExcludeNewer::from_args(
4855 exclude_newer,
4856 exclude_newer_package.into_iter().map(Into::into).collect(),
4857 ),
4858 no_emit_package: args
4859 .no_emit_package
4860 .combine(no_emit_package)
4861 .unwrap_or_default(),
4862 emit_index_url: args
4863 .emit_index_url
4864 .combine(emit_index_url)
4865 .unwrap_or_default(),
4866 emit_find_links: args
4867 .emit_find_links
4868 .combine(emit_find_links)
4869 .unwrap_or_default(),
4870 emit_build_options: args
4871 .emit_build_options
4872 .combine(emit_build_options)
4873 .unwrap_or_default(),
4874 emit_marker_expression: args
4875 .emit_marker_expression
4876 .combine(emit_marker_expression)
4877 .unwrap_or_default(),
4878 emit_index_annotation: args
4879 .emit_index_annotation
4880 .combine(emit_index_annotation)
4881 .unwrap_or_default(),
4882 link_mode: args.link_mode.combine(link_mode).unwrap_or_default(),
4883 hash_checking: HashCheckingMode::from_args(
4884 args.require_hashes.combine(require_hashes),
4885 args.verify_hashes.combine(verify_hashes),
4886 ),
4887 python: args.python.combine(python),
4888 system: args.system.combine(system).unwrap_or_default(),
4889 break_system_packages: args
4890 .break_system_packages
4891 .combine(break_system_packages)
4892 .unwrap_or_default(),
4893 target: args.target.combine(target).map(Target::from),
4894 prefix: args.prefix.combine(prefix).map(Prefix::from),
4895 compile_bytecode: args
4896 .compile_bytecode
4897 .combine(compile_bytecode)
4898 .unwrap_or_default(),
4899 sources: NoSources::from_args(
4900 args.no_sources.combine(no_sources),
4901 args_no_sources_package
4902 .combine(no_sources_package)
4903 .unwrap_or_default(),
4904 ),
4905 strict: args.strict.combine(strict).unwrap_or_default(),
4906 upgrade: Upgrade::from_args(
4907 args.upgrade,
4908 args.upgrade_package
4909 .into_iter()
4910 .flatten()
4911 .map(Requirement::from)
4912 .collect(),
4913 Vec::new(),
4914 )
4915 .combine(Upgrade::from_args(
4916 upgrade,
4917 upgrade_package
4918 .into_iter()
4919 .flatten()
4920 .map(Requirement::from)
4921 .collect(),
4922 Vec::new(),
4923 ))
4924 .unwrap_or_default(),
4925 reinstall: Reinstall::from_args(
4926 args.reinstall,
4927 args.reinstall_package.unwrap_or_default(),
4928 )
4929 .combine(Reinstall::from_args(
4930 reinstall,
4931 reinstall_package.unwrap_or_default(),
4932 ))
4933 .unwrap_or_default(),
4934 build_options: BuildOptions::new(
4935 NoBinary::from_pip_args(args.no_binary.combine(no_binary).unwrap_or_default())
4936 .combine(NoBinary::from_args(
4937 top_level_no_binary,
4938 top_level_no_binary_package.unwrap_or_default(),
4939 )),
4940 NoBuild::from_pip_args(
4941 args.only_binary.combine(only_binary).unwrap_or_default(),
4942 args.no_build.combine(no_build).unwrap_or_default(),
4943 )
4944 .combine(NoBuild::from_args(
4945 top_level_no_build,
4946 top_level_no_build_package.unwrap_or_default(),
4947 )),
4948 ),
4949 install_mirrors: environment
4950 .install_mirrors
4951 .combine(filesystem_install_mirrors),
4952 }
4953 }
4954}
4955
4956#[derive(Clone)]
4958pub struct PublishSettings {
4959 pub files: Vec<String>,
4961 pub username: Option<String>,
4962 pub password: Option<String>,
4963 pub index: Option<String>,
4964 pub dry_run: bool,
4965 pub no_attestations: bool,
4966
4967 pub publish_url: DisplaySafeUrl,
4969 pub trusted_publishing: TrustedPublishing,
4970 pub keyring_provider: KeyringProviderType,
4971 pub check_url: Option<IndexUrl>,
4972
4973 pub index_locations: IndexLocations,
4975}
4976
4977impl fmt::Debug for PublishSettings {
4978 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4979 f.debug_struct("PublishSettings")
4980 .field("files", &self.files)
4981 .field("username", &self.username)
4982 .field("password", &self.password.as_ref().map(|_| "****"))
4983 .field("index", &self.index)
4984 .field("dry_run", &self.dry_run)
4985 .field("no_attestations", &self.no_attestations)
4986 .field("publish_url", &self.publish_url)
4987 .field("trusted_publishing", &self.trusted_publishing)
4988 .field("keyring_provider", &self.keyring_provider)
4989 .field("check_url", &self.check_url)
4990 .field("index_locations", &self.index_locations)
4991 .finish()
4992 }
4993}
4994
4995impl PublishSettings {
4996 pub fn resolve(args: PublishArgs, filesystem: Option<FilesystemOptions>) -> Self {
4998 let Options {
4999 publish, top_level, ..
5000 } = filesystem
5001 .map(FilesystemOptions::into_options)
5002 .unwrap_or_default();
5003
5004 let PublishOptions {
5005 publish_url,
5006 trusted_publishing,
5007 check_url,
5008 } = publish;
5009 let ResolverInstallerSchema {
5010 keyring_provider,
5011 index,
5012 extra_index_url,
5013 index_url,
5014 ..
5015 } = top_level;
5016
5017 let (username, password) = if let Some(token) = args.token {
5019 (Some("__token__".to_string()), Some(token))
5020 } else {
5021 (args.username, args.password)
5022 };
5023
5024 Self {
5025 files: args.files,
5026 username,
5027 password,
5028 dry_run: args.dry_run,
5029 no_attestations: args.no_attestations,
5030 publish_url: args
5031 .publish_url
5032 .combine(publish_url)
5033 .unwrap_or_else(|| DisplaySafeUrl::parse(PYPI_PUBLISH_URL).unwrap()),
5034 trusted_publishing: args
5035 .trusted_publishing
5036 .combine(trusted_publishing)
5037 .unwrap_or_default(),
5038 keyring_provider: args
5039 .keyring_provider
5040 .combine(keyring_provider)
5041 .unwrap_or_default(),
5042 check_url: args.check_url.combine(check_url),
5043 index: args.index,
5044 index_locations: IndexLocations::new(
5045 index
5046 .into_iter()
5047 .flatten()
5048 .chain(extra_index_url.into_iter().flatten().map(Index::from))
5049 .chain(index_url.into_iter().map(Index::from))
5050 .collect(),
5051 Vec::new(),
5052 false,
5053 ),
5054 }
5055 }
5056}
5057
5058#[derive(Debug, Clone)]
5060pub struct AuthLogoutSettings {
5061 pub service: Service,
5062 pub username: Option<String>,
5063}
5064
5065impl AuthLogoutSettings {
5066 pub fn resolve(args: AuthLogoutArgs) -> Self {
5068 Self {
5069 service: args.service,
5070 username: args.username,
5071 }
5072 }
5073}
5074
5075#[derive(Debug, Clone)]
5077pub struct AuthTokenSettings {
5078 pub service: Service,
5079 pub username: Option<String>,
5080}
5081
5082impl AuthTokenSettings {
5083 pub fn resolve(args: AuthTokenArgs) -> Self {
5085 Self {
5086 service: args.service,
5087 username: args.username,
5088 }
5089 }
5090}
5091
5092#[derive(Debug, Clone)]
5094pub struct AuthLoginSettings {
5095 pub service: Service,
5096 pub username: Option<String>,
5097 pub password: Option<String>,
5098 pub token: Option<String>,
5099}
5100
5101impl AuthLoginSettings {
5102 pub fn resolve(args: AuthLoginArgs) -> Self {
5104 Self {
5105 service: args.service,
5106 username: args.username,
5107 password: args.password,
5108 token: args.token,
5109 }
5110 }
5111}
5112
5113mod env {
5115 use uv_static::EnvVars;
5116 pub(super) const UV_PYTHON_DOWNLOADS: (&str, &str) = (
5117 EnvVars::UV_PYTHON_DOWNLOADS,
5118 "one of 'auto', 'true', 'manual', 'never', or 'false'",
5119 );
5120}
5121
5122fn env<T>((name, expected): (&str, &str)) -> Option<T>
5127where
5128 T: FromStr,
5129{
5130 let val = match std::env::var(name) {
5131 Ok(val) => val,
5132 Err(VarError::NotPresent) => return None,
5133 Err(VarError::NotUnicode(_)) => parse_failure(name, expected),
5134 };
5135 Some(
5136 val.parse()
5137 .unwrap_or_else(|_| parse_failure(name, expected)),
5138 )
5139}
5140
5141#[expect(clippy::exit, clippy::print_stderr)]
5143fn parse_failure(name: &str, expected: &str) -> ! {
5144 eprintln!("error: invalid value for {name}, expected {expected}");
5145 process::exit(1)
5146}
5147
5148#[cfg(test)]
5149mod tests {
5150 use crate::{IndexArgs, RegistryClientArgs};
5151
5152 use super::*;
5153
5154 #[test]
5155 fn upgrade_settings_target_only_requested_package() -> anyhow::Result<()> {
5156 let package = PackageName::from_str("anyio")?;
5157 let settings = UpgradeSettings::resolve(
5158 UpgradeArgs {
5159 packages: vec![package.clone()],
5160 exclude: Vec::new(),
5161 index_args: IndexArgs {
5162 index: None,
5163 default_index: None,
5164 index_url: None,
5165 extra_index_url: None,
5166 find_links: None,
5167 no_index: false,
5168 },
5169 registry_client: RegistryClientArgs {
5170 index_strategy: None,
5171 keyring_provider: None,
5172 },
5173 },
5174 None,
5175 EnvironmentOptions::new()?,
5176 )?;
5177 let expected = FxHashSet::from_iter([package]);
5178
5179 assert!(!settings.settings.upgrade.is_all());
5180 assert_eq!(settings.settings.upgrade.packages(), Some(&expected));
5181 Ok(())
5182 }
5183}