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::SafeUrl;
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_build_hash_checking, 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: requirement_files(constraints, environment.constraints.clone()),
1018 overrides: requirement_files(overrides, environment.overrides.clone()),
1019 build_constraints: requirement_files(
1020 build_constraints,
1021 environment.build_constraints.clone(),
1022 ),
1023 isolated,
1024 show_resolution,
1025 lfs,
1026 python: python.and_then(Maybe::into_option),
1027 python_platform,
1028 refresh: Refresh::try_from(refresh)?,
1029 settings,
1030 options,
1031 install_mirrors: environment
1032 .install_mirrors
1033 .combine(filesystem_install_mirrors),
1034 env_file,
1035 no_env_file,
1036 })
1037 }
1038}
1039
1040#[derive(Debug, Clone)]
1042pub struct ToolInstallSettings {
1043 pub package: String,
1044 pub from: Option<String>,
1045 pub with: Vec<String>,
1046 pub with_requirements: Vec<RequirementsInput>,
1047 pub with_executables_from: Vec<String>,
1048 pub with_editable: Vec<String>,
1049 pub constraints: Vec<RequirementsInput>,
1050 pub overrides: Vec<RequirementsInput>,
1051 pub excludes: Vec<RequirementsInput>,
1052 pub build_constraints: Vec<RequirementsInput>,
1053 pub lfs: GitLfsSetting,
1054 pub python: Option<String>,
1055 pub python_platform: Option<TargetTriple>,
1056 pub refresh: Refresh,
1057 pub options: ResolverInstallerOptions,
1058 pub settings: ResolverInstallerSettings,
1059 pub force: bool,
1060 pub editable: bool,
1061 pub install_mirrors: PythonInstallMirrors,
1062}
1063
1064impl ToolInstallSettings {
1065 pub fn resolve(
1067 args: ToolInstallArgs,
1068 filesystem: Option<FilesystemOptions>,
1069 environment: EnvironmentOptions,
1070 ) -> anyhow::Result<Self> {
1071 let ToolInstallArgs {
1072 package,
1073 editable,
1074 from,
1075 with,
1076 with_editable,
1077 with_requirements,
1078 with_executables_from,
1079 constraints:
1080 DependencyConstraintsArgs {
1081 constraints,
1082 overrides,
1083 excludes,
1084 build_constraints,
1085 },
1086 lfs,
1087 installer,
1088 force,
1089 build,
1090 refresh,
1091 python,
1092 python_platform,
1093 torch_backend,
1094 } = args;
1095
1096 let filesystem_options = filesystem.map(FilesystemOptions::into_options);
1097
1098 let options = resolver_installer_options_with_environment(
1099 resolver_installer_options(
1100 installer,
1101 build,
1102 filesystem_options
1103 .as_ref()
1104 .and_then(|options| options.top_level.index.as_deref())
1105 .unwrap_or_default(),
1106 )?,
1107 &environment,
1108 )
1109 .combine(ResolverInstallerOptions::from(
1110 filesystem_options
1111 .as_ref()
1112 .map(|options| options.top_level.clone())
1113 .unwrap_or_default(),
1114 ));
1115
1116 let filesystem_install_mirrors = filesystem_options
1117 .map(|options| options.install_mirrors.clone())
1118 .unwrap_or_default();
1119
1120 let mut settings = ResolverInstallerSettings::from(options.clone());
1121 if torch_backend.is_some() {
1122 settings.resolver.torch_backend = torch_backend;
1123 }
1124 let lfs = GitLfsSetting::new(lfs.then_some(true), environment.lfs);
1125
1126 Ok(Self {
1127 package,
1128 from,
1129 with: with
1130 .into_iter()
1131 .flat_map(CommaSeparatedRequirements::into_iter)
1132 .collect(),
1133 with_editable: with_editable
1134 .into_iter()
1135 .flat_map(CommaSeparatedRequirements::into_iter)
1136 .collect(),
1137 with_requirements: with_requirements
1138 .into_iter()
1139 .filter_map(Maybe::into_option)
1140 .collect(),
1141 with_executables_from: with_executables_from
1142 .into_iter()
1143 .flat_map(CommaSeparatedRequirements::into_iter)
1144 .collect(),
1145 constraints: requirement_files(constraints, environment.constraints.clone()),
1146 overrides: requirement_files(overrides, environment.overrides.clone()),
1147 excludes: requirement_files(excludes, environment.excludes.clone()),
1148 build_constraints: requirement_files(
1149 build_constraints,
1150 environment.build_constraints.clone(),
1151 ),
1152 lfs,
1153 python: python.and_then(Maybe::into_option),
1154 python_platform,
1155 force,
1156 editable,
1157 refresh: Refresh::try_from(refresh)?,
1158 options,
1159 settings,
1160 install_mirrors: environment
1161 .install_mirrors
1162 .combine(filesystem_install_mirrors),
1163 })
1164 }
1165}
1166
1167#[derive(Debug, Clone)]
1169pub struct ToolUpgradeSettings {
1170 pub names: Vec<String>,
1171 pub python: Option<String>,
1172 pub python_platform: Option<TargetTriple>,
1173 pub install_mirrors: PythonInstallMirrors,
1174 pub args: ResolverInstallerOptions,
1175 pub filesystem: ResolverInstallerOptions,
1176}
1177impl ToolUpgradeSettings {
1178 pub fn resolve(
1180 args: ToolUpgradeArgs,
1181 filesystem: Option<FilesystemOptions>,
1182 environment: &EnvironmentOptions,
1183 ) -> anyhow::Result<Self> {
1184 let ToolUpgradeArgs {
1185 name,
1186 python,
1187 python_platform,
1188 upgrade,
1189 upgrade_package,
1190 upgrade_group,
1191 index_args,
1192 all,
1193 reinstall,
1194 registry_client,
1195 version_selection,
1196 config_setting,
1197 config_setting_package: config_settings_package,
1198 build_isolation,
1199 exclude_newer,
1200 link_mode,
1201 compile_bytecode,
1202 sources,
1203 build,
1204 } = args;
1205
1206 if upgrade {
1207 warn_user_once!("`--upgrade` is enabled by default on `uv tool upgrade`");
1208 }
1209 if !upgrade_package.is_empty() {
1210 warn_user_once!("`--upgrade-package` is enabled by default on `uv tool upgrade`");
1211 }
1212
1213 let installer = ResolverInstallerArgs {
1215 index_args,
1216 upgrade: upgrade_package.is_empty(),
1217 no_upgrade: false,
1218 upgrade_package,
1219 upgrade_group,
1220 reinstall,
1221 registry_client,
1222 version_selection,
1223 config_setting,
1224 config_settings_package,
1225 build_isolation,
1226 exclude_newer,
1227 link_mode,
1228 compile_bytecode,
1229 sources,
1230 };
1231
1232 let args = resolver_installer_options_with_environment(
1233 resolver_installer_options(installer, build, configured_indexes(filesystem.as_ref()))?,
1234 environment,
1235 );
1236 let filesystem = filesystem.map(FilesystemOptions::into_options);
1237 let filesystem_install_mirrors = filesystem
1238 .as_ref()
1239 .map(|options| options.install_mirrors.clone())
1240 .unwrap_or_default();
1241 let top_level = ResolverInstallerOptions::from(
1242 filesystem
1243 .map(|options| options.top_level)
1244 .unwrap_or_default(),
1245 );
1246
1247 Ok(Self {
1248 names: if all { vec![] } else { name },
1249 python: python.and_then(Maybe::into_option),
1250 python_platform,
1251 args,
1252 filesystem: top_level,
1253 install_mirrors: environment
1254 .install_mirrors
1255 .clone()
1256 .combine(filesystem_install_mirrors),
1257 })
1258 }
1259}
1260
1261#[derive(Debug, Clone)]
1263pub struct ToolListSettings {
1264 pub show_paths: bool,
1265 pub show_version_specifiers: bool,
1266 pub show_with: bool,
1267 pub show_extras: bool,
1268 pub show_python: bool,
1269 pub outdated: bool,
1270 pub args: ResolverInstallerOptions,
1271 pub filesystem: ResolverInstallerOptions,
1272}
1273
1274impl ToolListSettings {
1275 pub fn resolve(
1277 args: ToolListArgs,
1278 filesystem: Option<FilesystemOptions>,
1279 ) -> anyhow::Result<Self> {
1280 let ToolListArgs {
1281 show_paths,
1282 show_version_specifiers,
1283 show_with,
1284 show_extras,
1285 show_python,
1286 outdated,
1287 no_outdated,
1288 exclude_newer:
1289 PackageExcludeNewerArgs {
1290 exclude_newer: ExcludeNewerArgs { exclude_newer },
1291 exclude_newer_package,
1292 },
1293 python_preference: _,
1294 no_python_downloads: _,
1295 } = args;
1296
1297 let top_level = filesystem
1298 .map(FilesystemOptions::into_options)
1299 .map(|options| options.top_level)
1300 .unwrap_or_default();
1301 let filesystem = ResolverInstallerOptions {
1302 indexes: IndexOptions {
1303 index: top_level.index,
1304 ..IndexOptions::default()
1305 },
1306 exclude_newer: top_level.exclude_newer,
1307 exclude_newer_package: top_level.exclude_newer_package,
1308 ..ResolverInstallerOptions::default()
1309 };
1310
1311 Ok(Self {
1312 show_paths,
1313 show_version_specifiers,
1314 show_with,
1315 show_extras,
1316 show_python,
1317 outdated: flag(outdated, no_outdated, "outdated")?.unwrap_or(false),
1318 args: ResolverInstallerOptions {
1319 exclude_newer,
1320 exclude_newer_package: exclude_newer_package.map(ExcludeNewerPackage::from_iter),
1321 ..ResolverInstallerOptions::default()
1322 },
1323 filesystem,
1324 })
1325 }
1326}
1327
1328#[derive(Debug, Clone)]
1330pub struct ToolAuditSettings {
1331 pub names: Vec<PackageName>,
1332 pub output_format: AuditOutputFormat,
1333 pub service_format: VulnerabilityServiceFormat,
1334 pub service_url: Option<SafeUrl>,
1335 pub ignore: Vec<VulnerabilityID>,
1336 pub ignore_until_fixed: Vec<VulnerabilityID>,
1337 pub filesystem: ResolverInstallerOptions,
1338}
1339
1340impl ToolAuditSettings {
1341 pub fn resolve(args: ToolAuditArgs, filesystem: Option<FilesystemOptions>) -> Self {
1343 let ToolAuditArgs {
1344 name,
1345 all,
1346 audit:
1347 AuditCommonArgs {
1348 offline: _,
1349 output_format,
1350 ignore,
1351 ignore_until_fixed,
1352 service_format,
1353 service_url,
1354 },
1355 } = args;
1356
1357 let audit = filesystem
1358 .as_ref()
1359 .and_then(|options| options.audit.clone())
1360 .unwrap_or_default();
1361 let filesystem = filesystem
1362 .map(FilesystemOptions::into_options)
1363 .map(|options| ResolverInstallerOptions::from(options.top_level))
1364 .unwrap_or_default();
1365
1366 let ignore = ignore
1367 .into_iter()
1368 .chain(audit.ignore.unwrap_or_default())
1369 .map(VulnerabilityID::new)
1370 .collect();
1371 let ignore_until_fixed = ignore_until_fixed
1372 .into_iter()
1373 .chain(audit.ignore_until_fixed.unwrap_or_default())
1374 .map(VulnerabilityID::new)
1375 .collect();
1376
1377 Self {
1378 names: if all { vec![] } else { name },
1379 output_format,
1380 service_format,
1381 service_url,
1382 ignore,
1383 ignore_until_fixed,
1384 filesystem,
1385 }
1386 }
1387}
1388
1389#[derive(Debug, Clone)]
1391pub struct ToolUninstallSettings {
1392 pub name: Vec<PackageName>,
1393}
1394
1395impl ToolUninstallSettings {
1396 pub fn resolve(args: ToolUninstallArgs, _filesystem: Option<FilesystemOptions>) -> Self {
1398 let ToolUninstallArgs { name, all } = args;
1399
1400 Self {
1401 name: if all { vec![] } else { name },
1402 }
1403 }
1404}
1405
1406#[derive(Debug, Clone)]
1408pub struct ToolDirSettings {
1409 pub bin: bool,
1410}
1411
1412impl ToolDirSettings {
1413 #[expect(clippy::needless_pass_by_value)]
1415 pub fn resolve(args: ToolDirArgs, _filesystem: Option<FilesystemOptions>) -> Self {
1416 let ToolDirArgs { bin } = args;
1417
1418 Self { bin }
1419 }
1420}
1421
1422#[derive(Debug, Clone)]
1424pub struct PythonListSettings {
1425 pub request: Option<String>,
1426 pub kinds: PythonListKinds,
1427 pub all_platforms: bool,
1428 pub all_arches: bool,
1429 pub all_versions: bool,
1430 pub show_urls: bool,
1431 pub output_format: PythonListFormat,
1432 pub install_mirrors: PythonInstallMirrors,
1433}
1434
1435impl PythonListSettings {
1436 pub fn resolve(
1438 args: PythonListArgs,
1439 filesystem: Option<FilesystemOptions>,
1440 environment: EnvironmentOptions,
1441 ) -> Self {
1442 let PythonListArgs {
1443 request,
1444 all_versions,
1445 all_platforms,
1446 all_arches,
1447 only_installed,
1448 only_downloads,
1449 show_urls,
1450 output_format,
1451 python_downloads_json_url: python_downloads_json_url_arg,
1452 } = args;
1453
1454 let filesystem_install_mirrors = filesystem
1455 .map(|fs| fs.install_mirrors.clone())
1456 .unwrap_or_default();
1457
1458 let install_mirrors = PythonInstallMirrors {
1459 python_downloads_json_url: python_downloads_json_url_arg,
1460 ..Default::default()
1461 }
1462 .combine(environment.install_mirrors)
1463 .combine(filesystem_install_mirrors);
1464
1465 let kinds = if only_installed {
1466 PythonListKinds::Installed
1467 } else if only_downloads {
1468 PythonListKinds::Downloads
1469 } else {
1470 PythonListKinds::default()
1471 };
1472
1473 Self {
1474 request,
1475 kinds,
1476 all_platforms,
1477 all_arches,
1478 all_versions,
1479 show_urls,
1480 output_format,
1481 install_mirrors,
1482 }
1483 }
1484}
1485
1486#[derive(Debug, Clone)]
1488pub struct PythonDirSettings {
1489 pub bin: bool,
1490}
1491
1492impl PythonDirSettings {
1493 #[expect(clippy::needless_pass_by_value)]
1495 pub fn resolve(args: PythonDirArgs, _filesystem: Option<FilesystemOptions>) -> Self {
1496 let PythonDirArgs { bin } = args;
1497
1498 Self { bin }
1499 }
1500}
1501
1502#[derive(Debug, Clone)]
1504pub struct PythonInstallSettings {
1505 pub install_dir: Option<PathBuf>,
1506 pub targets: Vec<String>,
1507 pub reinstall: bool,
1508 pub force: bool,
1509 pub upgrade: PythonUpgrade,
1510 pub bin: Option<bool>,
1511 pub registry: Option<bool>,
1512 pub install_mirrors: PythonInstallMirrors,
1513 pub default: bool,
1514 pub compile_bytecode: bool,
1515}
1516
1517impl PythonInstallSettings {
1518 pub fn resolve(
1520 args: PythonInstallArgs,
1521 filesystem: Option<FilesystemOptions>,
1522 environment: EnvironmentOptions,
1523 ) -> anyhow::Result<Self> {
1524 let filesystem_install_mirrors = filesystem
1525 .map(|fs| fs.install_mirrors.clone())
1526 .unwrap_or_default();
1527
1528 let install_mirrors = args
1529 .install_mirrors()
1530 .combine(environment.install_mirrors)
1531 .combine(filesystem_install_mirrors);
1532
1533 let PythonInstallArgs {
1534 install_dir,
1535 targets,
1536 reinstall,
1537 bin,
1538 no_bin,
1539 registry,
1540 no_registry,
1541 force,
1542 upgrade,
1543 mirror: _,
1544 pypy_mirror: _,
1545 graalpy_mirror: _,
1546 pyodide_mirror: _,
1547 python_downloads_json_url: _,
1548 default,
1549 compile_bytecode,
1550 } = args;
1551
1552 Ok(Self {
1553 install_dir,
1554 targets,
1555 reinstall,
1556 force,
1557 upgrade: if upgrade {
1558 PythonUpgrade::Enabled(PythonUpgradeSource::Install)
1559 } else {
1560 PythonUpgrade::Disabled
1561 },
1562 bin: flag(bin, no_bin, "bin")?.or(environment.python_install_bin),
1563 registry: match flag(registry, no_registry, "registry")? {
1564 Some(registry) => Some(registry),
1565 None => environment.python_install_registry.or(
1566 if environment.python_no_registry.value == Some(true) {
1567 Some(false)
1568 } else {
1569 None
1570 },
1571 ),
1572 },
1573 install_mirrors,
1574 default,
1575 compile_bytecode: flag(
1576 compile_bytecode.compile_bytecode,
1577 compile_bytecode.no_compile_bytecode,
1578 "compile-bytecode",
1579 )?
1580 .unwrap_or_default(),
1581 })
1582 }
1583}
1584
1585#[expect(clippy::struct_excessive_bools)]
1587#[derive(Debug, Clone)]
1588pub struct PythonUpgradeSettings {
1589 pub install_dir: Option<PathBuf>,
1590 pub targets: Vec<String>,
1591 pub force: bool,
1592 pub registry: Option<bool>,
1593 pub install_mirrors: PythonInstallMirrors,
1594 pub reinstall: bool,
1595 pub default: bool,
1596 pub bin: Option<bool>,
1597 pub compile_bytecode: bool,
1598}
1599
1600impl PythonUpgradeSettings {
1601 pub fn resolve(
1603 args: PythonUpgradeArgs,
1604 filesystem: Option<FilesystemOptions>,
1605 environment: EnvironmentOptions,
1606 ) -> anyhow::Result<Self> {
1607 let filesystem_install_mirrors = filesystem
1608 .map(|fs| fs.install_mirrors.clone())
1609 .unwrap_or_default();
1610
1611 let install_mirrors = args
1612 .install_mirrors()
1613 .combine(environment.install_mirrors)
1614 .combine(filesystem_install_mirrors);
1615
1616 let force = false;
1617 let default = false;
1618 let bin = None;
1619 let registry = environment.python_install_registry.or(
1620 if environment.python_no_registry.value == Some(true) {
1621 Some(false)
1622 } else {
1623 None
1624 },
1625 );
1626
1627 let PythonUpgradeArgs {
1628 install_dir,
1629 targets,
1630 mirror: _,
1631 pypy_mirror: _,
1632 graalpy_mirror: _,
1633 pyodide_mirror: _,
1634 reinstall,
1635 python_downloads_json_url: _,
1636 compile_bytecode,
1637 } = args;
1638
1639 Ok(Self {
1640 install_dir,
1641 targets,
1642 force,
1643 registry,
1644 install_mirrors,
1645 reinstall,
1646 default,
1647 bin,
1648 compile_bytecode: flag(
1649 compile_bytecode.compile_bytecode,
1650 compile_bytecode.no_compile_bytecode,
1651 "compile-bytecode",
1652 )?
1653 .unwrap_or_default(),
1654 })
1655 }
1656}
1657
1658#[derive(Debug, Clone)]
1660pub struct PythonUninstallSettings {
1661 pub install_dir: Option<PathBuf>,
1662 pub targets: Vec<String>,
1663 pub all: bool,
1664}
1665
1666impl PythonUninstallSettings {
1667 pub fn resolve(args: PythonUninstallArgs, _filesystem: Option<FilesystemOptions>) -> Self {
1669 let PythonUninstallArgs {
1670 install_dir,
1671 targets,
1672 all,
1673 } = args;
1674
1675 Self {
1676 install_dir,
1677 targets,
1678 all,
1679 }
1680 }
1681}
1682
1683#[derive(Debug, Clone)]
1685pub struct PythonFindSettings {
1686 pub request: Option<String>,
1687 pub show_version: bool,
1688 pub resolve_links: bool,
1689 pub no_project: bool,
1690 pub system: bool,
1691 pub python_downloads_json_url: Option<String>,
1692}
1693
1694impl PythonFindSettings {
1695 pub fn resolve(
1697 args: PythonFindArgs,
1698 filesystem: Option<FilesystemOptions>,
1699 environment: EnvironmentOptions,
1700 ) -> anyhow::Result<Self> {
1701 let PythonFindArgs {
1702 request,
1703 show_version,
1704 resolve_links,
1705 no_project,
1706 system,
1707 no_system,
1708 script: _,
1709 python_downloads_json_url,
1710 } = args;
1711
1712 let filesystem_install_mirrors = filesystem
1713 .map(|fs| fs.install_mirrors.clone())
1714 .unwrap_or_default();
1715
1716 let install_mirrors = PythonInstallMirrors {
1717 python_downloads_json_url,
1718 ..Default::default()
1719 }
1720 .combine(environment.install_mirrors)
1721 .combine(filesystem_install_mirrors);
1722
1723 let PythonInstallMirrors {
1724 python_install_mirror: _,
1725 pypy_install_mirror: _,
1726 graalpy_install_mirror: _,
1727 pyodide_install_mirror: _,
1728 python_downloads_json_url,
1729 } = install_mirrors;
1730
1731 Ok(Self {
1732 request,
1733 show_version,
1734 resolve_links,
1735 no_project,
1736 system: flag(system, no_system, "system")?.unwrap_or_default(),
1737 python_downloads_json_url,
1738 })
1739 }
1740}
1741
1742#[derive(Debug, Clone)]
1744pub struct PythonPinSettings {
1745 pub request: Option<String>,
1746 pub resolved: bool,
1747 pub no_project: bool,
1748 pub global: bool,
1749 pub rm: bool,
1750 pub install_mirrors: PythonInstallMirrors,
1751}
1752
1753impl PythonPinSettings {
1754 pub fn resolve(
1756 args: PythonPinArgs,
1757 filesystem: Option<FilesystemOptions>,
1758 environment: EnvironmentOptions,
1759 ) -> anyhow::Result<Self> {
1760 let PythonPinArgs {
1761 request,
1762 no_resolved,
1763 resolved,
1764 no_project,
1765 global,
1766 rm,
1767 python_downloads_json_url,
1768 } = args;
1769
1770 let filesystem_install_mirrors = filesystem
1771 .map(|fs| fs.install_mirrors.clone())
1772 .unwrap_or_default();
1773
1774 let install_mirrors = PythonInstallMirrors {
1775 python_downloads_json_url,
1776 ..Default::default()
1777 }
1778 .combine(environment.install_mirrors)
1779 .combine(filesystem_install_mirrors);
1780
1781 Ok(Self {
1782 request,
1783 resolved: flag(resolved, no_resolved, "resolved")?.unwrap_or(false),
1784 no_project,
1785 global,
1786 rm,
1787 install_mirrors,
1788 })
1789 }
1790}
1791
1792#[derive(Debug, Clone)]
1794pub struct SyncSettings {
1795 pub lock_check: LockCheck,
1796 pub frozen: Option<FrozenSource>,
1797 pub dry_run: DryRun,
1798 pub script: Option<PathBuf>,
1799 pub active: ActiveEnvironment,
1800 pub extras: ExtrasSpecification,
1801 pub groups: DependencyGroups,
1802 pub editable: Option<EditableMode>,
1803 pub install_options: InstallOptions,
1804 pub modifications: Modifications,
1805 pub all_packages: bool,
1806 pub package: Vec<PackageName>,
1807 pub python: Option<String>,
1808 pub python_platform: Option<TargetTriple>,
1809 pub install_mirrors: PythonInstallMirrors,
1810 pub refresh: Refresh,
1811 pub settings: ResolverInstallerSettings,
1812 pub output_format: SyncFormat,
1813 pub malware_settings: MalwareCheckSettings,
1814}
1815
1816impl SyncSettings {
1817 pub fn resolve(
1819 args: SyncArgs,
1820 filesystem: Option<FilesystemOptions>,
1821 environment: EnvironmentOptions,
1822 ) -> anyhow::Result<Self> {
1823 let SyncArgs {
1824 extra,
1825 all_extras,
1826 no_extra,
1827 no_all_extras,
1828 dependency_groups:
1829 ProjectDependencyGroupsArgs {
1830 dev,
1831 no_dev,
1832 only_dev,
1833 group,
1834 no_group,
1835 no_default_groups,
1836 only_group,
1837 all_groups,
1838 },
1839 editable,
1840 no_editable,
1841 no_editable_package,
1842 inexact,
1843 exact,
1844 no_install_project,
1845 only_install_project,
1846 no_install_workspace,
1847 only_install_workspace,
1848 no_install_local,
1849 only_install_local,
1850 no_install_package,
1851 only_install_package,
1852 locked,
1853 no_locked,
1854 frozen,
1855 no_frozen,
1856 active,
1857 no_active,
1858 dry_run,
1859 installer,
1860 build,
1861 refresh,
1862 all_packages,
1863 package,
1864 script,
1865 python,
1866 python_platform,
1867 check,
1868 no_check,
1869 output_format,
1870 } = args;
1871 let filesystem_install_mirrors = filesystem
1872 .as_ref()
1873 .map(|fs| fs.install_mirrors.clone())
1874 .unwrap_or_default();
1875
1876 let malware_settings = MalwareCheckSettings::resolve(filesystem.as_ref(), &environment);
1877 let settings =
1878 resolve_resolver_installer_settings(installer, build, filesystem, &environment)?;
1879
1880 let check = flag(check, no_check, "check")?.unwrap_or_default();
1881 let dry_run = if check {
1882 DryRun::Check
1883 } else {
1884 DryRun::from_args(dry_run)
1885 };
1886
1887 let locked = resolve_lock_check(locked, no_locked, LockedFlag::Locked, environment.locked);
1889 let frozen = resolve_frozen(frozen, no_frozen, FrozenFlag::Frozen, environment.frozen);
1890
1891 let (locked, frozen) = resolve_lock_flags(locked, frozen)?;
1892
1893 let (dev, no_dev) = resolve_flag_pair(
1894 dev,
1895 no_dev,
1896 "dev",
1897 "no-dev",
1898 Some(environment.dev),
1899 Some(environment.no_dev),
1900 );
1901 let (editable, no_editable) = resolve_flag_pair(
1902 editable,
1903 no_editable,
1904 "editable",
1905 "no-editable",
1906 None,
1907 Some(environment.no_editable),
1908 );
1909
1910 let (no_install_project, only_install_project) = resolve_flag_pair(
1911 no_install_project,
1912 only_install_project,
1913 "no-install-project",
1914 "only-install-project",
1915 Some(environment.no_install_project),
1916 Some(environment.only_install_project),
1917 );
1918 let (no_install_workspace, only_install_workspace) = resolve_flag_pair(
1919 no_install_workspace,
1920 only_install_workspace,
1921 "no-install-workspace",
1922 "only-install-workspace",
1923 Some(environment.no_install_workspace),
1924 Some(environment.only_install_workspace),
1925 );
1926 let (no_install_local, only_install_local) = resolve_flag_pair(
1927 no_install_local,
1928 only_install_local,
1929 "no-install-local",
1930 "only-install-local",
1931 Some(environment.no_install_local),
1932 Some(environment.only_install_local),
1933 );
1934 check_conflicts(no_install_project, only_install_project)?;
1935 check_conflicts(no_install_workspace, only_install_workspace)?;
1936 check_conflicts(no_install_local, only_install_local)?;
1937 if script.is_some() {
1938 let script = Flag::from_cli("script");
1939 check_conflicts(no_install_project, script)?;
1940 check_conflicts(no_install_workspace, script)?;
1941 check_conflicts(no_install_local, script)?;
1942 }
1943 let no_install_project = no_install_project.is_enabled();
1944 let only_install_project = only_install_project.is_enabled();
1945 let no_install_workspace = no_install_workspace.is_enabled();
1946 let only_install_workspace = only_install_workspace.is_enabled();
1947 let no_install_local = no_install_local.is_enabled();
1948 let only_install_local = only_install_local.is_enabled();
1949
1950 Ok(Self {
1951 output_format,
1952 lock_check: locked,
1953 frozen,
1954 dry_run,
1955 script,
1956 active: flag(active, no_active, "active")?.into(),
1957 extras: ExtrasSpecification::from_args(
1958 extra.unwrap_or_default(),
1959 no_extra,
1960 false,
1962 vec![],
1964 flag(all_extras, no_all_extras, "all-extras")?.unwrap_or_default(),
1965 ),
1966 groups: DependencyGroups::from_args(
1967 DevMode::from_args(dev.into(), no_dev.into(), only_dev),
1968 group,
1969 if no_group.is_empty() {
1970 environment.no_group.clone().unwrap_or_default()
1971 } else {
1972 no_group
1973 },
1974 no_default_groups,
1975 only_group,
1976 all_groups,
1977 ),
1978 editable: EditableMode::from_args(
1979 flag(editable.into(), no_editable.into(), "editable")?,
1980 no_editable_package,
1981 ),
1982 install_options: InstallOptions::new(
1983 no_install_project,
1984 only_install_project,
1985 no_install_workspace,
1986 only_install_workspace,
1987 no_install_local,
1988 only_install_local,
1989 no_install_package,
1990 only_install_package,
1991 ),
1992 modifications: if flag(exact, inexact, "inexact")?.unwrap_or(true) {
1993 Modifications::Exact
1994 } else {
1995 Modifications::Sufficient
1996 },
1997 all_packages,
1998 package,
1999 python: python.and_then(Maybe::into_option),
2000 python_platform,
2001 refresh: Refresh::try_from(refresh)?,
2002 settings,
2003 install_mirrors: environment
2004 .install_mirrors
2005 .combine(filesystem_install_mirrors),
2006 malware_settings,
2007 })
2008 }
2009}
2010
2011#[derive(Debug, Clone)]
2013pub struct LockSettings {
2014 pub lock_check: LockCheck,
2015 pub frozen: Option<FrozenSource>,
2016 pub dry_run: DryRun,
2017 pub script: Option<PathBuf>,
2018 pub python: Option<String>,
2019 pub install_mirrors: PythonInstallMirrors,
2020 pub refresh: Refresh,
2021 pub settings: ResolverSettings,
2022}
2023
2024impl LockSettings {
2025 pub fn resolve(
2027 args: LockArgs,
2028 filesystem: Option<FilesystemOptions>,
2029 environment: EnvironmentOptions,
2030 ) -> anyhow::Result<Self> {
2031 let LockArgs {
2032 check,
2033 locked,
2034 no_locked,
2035 check_exists,
2036 frozen,
2037 no_frozen,
2038 dry_run,
2039 script,
2040 resolver,
2041 build,
2042 refresh,
2043 python,
2044 } = args;
2045
2046 let filesystem_install_mirrors = filesystem
2047 .as_ref()
2048 .map(|fs| fs.install_mirrors.clone())
2049 .unwrap_or_default();
2050
2051 let locked = resolve_lock_check(
2053 locked || check,
2054 no_locked,
2055 if check {
2056 LockedFlag::Check
2057 } else {
2058 LockedFlag::Locked
2059 },
2060 environment.locked,
2061 );
2062 let frozen = resolve_frozen(
2063 frozen || check_exists,
2064 no_frozen,
2065 if check_exists {
2066 FrozenFlag::CheckExists
2067 } else {
2068 FrozenFlag::Frozen
2069 },
2070 environment.frozen,
2071 );
2072
2073 let (locked, frozen) = resolve_lock_flags(locked, frozen)?;
2074
2075 Ok(Self {
2076 lock_check: locked,
2077 frozen,
2078 dry_run: DryRun::from_args(dry_run),
2079 script,
2080 python: python.and_then(Maybe::into_option),
2081 refresh: Refresh::try_from(refresh)?,
2082 settings: resolve_resolver_settings(resolver, build, filesystem, &environment)?,
2083 install_mirrors: environment
2084 .install_mirrors
2085 .combine(filesystem_install_mirrors),
2086 })
2087 }
2088}
2089
2090#[derive(Debug, Clone)]
2092pub struct UpgradeSettings {
2093 pub packages: Vec<PackageName>,
2094 pub exclude: Vec<PackageName>,
2095 pub install_mirrors: PythonInstallMirrors,
2096 pub settings: ResolverSettings,
2097}
2098
2099impl UpgradeSettings {
2100 pub fn resolve(
2102 args: UpgradeArgs,
2103 filesystem: Option<FilesystemOptions>,
2104 environment: EnvironmentOptions,
2105 ) -> anyhow::Result<Self> {
2106 let filesystem_install_mirrors = filesystem
2107 .as_ref()
2108 .map(|fs| fs.install_mirrors.clone())
2109 .unwrap_or_default();
2110 let (packages, exclude, options) =
2111 upgrade_options(args, configured_indexes(filesystem.as_ref()))?;
2112 let mut settings = combine_resolver_settings(options, filesystem, &environment);
2113 settings.upgrade = if packages.is_empty() {
2114 Upgrade::default()
2115 } else {
2116 Upgrade::from_packages(packages.clone())
2117 };
2118
2119 Ok(Self {
2120 packages,
2121 exclude,
2122 install_mirrors: environment
2123 .install_mirrors
2124 .combine(filesystem_install_mirrors),
2125 settings,
2126 })
2127 }
2128}
2129
2130#[derive(Debug, Clone)]
2132pub struct MetadataSettings {
2133 #[expect(dead_code)]
2134 script: Option<PathBuf>,
2135 pub lock_check: LockCheck,
2136 pub frozen: Option<FrozenSource>,
2137 pub sync: Option<Modifications>,
2138 pub active: ActiveEnvironment,
2139 pub python: Option<String>,
2140 pub install_mirrors: PythonInstallMirrors,
2141 pub refresh: Refresh,
2142 pub settings: ResolverSettings,
2143 pub malware_settings: MalwareCheckSettings,
2144}
2145
2146impl MetadataSettings {
2147 pub fn resolve(
2149 args: Box<MetadataArgs>,
2150 filesystem: Option<FilesystemOptions>,
2151 environment: EnvironmentOptions,
2152 ) -> anyhow::Result<Self> {
2153 let MetadataArgs {
2154 script,
2155 locked,
2156 no_locked,
2157 frozen,
2158 no_frozen,
2159 resolver,
2160 build,
2161 refresh,
2162 sync,
2163 exact,
2164 active,
2165 python,
2166 } = *args;
2167
2168 let filesystem_install_mirrors = filesystem
2169 .as_ref()
2170 .map(|fs| fs.install_mirrors.clone())
2171 .unwrap_or_default();
2172
2173 let locked = resolve_lock_check(locked, no_locked, LockedFlag::Locked, environment.locked);
2175 let frozen = resolve_frozen(frozen, no_frozen, FrozenFlag::Frozen, environment.frozen);
2176
2177 let (locked, frozen) = resolve_lock_flags(locked, frozen)?;
2178
2179 let malware_settings = MalwareCheckSettings::resolve(filesystem.as_ref(), &environment);
2180
2181 Ok(Self {
2182 script,
2183 lock_check: locked,
2184 frozen,
2185 sync: sync.then_some(if exact {
2186 Modifications::Exact
2187 } else {
2188 Modifications::Sufficient
2189 }),
2190 active: Some(active).into(),
2191 python: python.and_then(Maybe::into_option),
2192 refresh: Refresh::try_from(refresh)?,
2193 settings: resolve_resolver_settings(resolver, build, filesystem, &environment)?,
2194 install_mirrors: environment
2195 .install_mirrors
2196 .combine(filesystem_install_mirrors),
2197 malware_settings,
2198 })
2199 }
2200}
2201
2202#[expect(clippy::struct_excessive_bools)]
2204#[derive(Debug, Clone)]
2205pub struct AddSettings {
2206 pub lock_check: LockCheck,
2207 pub frozen: Option<FrozenSource>,
2208 pub active: ActiveEnvironment,
2209 pub no_sync: bool,
2210 pub packages: Vec<String>,
2211 pub requirements: Vec<RequirementsInput>,
2212 pub constraints: Vec<RequirementsInput>,
2213 pub marker: Option<MarkerTree>,
2214 pub dependency_type: DependencyType,
2215 pub editable: Option<EditableMode>,
2216 pub extras: Vec<ExtraName>,
2217 pub raw: bool,
2218 pub bounds: Option<AddBoundsKind>,
2219 pub rev: Option<String>,
2220 pub tag: Option<String>,
2221 pub branch: Option<String>,
2222 pub lfs: GitLfsSetting,
2223 pub package: Option<PackageName>,
2224 pub script: Option<PathBuf>,
2225 pub python: Option<String>,
2226 pub workspace: Option<bool>,
2227 pub no_install_project: bool,
2228 pub only_install_project: bool,
2229 pub no_install_workspace: bool,
2230 pub only_install_workspace: bool,
2231 pub no_install_local: bool,
2232 pub only_install_local: bool,
2233 pub no_install_package: Vec<PackageName>,
2234 pub only_install_package: Vec<PackageName>,
2235 pub install_mirrors: PythonInstallMirrors,
2236 pub refresh: Refresh,
2237 pub indexes: Vec<Index>,
2238 pub settings: ResolverInstallerSettings,
2239 pub malware_settings: MalwareCheckSettings,
2240}
2241
2242impl AddSettings {
2243 pub fn resolve(
2245 args: AddArgs,
2246 filesystem: Option<FilesystemOptions>,
2247 environment: EnvironmentOptions,
2248 ) -> anyhow::Result<Self> {
2249 let AddArgs {
2250 packages,
2251 requirements,
2252 constraints,
2253 marker,
2254 dev,
2255 optional,
2256 group,
2257 editable,
2258 no_editable,
2259 no_editable_package,
2260 extra,
2261 raw,
2262 bounds,
2263 rev,
2264 tag,
2265 branch,
2266 lfs,
2267 no_sync,
2268 locked,
2269 no_locked,
2270 frozen,
2271 no_frozen,
2272 active,
2273 no_active,
2274 installer,
2275 build,
2276 refresh,
2277 package,
2278 script,
2279 python,
2280 workspace,
2281 no_workspace,
2282 no_install_project,
2283 only_install_project,
2284 no_install_workspace,
2285 only_install_workspace,
2286 no_install_local,
2287 only_install_local,
2288 no_install_package,
2289 only_install_package,
2290 } = args;
2291
2292 let dev = dev || environment.dev.value == Some(true);
2294 let (editable, no_editable) = resolve_flag_pair(
2295 editable,
2296 no_editable,
2297 "editable",
2298 "no-editable",
2299 None,
2300 Some(environment.no_editable),
2301 );
2302
2303 let (no_install_project, only_install_project) = resolve_flag_pair(
2304 no_install_project,
2305 only_install_project,
2306 "no-install-project",
2307 "only-install-project",
2308 Some(environment.no_install_project),
2309 Some(environment.only_install_project),
2310 );
2311 let (no_install_workspace, only_install_workspace) = resolve_flag_pair(
2312 no_install_workspace,
2313 only_install_workspace,
2314 "no-install-workspace",
2315 "only-install-workspace",
2316 Some(environment.no_install_workspace),
2317 Some(environment.only_install_workspace),
2318 );
2319 let (no_install_local, only_install_local) = resolve_flag_pair(
2320 no_install_local,
2321 only_install_local,
2322 "no-install-local",
2323 "only-install-local",
2324 Some(environment.no_install_local),
2325 Some(environment.only_install_local),
2326 );
2327 check_conflicts(no_install_project, only_install_project)?;
2328 check_conflicts(no_install_workspace, only_install_workspace)?;
2329 check_conflicts(no_install_local, only_install_local)?;
2330
2331 let dependency_type = if let Some(extra) = optional {
2332 DependencyType::Optional(extra)
2333 } else if let Some(group) = group {
2334 DependencyType::Group(group)
2335 } else if dev {
2336 DependencyType::Dev
2337 } else {
2338 DependencyType::Production
2339 };
2340
2341 if installer
2343 .index_args
2344 .index_url
2345 .as_ref()
2346 .is_some_and(Maybe::is_some)
2347 {
2348 if script.is_some() {
2349 warn_user_once!(
2350 "Indexes specified via `--index-url` will not be persisted to the script; use `--default-index` instead."
2351 );
2352 } else {
2353 warn_user_once!(
2354 "Indexes specified via `--index-url` will not be persisted to the `pyproject.toml` file; use `--default-index` instead."
2355 );
2356 }
2357 }
2358
2359 if installer
2360 .index_args
2361 .extra_index_url
2362 .as_ref()
2363 .is_some_and(|extra_index_url| extra_index_url.iter().any(Maybe::is_some))
2364 {
2365 if script.is_some() {
2366 warn_user_once!(
2367 "Indexes specified via `--extra-index-url` will not be persisted to the script; use `--index` instead."
2368 );
2369 } else {
2370 warn_user_once!(
2371 "Indexes specified via `--extra-index-url` will not be persisted to the `pyproject.toml` file; use `--index` instead."
2372 );
2373 }
2374 }
2375
2376 let filesystem_install_mirrors = filesystem
2377 .as_ref()
2378 .map(|fs| fs.install_mirrors.clone())
2379 .unwrap_or_default();
2380
2381 let bounds = bounds.or(filesystem.as_ref().and_then(|fs| fs.add.add_bounds));
2382 let lfs = GitLfsSetting::new(lfs.then_some(true), environment.lfs);
2383
2384 let locked = resolve_lock_check(locked, no_locked, LockedFlag::Locked, environment.locked);
2386 let frozen = resolve_frozen(frozen, no_frozen, FrozenFlag::Frozen, environment.frozen);
2387 let no_sync = resolve_flag(no_sync, "no-sync", environment.no_sync);
2388
2389 let (locked, frozen) = resolve_lock_flags(locked, frozen)?;
2390
2391 check_conflicts(no_sync, frozen.map_or(Flag::Disabled, Flag::from))?;
2393
2394 let no_install_package_flag = if no_install_package.is_empty() {
2395 Flag::disabled()
2396 } else {
2397 Flag::from_cli("no-install-package")
2398 };
2399 let only_install_package_flag = if only_install_package.is_empty() {
2400 Flag::disabled()
2401 } else {
2402 Flag::from_cli("only-install-package")
2403 };
2404
2405 for install_flag in [
2406 no_install_project,
2407 no_install_workspace,
2408 no_install_local,
2409 only_install_project,
2410 only_install_workspace,
2411 only_install_local,
2412 no_install_package_flag,
2413 only_install_package_flag,
2414 ] {
2415 check_conflicts(install_flag, frozen.map_or(Flag::Disabled, Flag::from))?;
2416 check_conflicts(install_flag, no_sync)?;
2417 }
2418
2419 let no_install_project = no_install_project.is_enabled();
2420 let only_install_project = only_install_project.is_enabled();
2421 let no_install_workspace = no_install_workspace.is_enabled();
2422 let only_install_workspace = only_install_workspace.is_enabled();
2423 let no_install_local = no_install_local.is_enabled();
2424 let only_install_local = only_install_local.is_enabled();
2425
2426 let malware_settings = MalwareCheckSettings::resolve(filesystem.as_ref(), &environment);
2427 let active = flag(active, no_active, "active")?.into();
2428 let workspace = flag(workspace, no_workspace, "workspace")?;
2429 let editable = EditableMode::from_args(
2430 flag(editable.into(), no_editable.into(), "editable")?,
2431 no_editable_package,
2432 );
2433 let refresh = Refresh::try_from(refresh)?;
2434 let options =
2435 resolver_installer_options(installer, build, configured_indexes(filesystem.as_ref()))?;
2436 let indexes = options.indexes.index.clone().unwrap_or_default();
2437
2438 Ok(Self {
2439 lock_check: locked,
2440 frozen,
2441 active,
2442 no_sync: no_sync.is_enabled(),
2443 packages,
2444 requirements,
2445 constraints: requirement_files(constraints, environment.constraints.clone()),
2446 marker,
2447 dependency_type,
2448 raw,
2449 bounds,
2450 rev,
2451 tag,
2452 branch,
2453 lfs,
2454 package,
2455 script,
2456 python: python.and_then(Maybe::into_option),
2457 workspace,
2458 no_install_project,
2459 only_install_project,
2460 no_install_workspace,
2461 only_install_workspace,
2462 no_install_local,
2463 only_install_local,
2464 no_install_package,
2465 only_install_package,
2466 editable,
2467 extras: extra.unwrap_or_default(),
2468 refresh,
2469 indexes,
2470 settings: combine_resolver_installer_settings(options, filesystem, &environment),
2471 install_mirrors: environment
2472 .install_mirrors
2473 .combine(filesystem_install_mirrors),
2474 malware_settings,
2475 })
2476 }
2477}
2478
2479#[derive(Debug, Clone)]
2481pub struct RemoveSettings {
2482 pub lock_check: LockCheck,
2483 pub frozen: Option<FrozenSource>,
2484 pub active: ActiveEnvironment,
2485 pub no_sync: bool,
2486 pub packages: Vec<PackageName>,
2487 pub dependency_type: DependencyType,
2488 pub package: Option<PackageName>,
2489 pub script: Option<PathBuf>,
2490 pub python: Option<String>,
2491 pub install_mirrors: PythonInstallMirrors,
2492 pub refresh: Refresh,
2493 pub settings: ResolverInstallerSettings,
2494 pub malware_settings: MalwareCheckSettings,
2495}
2496
2497impl RemoveSettings {
2498 pub fn resolve(
2500 args: RemoveArgs,
2501 filesystem: Option<FilesystemOptions>,
2502 environment: EnvironmentOptions,
2503 ) -> anyhow::Result<Self> {
2504 let RemoveArgs {
2505 dev,
2506 optional,
2507 packages,
2508 group,
2509 no_sync,
2510 locked,
2511 no_locked,
2512 frozen,
2513 no_frozen,
2514 active,
2515 no_active,
2516 installer,
2517 build,
2518 refresh,
2519 package,
2520 script,
2521 python,
2522 } = args;
2523
2524 let dev = dev || environment.dev.value == Some(true);
2526
2527 let dependency_type = if let Some(extra) = optional {
2528 DependencyType::Optional(extra)
2529 } else if let Some(group) = group {
2530 DependencyType::Group(group)
2531 } else if dev {
2532 DependencyType::Dev
2533 } else {
2534 DependencyType::Production
2535 };
2536
2537 let filesystem_install_mirrors = filesystem
2538 .as_ref()
2539 .map(|fs| fs.install_mirrors.clone())
2540 .unwrap_or_default();
2541
2542 let packages = packages
2543 .into_iter()
2544 .map(|requirement| requirement.name)
2545 .collect();
2546
2547 let locked = resolve_lock_check(locked, no_locked, LockedFlag::Locked, environment.locked);
2549 let frozen = resolve_frozen(frozen, no_frozen, FrozenFlag::Frozen, environment.frozen);
2550 let no_sync = resolve_flag(no_sync, "no-sync", environment.no_sync);
2551
2552 let (locked, frozen) = resolve_lock_flags(locked, frozen)?;
2553
2554 check_conflicts(no_sync, frozen.map_or(Flag::Disabled, Flag::from))?;
2556
2557 let malware_settings = MalwareCheckSettings::resolve(filesystem.as_ref(), &environment);
2558
2559 Ok(Self {
2560 lock_check: locked,
2561 frozen,
2562 active: flag(active, no_active, "active")?.into(),
2563 no_sync: no_sync.is_enabled(),
2564 packages,
2565 dependency_type,
2566 package,
2567 script,
2568 python: python.and_then(Maybe::into_option),
2569 refresh: Refresh::try_from(refresh)?,
2570 settings: resolve_resolver_installer_settings(
2571 installer,
2572 build,
2573 filesystem,
2574 &environment,
2575 )?,
2576 install_mirrors: environment
2577 .install_mirrors
2578 .combine(filesystem_install_mirrors),
2579 malware_settings,
2580 })
2581 }
2582}
2583
2584#[derive(Debug, Clone)]
2586pub struct VersionSettings {
2587 pub value: Option<String>,
2588 pub bump: Vec<VersionBumpSpec>,
2589 pub short: bool,
2590 pub output_format: VersionFormat,
2591 pub dry_run: bool,
2592 pub lock_check: LockCheck,
2593 pub frozen: Option<FrozenSource>,
2594 pub active: ActiveEnvironment,
2595 pub no_sync: bool,
2596 pub package: Option<PackageName>,
2597 pub python: Option<String>,
2598 pub install_mirrors: PythonInstallMirrors,
2599 pub refresh: Refresh,
2600 pub settings: ResolverInstallerSettings,
2601 pub malware_settings: MalwareCheckSettings,
2602}
2603
2604impl VersionSettings {
2605 pub fn resolve(
2607 args: VersionArgs,
2608 filesystem: Option<FilesystemOptions>,
2609 environment: EnvironmentOptions,
2610 ) -> anyhow::Result<Self> {
2611 let VersionArgs {
2612 value,
2613 bump,
2614 short,
2615 output_format,
2616 dry_run,
2617 no_sync,
2618 locked,
2619 no_locked,
2620 frozen,
2621 no_frozen,
2622 active,
2623 no_active,
2624 installer,
2625 build,
2626 refresh,
2627 package,
2628 python,
2629 } = args;
2630
2631 let filesystem_install_mirrors = filesystem
2632 .as_ref()
2633 .map(|fs| fs.install_mirrors.clone())
2634 .unwrap_or_default();
2635
2636 let locked = resolve_lock_check(locked, no_locked, LockedFlag::Locked, environment.locked);
2638 let frozen = resolve_frozen(frozen, no_frozen, FrozenFlag::Frozen, environment.frozen);
2639 let no_sync = resolve_flag(no_sync, "no-sync", environment.no_sync);
2640
2641 let (locked, frozen) = resolve_lock_flags(locked, frozen)?;
2642
2643 check_conflicts(no_sync, frozen.map_or(Flag::Disabled, Flag::from))?;
2645
2646 let malware_settings = MalwareCheckSettings::resolve(filesystem.as_ref(), &environment);
2647
2648 Ok(Self {
2649 value,
2650 bump,
2651 short,
2652 output_format,
2653 dry_run,
2654 lock_check: locked,
2655 frozen,
2656 active: flag(active, no_active, "active")?.into(),
2657 no_sync: no_sync.is_enabled(),
2658 package,
2659 python: python.and_then(Maybe::into_option),
2660 refresh: Refresh::try_from(refresh)?,
2661 settings: resolve_resolver_installer_settings(
2662 installer,
2663 build,
2664 filesystem,
2665 &environment,
2666 )?,
2667 install_mirrors: environment
2668 .install_mirrors
2669 .combine(filesystem_install_mirrors),
2670 malware_settings,
2671 })
2672 }
2673}
2674
2675#[derive(Debug, Clone)]
2677pub struct TreeSettings {
2678 pub groups: DependencyGroups,
2679 pub lock_check: LockCheck,
2680 pub frozen: Option<FrozenSource>,
2681 pub universal: bool,
2682 pub format: TreeFormat,
2683 pub depth: u8,
2684 pub prune: Vec<PackageName>,
2685 pub package: Vec<PackageName>,
2686 pub no_dedupe: bool,
2687 pub invert: bool,
2688 pub outdated: bool,
2689 pub show_sizes: bool,
2690 pub script: Option<PathBuf>,
2691 pub python_version: Option<PythonVersion>,
2692 pub python_platform: Option<TargetTriple>,
2693 pub python: Option<String>,
2694 pub install_mirrors: PythonInstallMirrors,
2695 pub resolver: ResolverSettings,
2696}
2697
2698impl TreeSettings {
2699 pub fn resolve(
2701 args: TreeArgs,
2702 filesystem: Option<FilesystemOptions>,
2703 environment: EnvironmentOptions,
2704 ) -> anyhow::Result<Self> {
2705 let TreeArgs {
2706 tree,
2707 universal,
2708 format,
2709 dependency_groups:
2710 ProjectDependencyGroupsArgs {
2711 dev,
2712 no_dev,
2713 only_dev,
2714 group,
2715 no_group,
2716 no_default_groups,
2717 only_group,
2718 all_groups,
2719 },
2720 locked,
2721 no_locked,
2722 frozen,
2723 no_frozen,
2724 build,
2725 resolver,
2726 script,
2727 python_version,
2728 python_platform,
2729 python,
2730 } = args;
2731
2732 let filesystem_install_mirrors = filesystem
2733 .as_ref()
2734 .map(|fs| fs.install_mirrors.clone())
2735 .unwrap_or_default();
2736
2737 let locked = resolve_lock_check(locked, no_locked, LockedFlag::Locked, environment.locked);
2739 let frozen = resolve_frozen(frozen, no_frozen, FrozenFlag::Frozen, environment.frozen);
2740
2741 let (locked, frozen) = resolve_lock_flags(locked, frozen)?;
2742
2743 let (dev, no_dev) = resolve_flag_pair(
2744 dev,
2745 no_dev,
2746 "dev",
2747 "no-dev",
2748 Some(environment.dev),
2749 Some(environment.no_dev),
2750 );
2751
2752 Ok(Self {
2753 groups: DependencyGroups::from_args(
2754 DevMode::from_args(dev.into(), no_dev.into(), only_dev),
2755 group,
2756 if no_group.is_empty() {
2757 environment.no_group.clone().unwrap_or_default()
2758 } else {
2759 no_group
2760 },
2761 no_default_groups,
2762 only_group,
2763 all_groups,
2764 ),
2765 lock_check: locked,
2766 frozen,
2767 universal,
2768 format,
2769 depth: tree.depth,
2770 prune: tree.prune,
2771 package: tree.package,
2772 no_dedupe: tree.no_dedupe,
2773 invert: tree.invert,
2774 outdated: tree.outdated,
2775 show_sizes: tree.show_sizes,
2776 script,
2777 python_version,
2778 python_platform,
2779 python: python.and_then(Maybe::into_option),
2780 resolver: resolve_resolver_settings(resolver, build, filesystem, &environment)?,
2781 install_mirrors: environment
2782 .install_mirrors
2783 .combine(filesystem_install_mirrors),
2784 })
2785 }
2786}
2787
2788#[expect(clippy::struct_excessive_bools)]
2790#[derive(Debug, Clone)]
2791pub struct ExportSettings {
2792 pub format: Option<ExportFormat>,
2793 pub all_packages: bool,
2794 pub package: Vec<PackageName>,
2795 pub prune: Vec<PackageName>,
2796 pub extras: ExtrasSpecification,
2797 pub groups: DependencyGroups,
2798 pub editable: Option<EditableMode>,
2799 pub hashes: bool,
2800 pub install_options: InstallOptions,
2801 pub batch: Option<PathBuf>,
2802 pub output_file: Option<PathBuf>,
2803 pub lock_check: LockCheck,
2804 pub frozen: Option<FrozenSource>,
2805 pub include_annotations: bool,
2806 pub include_header: bool,
2807 pub include_index_url: bool,
2808 pub include_find_links: bool,
2809 pub script: Option<PathBuf>,
2810 pub python: Option<String>,
2811 pub install_mirrors: PythonInstallMirrors,
2812 pub refresh: Refresh,
2813 pub settings: ResolverSettings,
2814}
2815
2816impl ExportSettings {
2817 pub fn resolve(
2819 args: ExportArgs,
2820 filesystem: Option<FilesystemOptions>,
2821 environment: EnvironmentOptions,
2822 ) -> anyhow::Result<Self> {
2823 let ExportArgs {
2824 format,
2825 all_packages,
2826 package,
2827 prune,
2828 extra,
2829 all_extras,
2830 no_extra,
2831 no_all_extras,
2832 dependency_groups:
2833 ProjectDependencyGroupsArgs {
2834 dev,
2835 no_dev,
2836 only_dev,
2837 group,
2838 no_group,
2839 no_default_groups,
2840 only_group,
2841 all_groups,
2842 },
2843 annotate,
2844 no_annotate,
2845 header,
2846 no_header,
2847 emit_index_url,
2848 no_emit_index_url,
2849 emit_find_links,
2850 no_emit_find_links,
2851 editable,
2852 no_editable,
2853 no_editable_package,
2854 hashes,
2855 no_hashes,
2856 batch,
2857 output_file,
2858 no_emit_project,
2859 only_emit_project,
2860 no_emit_workspace,
2861 only_emit_workspace,
2862 no_emit_local,
2863 only_emit_local,
2864 no_emit_package,
2865 only_emit_package,
2866 locked,
2867 no_locked,
2868 frozen: frozen_cli,
2869 no_frozen,
2870 resolver,
2871 build,
2872 refresh,
2873 script,
2874 python,
2875 } = args;
2876 let filesystem_install_mirrors = filesystem
2877 .as_ref()
2878 .map(|fs| fs.install_mirrors.clone())
2879 .unwrap_or_default();
2880
2881 let locked = resolve_lock_check(locked, no_locked, LockedFlag::Locked, environment.locked);
2883 let frozen = resolve_frozen(
2884 frozen_cli,
2885 no_frozen,
2886 FrozenFlag::Frozen,
2887 environment.frozen,
2888 );
2889
2890 let (locked, frozen) = resolve_lock_flags(locked, frozen)?;
2891
2892 let (dev, no_dev) = resolve_flag_pair(
2893 dev,
2894 no_dev,
2895 "dev",
2896 "no-dev",
2897 Some(environment.dev),
2898 Some(environment.no_dev),
2899 );
2900 let (editable, no_editable) = resolve_flag_pair(
2901 editable,
2902 no_editable,
2903 "editable",
2904 "no-editable",
2905 None,
2906 Some(environment.no_editable),
2907 );
2908
2909 Ok(Self {
2910 format,
2911 all_packages,
2912 package,
2913 prune,
2914 extras: ExtrasSpecification::from_args(
2915 extra.unwrap_or_default(),
2916 no_extra,
2917 false,
2919 vec![],
2921 flag(all_extras, no_all_extras, "all-extras")?.unwrap_or_default(),
2922 ),
2923 groups: DependencyGroups::from_args(
2924 DevMode::from_args(dev.into(), no_dev.into(), only_dev),
2925 group,
2926 if no_group.is_empty() {
2927 environment.no_group.clone().unwrap_or_default()
2928 } else {
2929 no_group
2930 },
2931 no_default_groups,
2932 only_group,
2933 all_groups,
2934 ),
2935 editable: EditableMode::from_args(
2936 flag(editable.into(), no_editable.into(), "editable")?,
2937 no_editable_package,
2938 ),
2939 hashes: flag(hashes, no_hashes, "hashes")?.unwrap_or(true),
2940 install_options: InstallOptions::new(
2941 no_emit_project,
2942 only_emit_project,
2943 no_emit_workspace,
2944 only_emit_workspace,
2945 no_emit_local,
2946 only_emit_local,
2947 no_emit_package,
2948 only_emit_package,
2949 ),
2950 batch,
2951 output_file,
2952 lock_check: locked,
2953 frozen,
2954 include_annotations: flag(annotate, no_annotate, "annotate")?.unwrap_or(true),
2955 include_header: flag(header, no_header, "header")?.unwrap_or(true),
2956 include_index_url: flag(emit_index_url, no_emit_index_url, "emit-index-url")?
2957 .unwrap_or(false),
2958 include_find_links: flag(emit_find_links, no_emit_find_links, "emit-find-links")?
2959 .unwrap_or(false),
2960 script,
2961 python: python.and_then(Maybe::into_option),
2962 refresh: Refresh::try_from(refresh)?,
2963 settings: resolve_resolver_settings(resolver, build, filesystem, &environment)?,
2964 install_mirrors: environment
2965 .install_mirrors
2966 .combine(filesystem_install_mirrors),
2967 })
2968 }
2969}
2970
2971#[derive(Debug, Clone)]
2973pub struct FormatSettings {
2974 pub ruff_path: Option<PathBuf>,
2975 pub check: bool,
2976 pub diff: bool,
2977 pub extra_args: Vec<String>,
2978 pub version: Option<String>,
2979 pub exclude_newer: Option<jiff::Timestamp>,
2980 pub no_project: bool,
2981 pub show_version: bool,
2982}
2983
2984impl FormatSettings {
2985 pub fn resolve(
2987 args: FormatArgs,
2988 _filesystem: Option<FilesystemOptions>,
2989 environment: EnvironmentOptions,
2990 ) -> Self {
2991 let FormatArgs {
2992 check,
2993 diff,
2994 extra_args,
2995 version,
2996 exclude_newer,
2997 no_project,
2998 show_version,
2999 } = args;
3000
3001 Self {
3002 ruff_path: environment.ruff_path,
3003 check,
3004 diff,
3005 extra_args,
3006 version,
3007 exclude_newer: exclude_newer
3008 .and_then(ExcludeNewerOverride::into_value)
3009 .map(|value| value.timestamp()),
3010 no_project,
3011 show_version,
3012 }
3013 }
3014}
3015
3016#[derive(Debug, Clone)]
3018pub struct CheckSettings {
3019 pub ty_path: Option<PathBuf>,
3020 #[expect(dead_code)]
3021 script: Option<PathBuf>,
3022 pub fix: bool,
3023 pub all_packages: bool,
3024 pub package: Vec<PackageName>,
3025 pub extras: ExtrasSpecification,
3026 pub groups: DependencyGroups,
3027 pub lock_check: LockCheck,
3028 pub frozen: Option<FrozenSource>,
3029 pub no_sync: bool,
3030 pub no_install_project: bool,
3031 pub isolated: bool,
3032 pub python: Option<String>,
3033 pub install_mirrors: PythonInstallMirrors,
3034 pub refresh: Refresh,
3035 pub settings: ResolverInstallerSettings,
3036 pub ty_version: Option<String>,
3037 pub show_version: bool,
3038 pub show_command: bool,
3039 pub no_project: bool,
3040 pub malware_settings: MalwareCheckSettings,
3041}
3042
3043impl CheckSettings {
3044 pub fn resolve(
3046 args: CheckArgs,
3047 filesystem: Option<FilesystemOptions>,
3048 environment: EnvironmentOptions,
3049 ) -> anyhow::Result<Self> {
3050 let CheckArgs {
3051 fix,
3052 all_packages,
3053 package,
3054 script,
3055 extra,
3056 all_extras,
3057 no_extra,
3058 no_all_extras,
3059 dependency_groups:
3060 ProjectDependencyGroupsArgs {
3061 dev,
3062 no_dev,
3063 only_dev,
3064 group,
3065 no_group,
3066 no_default_groups,
3067 only_group,
3068 all_groups,
3069 },
3070 locked,
3071 no_locked,
3072 frozen,
3073 no_frozen,
3074 no_sync,
3075 no_install_project,
3076 isolated,
3077 python,
3078 ty_version,
3079 show_version,
3080 show_command,
3081 no_project,
3082 installer,
3083 build,
3084 refresh,
3085 } = args;
3086
3087 let filesystem_install_mirrors = filesystem
3088 .as_ref()
3089 .map(|fs| fs.install_mirrors.clone())
3090 .unwrap_or_default();
3091
3092 let locked = resolve_lock_check(locked, no_locked, LockedFlag::Locked, environment.locked);
3093 let frozen = resolve_frozen(frozen, no_frozen, FrozenFlag::Frozen, environment.frozen);
3094 let no_sync = resolve_flag(no_sync, "no-sync", environment.no_sync);
3095 let no_install_project = resolve_flag(
3096 no_install_project,
3097 "no-install-project",
3098 environment.no_install_project,
3099 );
3100 let isolated = resolve_flag(isolated, "isolated", environment.isolated).is_enabled();
3101 let (locked, frozen) = resolve_lock_flags(locked, frozen)?;
3102 check_conflicts(no_install_project, no_sync)?;
3103 if script.is_some() {
3104 check_conflicts(no_install_project, Flag::from_cli("script"))?;
3105 }
3106 if no_project {
3107 check_conflicts(no_install_project, Flag::from_cli("no-project"))?;
3108 }
3109
3110 let (dev, no_dev) = resolve_flag_pair(
3111 dev,
3112 no_dev,
3113 "dev",
3114 "no-dev",
3115 Some(environment.dev),
3116 Some(environment.no_dev),
3117 );
3118 let malware_settings = MalwareCheckSettings::resolve(filesystem.as_ref(), &environment);
3119 let settings =
3120 resolve_resolver_installer_settings(installer, build, filesystem, &environment)?;
3121 Ok(Self {
3122 ty_path: environment.ty_path,
3123 script,
3124 fix,
3125 all_packages,
3126 package,
3127 extras: ExtrasSpecification::from_args(
3128 extra.unwrap_or_default(),
3129 no_extra,
3130 false,
3131 vec![],
3132 flag(all_extras, no_all_extras, "all-extras")?.unwrap_or_default(),
3133 ),
3134 groups: DependencyGroups::from_args(
3135 DevMode::from_args(dev.into(), no_dev.into(), only_dev),
3136 group,
3137 if no_group.is_empty() {
3138 environment.no_group.clone().unwrap_or_default()
3139 } else {
3140 no_group
3141 },
3142 no_default_groups,
3143 only_group,
3144 all_groups,
3145 ),
3146 lock_check: locked,
3147 frozen,
3148 no_sync: no_sync.is_enabled(),
3149 no_install_project: no_install_project.is_enabled(),
3150 isolated,
3151 python: python.and_then(Maybe::into_option),
3152 install_mirrors: environment
3153 .install_mirrors
3154 .combine(filesystem_install_mirrors),
3155 refresh: Refresh::try_from(refresh)?,
3156 settings,
3157 ty_version,
3158 show_version,
3159 show_command,
3160 no_project,
3161 malware_settings,
3162 })
3163 }
3164}
3165
3166#[derive(Debug, Clone)]
3168pub struct AuditSettings {
3169 pub extras: ExtrasSpecification,
3170 pub groups: DependencyGroups,
3171 pub lock_check: LockCheck,
3172 pub frozen: Option<FrozenSource>,
3173 pub python_version: Option<PythonVersion>,
3174 pub python_platform: Option<TargetTriple>,
3175 pub install_mirrors: PythonInstallMirrors,
3176 pub settings: ResolverSettings,
3177 pub output_format: AuditOutputFormat,
3178 pub service_format: VulnerabilityServiceFormat,
3179 pub service_url: Option<SafeUrl>,
3180 pub ignore: Vec<VulnerabilityID>,
3181 pub ignore_until_fixed: Vec<VulnerabilityID>,
3182}
3183
3184impl AuditSettings {
3185 pub fn resolve(
3187 args: AuditArgs,
3188 filesystem: Option<FilesystemOptions>,
3189 environment: EnvironmentOptions,
3190 ) -> anyhow::Result<Self> {
3191 let AuditArgs {
3192 no_extra,
3193 no_dev,
3194 no_group,
3195 no_default_groups,
3196 only_group,
3197 only_dev,
3198 script: _,
3199 python_version,
3200 python_platform,
3201 locked,
3202 no_locked,
3203 frozen,
3204 no_frozen,
3205 audit:
3206 AuditCommonArgs {
3207 offline: _,
3208 output_format,
3209 ignore,
3210 ignore_until_fixed,
3211 service_format,
3212 service_url,
3213 },
3214 build,
3215 resolver,
3216 } = args;
3217
3218 let filesystem_install_mirrors = filesystem
3219 .as_ref()
3220 .map(|fs| fs.install_mirrors.clone())
3221 .unwrap_or_default();
3222
3223 let filesystem_audit = filesystem
3224 .as_ref()
3225 .and_then(|fs| fs.audit.clone())
3226 .unwrap_or_default();
3227
3228 let no_dev = no_dev || environment.no_dev.value == Some(true);
3229
3230 let locked = resolve_lock_check(locked, no_locked, LockedFlag::Locked, environment.locked);
3232 let frozen = resolve_frozen(frozen, no_frozen, FrozenFlag::Frozen, environment.frozen);
3233
3234 let (locked, frozen) = resolve_lock_flags(locked, frozen)?;
3235
3236 let all_groups = only_group.is_empty() && !only_dev && !no_default_groups;
3239
3240 Ok(Self {
3241 extras: ExtrasSpecification::from_args(
3242 vec![],
3243 no_extra,
3244 false,
3246 vec![],
3248 true,
3249 ),
3250 groups: DependencyGroups::from_args(
3251 DevMode::from_args(all_groups, no_dev, only_dev),
3252 vec![],
3253 if no_group.is_empty() {
3254 environment.no_group.clone().unwrap_or_default()
3255 } else {
3256 no_group
3257 },
3258 no_default_groups,
3259 only_group,
3260 all_groups,
3261 ),
3262 lock_check: locked,
3263 frozen,
3264 python_version,
3265 python_platform,
3266 settings: resolve_resolver_settings(resolver, build, filesystem, &environment)?,
3267 install_mirrors: environment
3268 .install_mirrors
3269 .combine(filesystem_install_mirrors),
3270 output_format,
3271 service_format,
3272 service_url,
3273 ignore: {
3274 let config_ignore = filesystem_audit.ignore.unwrap_or_default();
3275 let mut merged = ignore;
3276 merged.extend(config_ignore);
3277 merged.into_iter().map(VulnerabilityID::new).collect()
3278 },
3279 ignore_until_fixed: {
3280 let config_ignore_until_fixed =
3281 filesystem_audit.ignore_until_fixed.unwrap_or_default();
3282 let mut merged = ignore_until_fixed;
3283 merged.extend(config_ignore_until_fixed);
3284 merged.into_iter().map(VulnerabilityID::new).collect()
3285 },
3286 })
3287 }
3288}
3289
3290fn workspace_overrides(filesystem: Option<&FilesystemOptions>) -> Vec<Override<Requirement>> {
3291 let mut overrides = Vec::new();
3292 for dependency in filesystem
3293 .and_then(|configuration| configuration.override_dependencies.as_ref())
3294 .into_iter()
3295 .flatten()
3296 {
3297 match dependency {
3298 OverrideDependency::Requirement(requirement) => {
3299 overrides.push(Override::Requirement(Requirement::from(
3300 requirement
3301 .clone()
3302 .with_origin(RequirementOrigin::Workspace),
3303 )));
3304 }
3305 OverrideDependency::Package(package) => {
3306 overrides.push(Override::Package(PackageOverride {
3307 package: package.package.clone(),
3308 dependencies: package
3309 .dependencies
3310 .iter()
3311 .cloned()
3312 .map(|requirement| {
3313 Requirement::from(requirement.with_origin(RequirementOrigin::Workspace))
3314 })
3315 .collect(),
3316 }));
3317 }
3318 }
3319 }
3320 overrides
3321}
3322
3323fn requirement_files(
3326 arguments: Vec<Maybe<RequirementsInput>>,
3327 environment: Option<Vec<RequirementsInput>>,
3328) -> Vec<RequirementsInput> {
3329 if arguments.is_empty() {
3330 environment.unwrap_or_default()
3331 } else {
3332 arguments
3333 .into_iter()
3334 .filter_map(Maybe::into_option)
3335 .collect()
3336 }
3337}
3338
3339#[derive(Debug, Clone)]
3341pub struct PipCompileSettings {
3342 pub format: Option<PipCompileFormat>,
3343 pub src_file: Vec<RequirementsInput>,
3344 pub constraints: Vec<RequirementsInput>,
3345 pub overrides: Vec<RequirementsInput>,
3346 pub excludes: Vec<RequirementsInput>,
3347 pub build_constraints: Vec<RequirementsInput>,
3348 pub build_hash_checking: HashCheckingMode,
3349 pub constraints_from_workspace: Vec<Requirement>,
3350 pub overrides_from_workspace: Vec<Override<Requirement>>,
3351 pub excludes_from_workspace: Vec<ExcludeDependency>,
3352 pub build_constraints_from_workspace: Vec<NameRequirementSpecification>,
3353 pub environments: SupportedEnvironments,
3354 pub required_environments: SupportedEnvironments,
3355 pub minimum_libc_version: Option<MinimumLibcVersion>,
3356 pub refresh: Refresh,
3357 pub settings: PipSettings,
3358}
3359
3360impl PipCompileSettings {
3361 pub fn resolve(
3363 args: PipCompileArgs,
3364 filesystem: Option<FilesystemOptions>,
3365 environment: EnvironmentOptions,
3366 ) -> anyhow::Result<Self> {
3367 let PipCompileArgs {
3368 src_file,
3369 constraints:
3370 DependencyConstraintsArgs {
3371 constraints,
3372 overrides,
3373 excludes,
3374 build_constraints,
3375 },
3376 extra,
3377 all_extras,
3378 no_all_extras,
3379 require_build_hashes,
3380 no_require_build_hashes,
3381 refresh,
3382 no_deps,
3383 deps,
3384 group,
3385 output_file,
3386 format,
3387 no_strip_extras,
3388 strip_extras,
3389 no_strip_markers,
3390 strip_markers,
3391 no_annotate,
3392 annotate,
3393 no_header,
3394 header,
3395 annotation_style,
3396 custom_compile_command,
3397 resolver,
3398 python,
3399 system,
3400 no_system,
3401 generate_hashes,
3402 no_generate_hashes,
3403 no_build,
3404 build,
3405 no_binary,
3406 only_binary,
3407 python_version,
3408 python_platform,
3409 universal,
3410 no_universal,
3411 no_emit_package,
3412 emit_index_url,
3413 no_emit_index_url,
3414 emit_find_links,
3415 no_emit_find_links,
3416 emit_build_options,
3417 no_emit_build_options,
3418 emit_marker_expression,
3419 no_emit_marker_expression,
3420 emit_index_annotation,
3421 no_emit_index_annotation,
3422 torch_backend,
3423 compat_args: _,
3424 } = args;
3425
3426 let constraints_from_workspace = if let Some(configuration) = &filesystem {
3427 configuration
3428 .constraint_dependencies
3429 .clone()
3430 .unwrap_or_default()
3431 .into_iter()
3432 .map(|requirement| {
3433 Requirement::from(requirement.with_origin(RequirementOrigin::Workspace))
3434 })
3435 .collect()
3436 } else {
3437 Vec::new()
3438 };
3439
3440 let overrides_from_workspace = workspace_overrides(filesystem.as_ref());
3441
3442 let excludes_from_workspace = if let Some(configuration) = &filesystem {
3443 configuration
3444 .exclude_dependencies
3445 .clone()
3446 .unwrap_or_default()
3447 } else {
3448 Vec::new()
3449 };
3450
3451 let build_constraints_from_workspace = if let Some(configuration) = &filesystem {
3452 configuration
3453 .build_constraint_dependencies
3454 .clone()
3455 .unwrap_or_default()
3456 .into_iter()
3457 .map(|requirement| {
3458 let (requirement, hashes) = requirement.into_parts();
3459 NameRequirementSpecification {
3460 requirement: Requirement::from(
3461 requirement.with_origin(RequirementOrigin::Workspace),
3462 ),
3463 hashes,
3464 }
3465 })
3466 .collect()
3467 } else {
3468 Vec::new()
3469 };
3470
3471 let environments = if let Some(configuration) = &filesystem {
3472 configuration.environments.clone().unwrap_or_default()
3473 } else {
3474 SupportedEnvironments::default()
3475 };
3476
3477 let required_environments = if let Some(configuration) = &filesystem {
3478 configuration
3479 .required_environments
3480 .clone()
3481 .unwrap_or_default()
3482 } else {
3483 SupportedEnvironments::default()
3484 };
3485
3486 let minimum_libc_version = filesystem
3487 .as_ref()
3488 .and_then(|configuration| configuration.minimum_libc_version);
3489
3490 Ok(Self {
3491 format,
3492 src_file,
3493 constraints: requirement_files(constraints, environment.constraints.clone()),
3494 build_constraints: requirement_files(
3495 build_constraints,
3496 environment.build_constraints.clone(),
3497 ),
3498 build_hash_checking: resolve_pip_build_hash_checking(
3499 flag(
3500 require_build_hashes,
3501 no_require_build_hashes,
3502 "require-build-hashes",
3503 )?,
3504 filesystem.as_ref(),
3505 &environment,
3506 ),
3507 overrides: requirement_files(overrides, environment.overrides.clone()),
3508 excludes: requirement_files(excludes, environment.excludes.clone()),
3509 constraints_from_workspace,
3510 overrides_from_workspace,
3511 excludes_from_workspace,
3512 build_constraints_from_workspace,
3513 environments,
3514 required_environments,
3515 minimum_libc_version,
3516 refresh: Refresh::try_from(refresh)?,
3517 settings: PipSettings::combine(
3518 PipOptions {
3519 python: python.and_then(Maybe::into_option),
3520 system: flag(system, no_system, "system")?,
3521 no_build: flag(no_build, build, "build")?,
3522 no_binary,
3523 only_binary,
3524 extra,
3525 all_extras: flag(all_extras, no_all_extras, "all-extras")?,
3526 no_deps: flag(no_deps, deps, "deps")?,
3527 group: Some(group),
3528 output_file,
3529 no_strip_extras: flag(no_strip_extras, strip_extras, "strip-extras")?,
3530 no_strip_markers: flag(no_strip_markers, strip_markers, "strip-markers")?,
3531 no_annotate: flag(no_annotate, annotate, "annotate")?,
3532 no_header: flag(no_header, header, "header")?,
3533 custom_compile_command,
3534 generate_hashes: flag(generate_hashes, no_generate_hashes, "generate-hashes")?,
3535 python_version,
3536 python_platform,
3537 universal: flag(universal, no_universal, "universal")?,
3538 no_emit_package,
3539 emit_index_url: flag(emit_index_url, no_emit_index_url, "emit-index-url")?,
3540 emit_find_links: flag(emit_find_links, no_emit_find_links, "emit-find-links")?,
3541 emit_build_options: flag(
3542 emit_build_options,
3543 no_emit_build_options,
3544 "emit-build-options",
3545 )?,
3546 emit_marker_expression: flag(
3547 emit_marker_expression,
3548 no_emit_marker_expression,
3549 "emit-marker-expression",
3550 )?,
3551 emit_index_annotation: flag(
3552 emit_index_annotation,
3553 no_emit_index_annotation,
3554 "emit-index-annotation",
3555 )?,
3556 annotation_style,
3557 torch_backend,
3558 ..resolver.into_pip_options(configured_indexes(filesystem.as_ref()))?
3559 },
3560 filesystem,
3561 environment,
3562 ),
3563 })
3564 }
3565}
3566
3567#[derive(Debug, Clone)]
3569pub struct PipSyncSettings {
3570 pub src_file: Vec<RequirementsInput>,
3571 pub constraints: Vec<RequirementsInput>,
3572 pub build_constraints: Vec<RequirementsInput>,
3573 pub build_hash_checking: HashCheckingMode,
3574 pub dry_run: DryRun,
3575 pub output_format: PipInstallFormat,
3576 pub refresh: Refresh,
3577 pub settings: PipSettings,
3578}
3579
3580impl PipSyncSettings {
3581 pub fn resolve(
3583 args: Box<PipSyncArgs>,
3584 filesystem: Option<FilesystemOptions>,
3585 environment: EnvironmentOptions,
3586 ) -> anyhow::Result<Self> {
3587 let PipSyncArgs {
3588 src_file,
3589 constraints,
3590 build_constraints,
3591 require_build_hashes,
3592 no_require_build_hashes,
3593 extra,
3594 all_extras,
3595 no_all_extras,
3596 group,
3597 installer,
3598 refresh,
3599 hash_checking:
3600 HashCheckingArgs {
3601 require_hashes,
3602 no_require_hashes,
3603 verify_hashes,
3604 no_verify_hashes,
3605 },
3606 python,
3607 system,
3608 no_system,
3609 break_system_packages,
3610 no_break_system_packages,
3611 target,
3612 prefix,
3613 allow_empty_requirements,
3614 no_allow_empty_requirements,
3615 no_build,
3616 build,
3617 no_binary,
3618 only_binary,
3619 python_version,
3620 python_platform,
3621 strict,
3622 no_strict,
3623 dry_run,
3624 output_format,
3625 torch_backend,
3626 compat_args: _,
3627 check,
3628 } = *args;
3629
3630 Ok(Self {
3631 src_file,
3632 constraints: requirement_files(constraints, environment.constraints.clone()),
3633 build_constraints: requirement_files(
3634 build_constraints,
3635 environment.build_constraints.clone(),
3636 ),
3637 build_hash_checking: resolve_pip_build_hash_checking(
3638 flag(
3639 require_build_hashes,
3640 no_require_build_hashes,
3641 "require-build-hashes",
3642 )?,
3643 filesystem.as_ref(),
3644 &environment,
3645 ),
3646 dry_run: if check {
3647 DryRun::Check
3648 } else {
3649 DryRun::from_args(dry_run)
3650 },
3651 output_format,
3652 refresh: Refresh::try_from(refresh)?,
3653 settings: PipSettings::combine(
3654 PipOptions {
3655 python: python.and_then(Maybe::into_option),
3656 system: flag(system, no_system, "system")?,
3657 break_system_packages: flag(
3658 break_system_packages,
3659 no_break_system_packages,
3660 "break-system-packages",
3661 )?,
3662 target,
3663 prefix,
3664 require_hashes: flag(require_hashes, no_require_hashes, "require-hashes")?,
3665 verify_hashes: flag(verify_hashes, no_verify_hashes, "verify-hashes")?,
3666 no_build: flag(no_build, build, "build")?,
3667 no_binary,
3668 only_binary,
3669 allow_empty_requirements: flag(
3670 allow_empty_requirements,
3671 no_allow_empty_requirements,
3672 "allow-empty-requirements",
3673 )?,
3674 python_version,
3675 python_platform,
3676 strict: flag(strict, no_strict, "strict")?,
3677 extra,
3678 all_extras: flag(all_extras, no_all_extras, "all-extras")?,
3679 group: Some(group),
3680 torch_backend,
3681 ..installer.into_pip_options(configured_indexes(filesystem.as_ref()))?
3682 },
3683 filesystem,
3684 environment,
3685 ),
3686 })
3687 }
3688}
3689
3690#[derive(Debug, Clone)]
3692pub struct PipInstallSettings {
3693 pub package: Vec<String>,
3694 pub requirements: Vec<RequirementsInput>,
3695 pub editables: Vec<String>,
3696 pub editable: Option<EditableMode>,
3697 pub constraints: Vec<RequirementsInput>,
3698 pub overrides: Vec<RequirementsInput>,
3699 pub excludes: Vec<RequirementsInput>,
3700 pub build_constraints: Vec<RequirementsInput>,
3701 pub build_hash_checking: HashCheckingMode,
3702 pub dry_run: DryRun,
3703 pub output_format: PipInstallFormat,
3704 pub constraints_from_workspace: Vec<Requirement>,
3705 pub overrides_from_workspace: Vec<Override<Requirement>>,
3706 pub excludes_from_workspace: Vec<ExcludeDependency>,
3707 pub build_constraints_from_workspace: Vec<NameRequirementSpecification>,
3708 pub modifications: Modifications,
3709 pub refresh: Refresh,
3710 pub settings: PipSettings,
3711}
3712
3713impl PipInstallSettings {
3714 pub fn resolve(
3716 args: PipInstallArgs,
3717 filesystem: Option<FilesystemOptions>,
3718 environment: EnvironmentOptions,
3719 ) -> anyhow::Result<Self> {
3720 let PipInstallArgs {
3721 package,
3722 requirements,
3723 editable,
3724 no_editable,
3725 no_editable_package,
3726 constraints:
3727 DependencyConstraintsArgs {
3728 constraints,
3729 overrides,
3730 excludes,
3731 build_constraints,
3732 },
3733 require_build_hashes,
3734 no_require_build_hashes,
3735 extra,
3736 all_extras,
3737 no_all_extras,
3738 installer,
3739 refresh,
3740 no_deps,
3741 deps,
3742 group,
3743 hash_checking:
3744 HashCheckingArgs {
3745 require_hashes,
3746 no_require_hashes,
3747 verify_hashes,
3748 no_verify_hashes,
3749 },
3750 python,
3751 system,
3752 no_system,
3753 break_system_packages,
3754 no_break_system_packages,
3755 target,
3756 prefix,
3757 no_build,
3758 build,
3759 no_binary,
3760 only_binary,
3761 python_version,
3762 python_platform,
3763 inexact,
3764 exact,
3765 strict,
3766 no_strict,
3767 dry_run,
3768 output_format,
3769 torch_backend,
3770 compat_args: _,
3771 check,
3772 } = args;
3773
3774 let constraints_from_workspace = if let Some(configuration) = &filesystem {
3775 configuration
3776 .constraint_dependencies
3777 .clone()
3778 .unwrap_or_default()
3779 .into_iter()
3780 .map(|requirement| {
3781 Requirement::from(requirement.with_origin(RequirementOrigin::Workspace))
3782 })
3783 .collect()
3784 } else {
3785 Vec::new()
3786 };
3787
3788 let overrides_from_workspace = workspace_overrides(filesystem.as_ref());
3789
3790 let excludes_from_workspace = if let Some(configuration) = &filesystem {
3791 configuration
3792 .exclude_dependencies
3793 .clone()
3794 .unwrap_or_default()
3795 } else {
3796 Vec::new()
3797 };
3798
3799 let build_constraints_from_workspace = if let Some(configuration) = &filesystem {
3800 configuration
3801 .build_constraint_dependencies
3802 .clone()
3803 .unwrap_or_default()
3804 .into_iter()
3805 .map(|requirement| {
3806 let (requirement, hashes) = requirement.into_parts();
3807 NameRequirementSpecification {
3808 requirement: Requirement::from(
3809 requirement.with_origin(RequirementOrigin::Workspace),
3810 ),
3811 hashes,
3812 }
3813 })
3814 .collect()
3815 } else {
3816 Vec::new()
3817 };
3818
3819 Ok(Self {
3820 package,
3821 requirements,
3822 editables: editable,
3823 constraints: requirement_files(constraints, environment.constraints.clone()),
3824 overrides: requirement_files(overrides, environment.overrides.clone()),
3825 excludes: requirement_files(excludes, environment.excludes.clone()),
3826 build_constraints: requirement_files(
3827 build_constraints,
3828 environment.build_constraints.clone(),
3829 ),
3830 build_hash_checking: resolve_pip_build_hash_checking(
3831 flag(
3832 require_build_hashes,
3833 no_require_build_hashes,
3834 "require-build-hashes",
3835 )?,
3836 filesystem.as_ref(),
3837 &environment,
3838 ),
3839 dry_run: if check {
3840 DryRun::Check
3841 } else {
3842 DryRun::from_args(dry_run)
3843 },
3844 output_format,
3845 constraints_from_workspace,
3846 overrides_from_workspace,
3847 excludes_from_workspace,
3848 build_constraints_from_workspace,
3849 modifications: if flag(exact, inexact, "inexact")?.unwrap_or(false) {
3850 Modifications::Exact
3851 } else {
3852 Modifications::Sufficient
3853 },
3854 editable: EditableMode::from_args(
3855 if no_editable || environment.no_editable.value == Some(true) {
3856 Some(false)
3857 } else {
3858 None
3859 },
3860 no_editable_package,
3861 ),
3862 refresh: Refresh::try_from(refresh)?,
3863 settings: PipSettings::combine(
3864 PipOptions {
3865 python: python.and_then(Maybe::into_option),
3866 system: flag(system, no_system, "system")?,
3867 break_system_packages: flag(
3868 break_system_packages,
3869 no_break_system_packages,
3870 "break-system-packages",
3871 )?,
3872 target,
3873 prefix,
3874 no_build: flag(no_build, build, "build")?,
3875 no_binary,
3876 only_binary,
3877 strict: flag(strict, no_strict, "strict")?,
3878 extra,
3879 all_extras: flag(all_extras, no_all_extras, "all-extras")?,
3880 group: Some(group),
3881 no_deps: flag(no_deps, deps, "deps")?,
3882 python_version,
3883 python_platform,
3884 require_hashes: flag(require_hashes, no_require_hashes, "require-hashes")?,
3885 verify_hashes: flag(verify_hashes, no_verify_hashes, "verify-hashes")?,
3886 torch_backend,
3887 ..installer.into_pip_options(configured_indexes(filesystem.as_ref()))?
3888 },
3889 filesystem,
3890 environment,
3891 ),
3892 })
3893 }
3894}
3895
3896#[derive(Debug, Clone)]
3898pub struct PipUninstallSettings {
3899 pub package: Vec<String>,
3900 pub requirements: Vec<RequirementsInput>,
3901 pub dry_run: DryRun,
3902 pub settings: PipSettings,
3903}
3904
3905impl PipUninstallSettings {
3906 pub fn resolve(
3908 args: PipUninstallArgs,
3909 filesystem: Option<FilesystemOptions>,
3910 environment: EnvironmentOptions,
3911 ) -> anyhow::Result<Self> {
3912 let PipUninstallArgs {
3913 package,
3914 requirements,
3915 python,
3916 keyring_provider,
3917 system,
3918 no_system,
3919 break_system_packages,
3920 no_break_system_packages,
3921 target,
3922 prefix,
3923 dry_run,
3924 compat_args: _,
3925 } = args;
3926
3927 Ok(Self {
3928 package,
3929 requirements,
3930 dry_run: DryRun::from_args(dry_run),
3931 settings: PipSettings::combine(
3932 PipOptions {
3933 python: python.and_then(Maybe::into_option),
3934 system: flag(system, no_system, "system")?,
3935 break_system_packages: flag(
3936 break_system_packages,
3937 no_break_system_packages,
3938 "break-system-packages",
3939 )?,
3940 target,
3941 prefix,
3942 keyring_provider,
3943 ..PipOptions::default()
3944 },
3945 filesystem,
3946 environment,
3947 ),
3948 })
3949 }
3950}
3951
3952#[derive(Debug, Clone)]
3954pub struct PipFreezeSettings {
3955 pub exclude_editable: bool,
3956 pub exclude: FxHashSet<PackageName>,
3957 pub paths: Option<Vec<PathBuf>>,
3958 pub settings: PipSettings,
3959}
3960
3961impl PipFreezeSettings {
3962 pub fn resolve(
3964 args: PipFreezeArgs,
3965 filesystem: Option<FilesystemOptions>,
3966 environment: EnvironmentOptions,
3967 ) -> anyhow::Result<Self> {
3968 let PipFreezeArgs {
3969 exclude_editable,
3970 exclude,
3971 strict,
3972 no_strict,
3973 python,
3974 paths,
3975 system,
3976 no_system,
3977 target,
3978 prefix,
3979 compat_args: _,
3980 } = args;
3981
3982 Ok(Self {
3983 exclude_editable,
3984 exclude: exclude.into_iter().collect(),
3985 paths,
3986 settings: PipSettings::combine(
3987 PipOptions {
3988 python: python.and_then(Maybe::into_option),
3989 system: flag(system, no_system, "system")?,
3990 strict: flag(strict, no_strict, "strict")?,
3991 target,
3992 prefix,
3993 ..PipOptions::default()
3994 },
3995 filesystem,
3996 environment,
3997 ),
3998 })
3999 }
4000}
4001
4002#[derive(Debug, Clone)]
4004pub struct PipListSettings {
4005 pub editable: Option<bool>,
4006 pub exclude: FxHashSet<PackageName>,
4007 pub format: ListFormat,
4008 pub outdated: bool,
4009 pub settings: PipSettings,
4010}
4011
4012impl PipListSettings {
4013 pub fn resolve(
4015 args: PipListArgs,
4016 filesystem: Option<FilesystemOptions>,
4017 environment: EnvironmentOptions,
4018 ) -> anyhow::Result<Self> {
4019 let PipListArgs {
4020 editable,
4021 exclude_editable,
4022 exclude,
4023 format,
4024 outdated,
4025 no_outdated,
4026 strict,
4027 no_strict,
4028 fetch,
4029 python,
4030 system,
4031 no_system,
4032 target,
4033 prefix,
4034 compat_args: _,
4035 } = args;
4036
4037 Ok(Self {
4038 editable: flag(editable, exclude_editable, "exclude-editable")?,
4039 exclude: exclude.into_iter().collect(),
4040 format,
4041 outdated: flag(outdated, no_outdated, "outdated")?.unwrap_or(false),
4042 settings: PipSettings::combine(
4043 PipOptions {
4044 python: python.and_then(Maybe::into_option),
4045 system: flag(system, no_system, "system")?,
4046 strict: flag(strict, no_strict, "strict")?,
4047 target,
4048 prefix,
4049 ..fetch.into_pip_options(configured_indexes(filesystem.as_ref()))?
4050 },
4051 filesystem,
4052 environment,
4053 ),
4054 })
4055 }
4056}
4057
4058#[derive(Debug, Clone)]
4060pub struct PipShowSettings {
4061 pub package: Vec<PackageName>,
4062 pub files: bool,
4063 pub settings: PipSettings,
4064}
4065
4066impl PipShowSettings {
4067 pub fn resolve(
4069 args: PipShowArgs,
4070 filesystem: Option<FilesystemOptions>,
4071 environment: EnvironmentOptions,
4072 ) -> anyhow::Result<Self> {
4073 let PipShowArgs {
4074 package,
4075 strict,
4076 no_strict,
4077 files,
4078 python,
4079 system,
4080 no_system,
4081 target,
4082 prefix,
4083 compat_args: _,
4084 } = args;
4085
4086 Ok(Self {
4087 package,
4088 files,
4089 settings: PipSettings::combine(
4090 PipOptions {
4091 python: python.and_then(Maybe::into_option),
4092 system: flag(system, no_system, "system")?,
4093 strict: flag(strict, no_strict, "strict")?,
4094 target,
4095 prefix,
4096 ..PipOptions::default()
4097 },
4098 filesystem,
4099 environment,
4100 ),
4101 })
4102 }
4103}
4104
4105#[derive(Debug, Clone)]
4107pub struct PipTreeSettings {
4108 pub show_version_specifiers: bool,
4109 pub depth: u8,
4110 pub prune: Vec<PackageName>,
4111 pub package: Vec<PackageName>,
4112 pub no_dedupe: bool,
4113 pub invert: bool,
4114 pub outdated: bool,
4115 pub settings: PipSettings,
4116}
4117
4118impl PipTreeSettings {
4119 pub fn resolve(
4121 args: PipTreeArgs,
4122 filesystem: Option<FilesystemOptions>,
4123 environment: EnvironmentOptions,
4124 ) -> anyhow::Result<Self> {
4125 let PipTreeArgs {
4126 show_version_specifiers,
4127 tree,
4128 strict,
4129 no_strict,
4130 fetch,
4131 python,
4132 system,
4133 no_system,
4134 compat_args: _,
4135 } = args;
4136
4137 Ok(Self {
4138 show_version_specifiers,
4139 depth: tree.depth,
4140 prune: tree.prune,
4141 no_dedupe: tree.no_dedupe,
4142 invert: tree.invert,
4143 package: tree.package,
4144 outdated: tree.outdated,
4145 settings: PipSettings::combine(
4146 PipOptions {
4147 python: python.and_then(Maybe::into_option),
4148 system: flag(system, no_system, "system")?,
4149 strict: flag(strict, no_strict, "strict")?,
4150 ..fetch.into_pip_options(configured_indexes(filesystem.as_ref()))?
4151 },
4152 filesystem,
4153 environment,
4154 ),
4155 })
4156 }
4157}
4158
4159#[derive(Debug, Clone)]
4161pub struct PipCheckSettings {
4162 pub settings: PipSettings,
4163}
4164
4165impl PipCheckSettings {
4166 pub fn resolve(
4168 args: PipCheckArgs,
4169 filesystem: Option<FilesystemOptions>,
4170 environment: EnvironmentOptions,
4171 ) -> anyhow::Result<Self> {
4172 let PipCheckArgs {
4173 python,
4174 system,
4175 no_system,
4176 python_version,
4177 python_platform,
4178 } = args;
4179
4180 Ok(Self {
4181 settings: PipSettings::combine(
4182 PipOptions {
4183 python: python.and_then(Maybe::into_option),
4184 system: flag(system, no_system, "system")?,
4185 python_version,
4186 python_platform,
4187 ..PipOptions::default()
4188 },
4189 filesystem,
4190 environment,
4191 ),
4192 })
4193 }
4194}
4195
4196#[derive(Debug, Clone)]
4198pub struct BuildSettings {
4199 pub skip_dependency_check: bool,
4200 pub src: Option<PathBuf>,
4201 pub package: Option<PackageName>,
4202 pub all_packages: bool,
4203 pub out_dir: Option<PathBuf>,
4204 pub sdist: bool,
4205 pub wheel: bool,
4206 pub list: bool,
4207 pub build_logs: bool,
4208 pub gitignore: bool,
4209 pub force_pep517: bool,
4210 pub clear: bool,
4211 pub build_constraints: Vec<RequirementsInput>,
4212 pub build_constraints_from_workspace: Vec<NameRequirementSpecification>,
4213 pub hash_checking: Option<HashCheckingMode>,
4214 pub python: Option<String>,
4215 pub install_mirrors: PythonInstallMirrors,
4216 pub refresh: Refresh,
4217 pub settings: ResolverSettings,
4218}
4219
4220impl BuildSettings {
4221 pub fn resolve(
4223 args: BuildArgs,
4224 filesystem: Option<FilesystemOptions>,
4225 environment: EnvironmentOptions,
4226 ) -> anyhow::Result<Self> {
4227 let BuildArgs {
4228 skip_dependency_check,
4229 src,
4230 out_dir,
4231 package,
4232 all_packages,
4233 sdist,
4234 wheel,
4235 list,
4236 force_pep517,
4237 clear,
4238 build_constraints,
4239 hash_checking:
4240 HashCheckingArgs {
4241 require_hashes,
4242 no_require_hashes,
4243 verify_hashes,
4244 no_verify_hashes,
4245 },
4246 build_logs,
4247 no_build_logs,
4248 create_gitignore,
4249 no_create_gitignore,
4250 python,
4251 build,
4252 refresh,
4253 resolver,
4254 } = args;
4255 let filesystem_install_mirrors = match &filesystem {
4256 Some(fs) => fs.install_mirrors.clone(),
4257 None => PythonInstallMirrors::default(),
4258 };
4259 let build_constraints_from_workspace = if let Some(configuration) = &filesystem {
4260 configuration
4261 .build_constraint_dependencies
4262 .clone()
4263 .unwrap_or_default()
4264 .into_iter()
4265 .map(|requirement| {
4266 let (requirement, hashes) = requirement.into_parts();
4267 NameRequirementSpecification {
4268 requirement: Requirement::from(
4269 requirement.with_origin(RequirementOrigin::Workspace),
4270 ),
4271 hashes,
4272 }
4273 })
4274 .collect()
4275 } else {
4276 Vec::new()
4277 };
4278
4279 Ok(Self {
4280 skip_dependency_check,
4281 src,
4282 package,
4283 all_packages,
4284 out_dir,
4285 sdist,
4286 wheel,
4287 list,
4288 build_logs: flag(build_logs, no_build_logs, "build-logs")?.unwrap_or(true),
4289 force_pep517,
4290 clear,
4291 gitignore: flag(create_gitignore, no_create_gitignore, "create-gitignore")?
4292 .unwrap_or(true),
4293 build_constraints: requirement_files(
4294 build_constraints,
4295 environment.build_constraints.clone(),
4296 ),
4297 build_constraints_from_workspace,
4298 hash_checking: HashCheckingMode::from_args(
4299 flag(require_hashes, no_require_hashes, "require-hashes")?,
4300 flag(verify_hashes, no_verify_hashes, "verify-hashes")?,
4301 ),
4302 python: python.and_then(Maybe::into_option),
4303 refresh: Refresh::try_from(refresh)?,
4304 settings: resolve_resolver_settings(resolver, build, filesystem, &environment)?,
4305 install_mirrors: environment
4306 .install_mirrors
4307 .combine(filesystem_install_mirrors),
4308 })
4309 }
4310}
4311
4312#[derive(Debug, Clone)]
4314pub struct VenvSettings {
4315 pub seed: bool,
4316 pub allow_existing: bool,
4317 pub clear: bool,
4318 pub force: bool,
4319 pub no_clear: bool,
4320 pub path: Option<PathBuf>,
4321 pub prompt: Option<String>,
4322 pub system_site_packages: bool,
4323 pub relocatable: bool,
4324 pub no_relocatable: bool,
4325 pub no_project: bool,
4326 pub refresh: Refresh,
4327 pub settings: PipSettings,
4328}
4329
4330impl VenvSettings {
4331 pub fn resolve(
4333 args: VenvArgs,
4334 filesystem: Option<FilesystemOptions>,
4335 environment: EnvironmentOptions,
4336 ) -> anyhow::Result<Self> {
4337 let VenvArgs {
4338 python,
4339 system,
4340 no_system,
4341 seed,
4342 allow_existing,
4343 clear,
4344 force,
4345 no_clear,
4346 path,
4347 prompt,
4348 system_site_packages,
4349 relocatable,
4350 no_relocatable,
4351 index_args,
4352 registry_client:
4353 RegistryClientArgs {
4354 index_strategy,
4355 keyring_provider,
4356 },
4357 exclude_newer:
4358 PackageExcludeNewerArgs {
4359 exclude_newer: ExcludeNewerArgs { exclude_newer },
4360 exclude_newer_package,
4361 },
4362 no_project,
4363 link_mode,
4364 refresh,
4365 compat_args: _,
4366 } = args;
4367
4368 let seed = seed || environment.venv_seed.value == Some(true);
4370 let (clear, no_clear) = resolve_flag_pair(
4371 clear,
4372 no_clear,
4373 "clear",
4374 "no-clear",
4375 Some(environment.venv_clear),
4376 None,
4377 );
4378 let (relocatable, no_relocatable) = resolve_flag_pair(
4379 relocatable,
4380 no_relocatable,
4381 "relocatable",
4382 "no-relocatable",
4383 Some(environment.venv_relocatable),
4384 None,
4385 );
4386
4387 Ok(Self {
4388 seed,
4389 allow_existing,
4390 clear: clear.into(),
4391 force,
4392 no_clear: no_clear.into(),
4393 path,
4394 prompt,
4395 system_site_packages,
4396 no_project,
4397 relocatable: relocatable.into(),
4398 no_relocatable: no_relocatable.into(),
4399 refresh: Refresh::try_from(refresh)?,
4400 settings: PipSettings::combine(
4401 PipOptions {
4402 python: python.and_then(Maybe::into_option),
4403 system: flag(system, no_system, "system")?,
4404 index_strategy,
4405 keyring_provider,
4406 exclude_newer,
4407 exclude_newer_package: exclude_newer_package
4408 .map(ExcludeNewerPackage::from_iter),
4409 link_mode,
4410 ..index_args.into_pip_options(configured_indexes(filesystem.as_ref()))?
4411 },
4412 filesystem,
4413 environment,
4414 ),
4415 })
4416 }
4417}
4418
4419fn resolve_pip_build_hash_checking(
4421 require_build_hashes: Option<bool>,
4422 filesystem: Option<&FilesystemOptions>,
4423 environment: &EnvironmentOptions,
4424) -> HashCheckingMode {
4425 let configured = filesystem.and_then(|filesystem| {
4426 filesystem
4427 .pip
4428 .as_ref()
4429 .and_then(|pip| pip.require_build_hashes)
4430 .or(filesystem.top_level.require_build_hashes)
4431 });
4432 resolve_build_hash_checking(
4433 require_build_hashes
4434 .or(environment.require_build_hashes)
4435 .or(configured),
4436 )
4437}
4438
4439fn configured_indexes(filesystem: Option<&FilesystemOptions>) -> &[Index] {
4441 filesystem
4442 .and_then(|options| options.top_level.index.as_deref())
4443 .unwrap_or_default()
4444}
4445
4446fn resolve_resolver_settings(
4448 args: ResolverArgs,
4449 build: BuildOptionsArgs,
4450 filesystem: Option<FilesystemOptions>,
4451 environment: &EnvironmentOptions,
4452) -> Result<ResolverSettings> {
4453 let args = resolver_options(args, build, configured_indexes(filesystem.as_ref()))?;
4454
4455 Ok(combine_resolver_settings(args, filesystem, environment))
4456}
4457
4458fn combine_resolver_settings(
4460 mut args: ResolverOptions,
4461 filesystem: Option<FilesystemOptions>,
4462 environment: &EnvironmentOptions,
4463) -> ResolverSettings {
4464 args.require_build_hashes = args
4465 .require_build_hashes
4466 .or(environment.require_build_hashes);
4467 args.no_binary_package = args
4468 .no_binary_package
4469 .or(environment.no_binary_package.clone());
4470 args.no_build_package = args
4471 .no_build_package
4472 .or(environment.no_build_package.clone());
4473 args.no_sources_package = args
4474 .no_sources_package
4475 .or(environment.no_sources_package.clone());
4476
4477 let options = args.combine(ResolverOptions::from(
4480 filesystem
4481 .map(FilesystemOptions::into_options)
4482 .map(|options| options.top_level)
4483 .unwrap_or_default(),
4484 ));
4485
4486 ResolverSettings {
4487 cuda_driver_version: environment.cuda_driver_version.clone(),
4488 amd_gpu_architecture: environment.amd_gpu_architecture,
4489 ..ResolverSettings::from(options)
4490 }
4491}
4492
4493fn resolve_resolver_installer_settings(
4495 args: ResolverInstallerArgs,
4496 build: BuildOptionsArgs,
4497 filesystem: Option<FilesystemOptions>,
4498 environment: &EnvironmentOptions,
4499) -> Result<ResolverInstallerSettings> {
4500 let args = resolver_installer_options(args, build, configured_indexes(filesystem.as_ref()))?;
4501
4502 Ok(combine_resolver_installer_settings(
4503 args,
4504 filesystem,
4505 environment,
4506 ))
4507}
4508
4509fn combine_resolver_installer_settings(
4511 args: ResolverInstallerOptions,
4512 filesystem: Option<FilesystemOptions>,
4513 environment: &EnvironmentOptions,
4514) -> ResolverInstallerSettings {
4515 let options = resolver_installer_options_with_environment(args, environment).combine(
4516 ResolverInstallerOptions::from(
4517 filesystem
4518 .map(FilesystemOptions::into_options)
4519 .map(|options| options.top_level)
4520 .unwrap_or_default(),
4521 ),
4522 );
4523
4524 let base = ResolverInstallerSettings::from(options);
4525 ResolverInstallerSettings {
4526 resolver: ResolverSettings {
4527 cuda_driver_version: environment.cuda_driver_version.clone(),
4528 amd_gpu_architecture: environment.amd_gpu_architecture,
4529 ..base.resolver
4530 },
4531 ..base
4532 }
4533}
4534
4535fn resolver_installer_options_with_environment(
4536 mut options: ResolverInstallerOptions,
4537 environment: &EnvironmentOptions,
4538) -> ResolverInstallerOptions {
4539 options.require_build_hashes = options
4540 .require_build_hashes
4541 .or(environment.require_build_hashes);
4542 options.no_binary_package = options
4543 .no_binary_package
4544 .or(environment.no_binary_package.clone());
4545 options.no_build_package = options
4546 .no_build_package
4547 .or(environment.no_build_package.clone());
4548 options.no_sources_package = options
4549 .no_sources_package
4550 .or(environment.no_sources_package.clone());
4551 options
4552}
4553
4554#[derive(Debug, Clone)]
4559pub struct PipSettings {
4560 pub index_locations: IndexLocations,
4561 pub python: Option<String>,
4562 pub install_mirrors: PythonInstallMirrors,
4563 pub system: bool,
4564 pub extras: ExtrasSpecification,
4565 pub groups: Vec<PipGroupName>,
4566 pub break_system_packages: bool,
4567 pub target: Option<Target>,
4568 pub prefix: Option<Prefix>,
4569 pub index_strategy: IndexStrategy,
4570 pub keyring_provider: KeyringProviderType,
4571 pub torch_backend: Option<TorchMode>,
4572 pub cuda_driver_version: Option<Version>,
4573 pub amd_gpu_architecture: Option<AmdGpuArchitecture>,
4574 pub build_isolation: BuildIsolation,
4575 pub extra_build_dependencies: ExtraBuildDependencies,
4576 pub extra_build_variables: ExtraBuildVariables,
4577 pub build_options: BuildOptions,
4578 pub allow_empty_requirements: bool,
4579 pub strict: bool,
4580 pub dependency_mode: DependencyMode,
4581 pub resolution: ResolutionMode,
4582 pub prerelease: Prerelease,
4583 pub fork_strategy: ForkStrategy,
4584 pub dependency_metadata: DependencyMetadata,
4585 pub output_file: Option<PathBuf>,
4586 pub no_strip_extras: bool,
4587 pub no_strip_markers: bool,
4588 pub no_annotate: bool,
4589 pub no_header: bool,
4590 pub custom_compile_command: Option<String>,
4591 pub generate_hashes: bool,
4592 pub config_setting: ConfigSettings,
4593 pub config_settings_package: PackageConfigSettings,
4594 pub python_version: Option<PythonVersion>,
4595 pub python_platform: Option<TargetTriple>,
4596 pub universal: bool,
4597 pub exclude_newer: ExcludeNewer,
4598 pub no_emit_package: Vec<PackageName>,
4599 pub emit_index_url: bool,
4600 pub emit_find_links: bool,
4601 pub emit_build_options: bool,
4602 pub emit_marker_expression: bool,
4603 pub emit_index_annotation: bool,
4604 pub annotation_style: AnnotationStyle,
4605 pub link_mode: LinkMode,
4606 pub compile_bytecode: bool,
4607 pub sources: NoSources,
4608 pub hash_checking: Option<HashCheckingMode>,
4609 pub upgrade: Upgrade,
4610 pub reinstall: Reinstall,
4611}
4612
4613impl PipSettings {
4614 fn combine(
4616 args: PipOptions,
4617 filesystem: Option<FilesystemOptions>,
4618 environment: EnvironmentOptions,
4619 ) -> Self {
4620 let Options {
4621 top_level,
4622 pip,
4623 install_mirrors: filesystem_install_mirrors,
4624 ..
4625 } = filesystem
4626 .map(FilesystemOptions::into_options)
4627 .unwrap_or_default();
4628
4629 let PipOptions {
4630 python,
4631 system,
4632 break_system_packages,
4633 target,
4634 prefix,
4635 index,
4636 index_url,
4637 extra_index_url,
4638 no_index,
4639 find_links,
4640 index_strategy,
4641 torch_backend,
4642 keyring_provider,
4643 no_build,
4644 no_binary,
4645 only_binary,
4646 no_build_isolation,
4647 require_build_hashes: _,
4648 no_build_isolation_package,
4649 extra_build_dependencies,
4650 extra_build_variables,
4651 strict,
4652 extra,
4653 all_extras,
4654 no_extra,
4655 group,
4656 no_deps,
4657 allow_empty_requirements,
4658 resolution,
4659 prerelease,
4660 prerelease_package: _,
4661 fork_strategy,
4662 dependency_metadata,
4663 output_file,
4664 no_strip_extras,
4665 no_strip_markers,
4666 no_annotate,
4667 no_header,
4668 custom_compile_command,
4669 generate_hashes,
4670 config_settings,
4671 config_settings_package,
4672 python_version,
4673 python_platform,
4674 universal,
4675 exclude_newer,
4676 no_emit_package,
4677 emit_index_url,
4678 emit_find_links,
4679 emit_build_options,
4680 emit_marker_expression,
4681 emit_index_annotation,
4682 annotation_style,
4683 link_mode,
4684 compile_bytecode,
4685 require_hashes,
4686 verify_hashes,
4687 no_sources,
4688 no_sources_package,
4689 upgrade,
4690 upgrade_package,
4691 reinstall,
4692 reinstall_package,
4693 exclude_newer_package,
4694 } = pip.unwrap_or_default();
4695
4696 let ResolverInstallerSchema {
4697 index: top_level_index,
4698 index_url: top_level_index_url,
4699 extra_index_url: top_level_extra_index_url,
4700 no_index: top_level_no_index,
4701 find_links: top_level_find_links,
4702 index_strategy: top_level_index_strategy,
4703 keyring_provider: top_level_keyring_provider,
4704 resolution: top_level_resolution,
4705 prerelease: top_level_prerelease,
4706 prerelease_package: top_level_prerelease_package,
4707 fork_strategy: top_level_fork_strategy,
4708 dependency_metadata: top_level_dependency_metadata,
4709 config_settings: top_level_config_settings,
4710 config_settings_package: top_level_config_settings_package,
4711 no_build_isolation: top_level_no_build_isolation,
4712 no_build_isolation_package: top_level_no_build_isolation_package,
4713 extra_build_dependencies: top_level_extra_build_dependencies,
4714 extra_build_variables: top_level_extra_build_variables,
4715 exclude_newer: top_level_exclude_newer,
4716 link_mode: top_level_link_mode,
4717 compile_bytecode: top_level_compile_bytecode,
4718 no_sources: top_level_no_sources,
4719 no_sources_package: top_level_no_sources_package,
4720 upgrade: top_level_upgrade,
4721 upgrade_package: top_level_upgrade_package,
4722 reinstall: top_level_reinstall,
4723 reinstall_package: top_level_reinstall_package,
4724 no_build: top_level_no_build,
4725 no_build_package: top_level_no_build_package,
4726 no_binary: top_level_no_binary,
4727 no_binary_package: top_level_no_binary_package,
4728 exclude_newer_package: top_level_exclude_newer_package,
4729 torch_backend: top_level_torch_backend,
4730 require_build_hashes: _,
4731 } = top_level;
4732
4733 let index = index.combine(top_level_index);
4738 let no_index = no_index.combine(top_level_no_index);
4739 let index_url = index_url.combine(top_level_index_url);
4740 let extra_index_url = extra_index_url.combine(top_level_extra_index_url);
4741 let find_links = find_links.combine(top_level_find_links);
4742 let index_strategy = index_strategy.combine(top_level_index_strategy);
4743 let keyring_provider = keyring_provider.combine(top_level_keyring_provider);
4744 let resolution = resolution.combine(top_level_resolution);
4745 let prerelease = prerelease.combine(top_level_prerelease);
4746 let prerelease_package = args
4747 .prerelease_package
4748 .combine(top_level_prerelease_package)
4749 .unwrap_or_default();
4750 let fork_strategy = fork_strategy.combine(top_level_fork_strategy);
4751 let dependency_metadata = dependency_metadata.combine(top_level_dependency_metadata);
4752 let config_settings = config_settings.combine(top_level_config_settings);
4753 let config_settings_package =
4754 config_settings_package.combine(top_level_config_settings_package);
4755 let no_build_isolation = no_build_isolation.combine(top_level_no_build_isolation);
4756 let no_build_isolation_package =
4757 no_build_isolation_package.combine(top_level_no_build_isolation_package);
4758 let extra_build_dependencies =
4759 extra_build_dependencies.combine(top_level_extra_build_dependencies);
4760 let extra_build_variables = extra_build_variables.combine(top_level_extra_build_variables);
4761 let exclude_newer = args
4762 .exclude_newer
4763 .combine(exclude_newer)
4764 .combine(top_level_exclude_newer);
4765 let exclude_newer_package = args
4766 .exclude_newer_package
4767 .combine(exclude_newer_package)
4768 .combine(top_level_exclude_newer_package)
4769 .unwrap_or_default();
4770 let link_mode = link_mode.combine(top_level_link_mode);
4771 let compile_bytecode = compile_bytecode.combine(top_level_compile_bytecode);
4772 let no_sources = no_sources.combine(top_level_no_sources);
4773 let no_sources_package = no_sources_package.combine(top_level_no_sources_package);
4774 let upgrade = upgrade.combine(top_level_upgrade);
4775 let upgrade_package = upgrade_package.combine(top_level_upgrade_package);
4776 let reinstall = reinstall.combine(top_level_reinstall);
4777 let reinstall_package = reinstall_package.combine(top_level_reinstall_package);
4778 let torch_backend = torch_backend.combine(top_level_torch_backend);
4779 let args_no_sources_package = args
4780 .no_sources_package
4781 .or(environment.no_sources_package.clone());
4782
4783 Self {
4784 index_locations: IndexLocations::new(
4785 args.index
4786 .into_iter()
4787 .flatten()
4788 .chain(args.extra_index_url.into_iter().flatten().map(Index::from))
4789 .chain(args.index_url.into_iter().map(Index::from))
4790 .chain(index.into_iter().flatten())
4791 .chain(extra_index_url.into_iter().flatten().map(Index::from))
4792 .chain(index_url.into_iter().map(Index::from))
4793 .collect(),
4794 args.find_links
4795 .combine(find_links)
4796 .into_iter()
4797 .flatten()
4798 .map(Index::from)
4799 .collect(),
4800 args.no_index.combine(no_index).unwrap_or_default(),
4801 ),
4802 extras: ExtrasSpecification::from_args(
4803 args.extra.combine(extra).unwrap_or_default(),
4804 args.no_extra.combine(no_extra).unwrap_or_default(),
4805 false,
4807 vec![],
4809 args.all_extras.combine(all_extras).unwrap_or_default(),
4810 ),
4811
4812 groups: args.group.combine(group).unwrap_or_default(),
4813 dependency_mode: if args.no_deps.combine(no_deps).unwrap_or_default() {
4814 DependencyMode::Direct
4815 } else {
4816 DependencyMode::Transitive
4817 },
4818 resolution: args.resolution.combine(resolution).unwrap_or_default(),
4819 prerelease: resolve_prerelease(
4820 args.prerelease.combine(prerelease).unwrap_or_default(),
4821 prerelease_package,
4822 ),
4823 fork_strategy: args
4824 .fork_strategy
4825 .combine(fork_strategy)
4826 .unwrap_or_default(),
4827 dependency_metadata: DependencyMetadata::from_entries(
4828 args.dependency_metadata
4829 .combine(dependency_metadata)
4830 .unwrap_or_default(),
4831 ),
4832 output_file: args.output_file.combine(output_file),
4833 no_strip_extras: args
4834 .no_strip_extras
4835 .combine(no_strip_extras)
4836 .unwrap_or_default(),
4837 no_strip_markers: args
4838 .no_strip_markers
4839 .combine(no_strip_markers)
4840 .unwrap_or_default(),
4841 no_annotate: args.no_annotate.combine(no_annotate).unwrap_or_default(),
4842 no_header: args.no_header.combine(no_header).unwrap_or_default(),
4843 custom_compile_command: args.custom_compile_command.combine(custom_compile_command),
4844 annotation_style: args
4845 .annotation_style
4846 .combine(annotation_style)
4847 .unwrap_or_default(),
4848 index_strategy: args
4849 .index_strategy
4850 .combine(index_strategy)
4851 .unwrap_or_default(),
4852 keyring_provider: args
4853 .keyring_provider
4854 .combine(keyring_provider)
4855 .unwrap_or_default(),
4856 generate_hashes: args
4857 .generate_hashes
4858 .combine(generate_hashes)
4859 .unwrap_or_default(),
4860 allow_empty_requirements: args
4861 .allow_empty_requirements
4862 .combine(allow_empty_requirements)
4863 .unwrap_or_default(),
4864 build_isolation: BuildIsolation::from_args(
4865 args.no_build_isolation,
4866 args.no_build_isolation_package.unwrap_or_default(),
4867 )
4868 .combine(BuildIsolation::from_args(
4869 no_build_isolation,
4870 no_build_isolation_package.unwrap_or_default(),
4871 ))
4872 .unwrap_or_default(),
4873 extra_build_dependencies: args
4874 .extra_build_dependencies
4875 .combine(extra_build_dependencies)
4876 .unwrap_or_default(),
4877 extra_build_variables: args
4878 .extra_build_variables
4879 .combine(extra_build_variables)
4880 .unwrap_or_default(),
4881 config_setting: args
4882 .config_settings
4883 .combine(config_settings)
4884 .unwrap_or_default(),
4885 config_settings_package: args
4886 .config_settings_package
4887 .combine(config_settings_package)
4888 .unwrap_or_default(),
4889 torch_backend: args.torch_backend.combine(torch_backend),
4890 cuda_driver_version: environment.cuda_driver_version.clone(),
4891 amd_gpu_architecture: environment.amd_gpu_architecture,
4892 python_version: args.python_version.combine(python_version),
4893 python_platform: args.python_platform.combine(python_platform),
4894 universal: args.universal.combine(universal).unwrap_or_default(),
4895 exclude_newer: ExcludeNewer::from_args(
4896 exclude_newer,
4897 exclude_newer_package.into_iter().map(Into::into).collect(),
4898 ),
4899 no_emit_package: args
4900 .no_emit_package
4901 .combine(no_emit_package)
4902 .unwrap_or_default(),
4903 emit_index_url: args
4904 .emit_index_url
4905 .combine(emit_index_url)
4906 .unwrap_or_default(),
4907 emit_find_links: args
4908 .emit_find_links
4909 .combine(emit_find_links)
4910 .unwrap_or_default(),
4911 emit_build_options: args
4912 .emit_build_options
4913 .combine(emit_build_options)
4914 .unwrap_or_default(),
4915 emit_marker_expression: args
4916 .emit_marker_expression
4917 .combine(emit_marker_expression)
4918 .unwrap_or_default(),
4919 emit_index_annotation: args
4920 .emit_index_annotation
4921 .combine(emit_index_annotation)
4922 .unwrap_or_default(),
4923 link_mode: args.link_mode.combine(link_mode).unwrap_or_default(),
4924 hash_checking: HashCheckingMode::from_args(
4925 args.require_hashes.combine(require_hashes),
4926 args.verify_hashes.combine(verify_hashes),
4927 ),
4928 python: args.python.combine(python),
4929 system: args.system.combine(system).unwrap_or_default(),
4930 break_system_packages: args
4931 .break_system_packages
4932 .combine(break_system_packages)
4933 .unwrap_or_default(),
4934 target: args.target.combine(target).map(Target::from),
4935 prefix: args.prefix.combine(prefix).map(Prefix::from),
4936 compile_bytecode: args
4937 .compile_bytecode
4938 .combine(compile_bytecode)
4939 .unwrap_or_default(),
4940 sources: NoSources::from_args(
4941 args.no_sources.combine(no_sources),
4942 args_no_sources_package
4943 .combine(no_sources_package)
4944 .unwrap_or_default(),
4945 ),
4946 strict: args.strict.combine(strict).unwrap_or_default(),
4947 upgrade: Upgrade::from_args(
4948 args.upgrade,
4949 args.upgrade_package
4950 .into_iter()
4951 .flatten()
4952 .map(Requirement::from)
4953 .collect(),
4954 Vec::new(),
4955 )
4956 .combine(Upgrade::from_args(
4957 upgrade,
4958 upgrade_package
4959 .into_iter()
4960 .flatten()
4961 .map(Requirement::from)
4962 .collect(),
4963 Vec::new(),
4964 ))
4965 .unwrap_or_default(),
4966 reinstall: Reinstall::from_args(
4967 args.reinstall,
4968 args.reinstall_package.unwrap_or_default(),
4969 )
4970 .combine(Reinstall::from_args(
4971 reinstall,
4972 reinstall_package.unwrap_or_default(),
4973 ))
4974 .unwrap_or_default(),
4975 build_options: BuildOptions::new(
4976 NoBinary::from_pip_args(args.no_binary.combine(no_binary).unwrap_or_default())
4977 .combine(NoBinary::from_args(
4978 top_level_no_binary,
4979 top_level_no_binary_package.unwrap_or_default(),
4980 )),
4981 NoBuild::from_pip_args(
4982 args.only_binary.combine(only_binary).unwrap_or_default(),
4983 args.no_build.combine(no_build).unwrap_or_default(),
4984 )
4985 .combine(NoBuild::from_args(
4986 top_level_no_build,
4987 top_level_no_build_package.unwrap_or_default(),
4988 )),
4989 ),
4990 install_mirrors: environment
4991 .install_mirrors
4992 .combine(filesystem_install_mirrors),
4993 }
4994 }
4995}
4996
4997#[derive(Clone)]
4999pub struct PublishSettings {
5000 pub files: Vec<String>,
5002 pub username: Option<String>,
5003 pub password: Option<String>,
5004 pub index: Option<String>,
5005 pub dry_run: bool,
5006 pub no_attestations: bool,
5007
5008 pub publish_url: SafeUrl,
5010 pub trusted_publishing: TrustedPublishing,
5011 pub keyring_provider: KeyringProviderType,
5012 pub check_url: Option<IndexUrl>,
5013
5014 pub index_locations: IndexLocations,
5016}
5017
5018impl fmt::Debug for PublishSettings {
5019 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
5020 f.debug_struct("PublishSettings")
5021 .field("files", &self.files)
5022 .field("username", &self.username)
5023 .field("password", &self.password.as_ref().map(|_| "****"))
5024 .field("index", &self.index)
5025 .field("dry_run", &self.dry_run)
5026 .field("no_attestations", &self.no_attestations)
5027 .field("publish_url", &self.publish_url)
5028 .field("trusted_publishing", &self.trusted_publishing)
5029 .field("keyring_provider", &self.keyring_provider)
5030 .field("check_url", &self.check_url)
5031 .field("index_locations", &self.index_locations)
5032 .finish()
5033 }
5034}
5035
5036impl PublishSettings {
5037 pub fn resolve(args: PublishArgs, filesystem: Option<FilesystemOptions>) -> Self {
5039 let Options {
5040 publish, top_level, ..
5041 } = filesystem
5042 .map(FilesystemOptions::into_options)
5043 .unwrap_or_default();
5044
5045 let PublishOptions {
5046 publish_url,
5047 trusted_publishing,
5048 check_url,
5049 } = publish;
5050 let ResolverInstallerSchema {
5051 keyring_provider,
5052 index,
5053 extra_index_url,
5054 index_url,
5055 ..
5056 } = top_level;
5057
5058 let (username, password) = if let Some(token) = args.token {
5060 (Some("__token__".to_string()), Some(token))
5061 } else {
5062 (args.username, args.password)
5063 };
5064
5065 Self {
5066 files: args.files,
5067 username,
5068 password,
5069 dry_run: args.dry_run,
5070 no_attestations: args.no_attestations,
5071 publish_url: args
5072 .publish_url
5073 .combine(publish_url)
5074 .unwrap_or_else(|| SafeUrl::parse(PYPI_PUBLISH_URL).unwrap()),
5075 trusted_publishing: args
5076 .trusted_publishing
5077 .combine(trusted_publishing)
5078 .unwrap_or_default(),
5079 keyring_provider: args
5080 .keyring_provider
5081 .combine(keyring_provider)
5082 .unwrap_or_default(),
5083 check_url: args.check_url.combine(check_url),
5084 index: args.index,
5085 index_locations: IndexLocations::new(
5086 index
5087 .into_iter()
5088 .flatten()
5089 .chain(extra_index_url.into_iter().flatten().map(Index::from))
5090 .chain(index_url.into_iter().map(Index::from))
5091 .collect(),
5092 Vec::new(),
5093 false,
5094 ),
5095 }
5096 }
5097}
5098
5099#[derive(Debug, Clone)]
5101pub struct AuthLogoutSettings {
5102 pub service: Service,
5103 pub username: Option<String>,
5104}
5105
5106impl AuthLogoutSettings {
5107 pub fn resolve(args: AuthLogoutArgs) -> Self {
5109 Self {
5110 service: args.service,
5111 username: args.username,
5112 }
5113 }
5114}
5115
5116#[derive(Debug, Clone)]
5118pub struct AuthTokenSettings {
5119 pub service: Service,
5120 pub username: Option<String>,
5121}
5122
5123impl AuthTokenSettings {
5124 pub fn resolve(args: AuthTokenArgs) -> Self {
5126 Self {
5127 service: args.service,
5128 username: args.username,
5129 }
5130 }
5131}
5132
5133#[derive(Debug, Clone)]
5135pub struct AuthLoginSettings {
5136 pub service: Service,
5137 pub username: Option<String>,
5138 pub password: Option<String>,
5139 pub token: Option<String>,
5140}
5141
5142impl AuthLoginSettings {
5143 pub fn resolve(args: AuthLoginArgs) -> Self {
5145 Self {
5146 service: args.service,
5147 username: args.username,
5148 password: args.password,
5149 token: args.token,
5150 }
5151 }
5152}
5153
5154mod env {
5156 use uv_static::EnvVars;
5157 pub(super) const UV_PYTHON_DOWNLOADS: (&str, &str) = (
5158 EnvVars::UV_PYTHON_DOWNLOADS,
5159 "one of 'auto', 'true', 'manual', 'never', or 'false'",
5160 );
5161}
5162
5163fn env<T>((name, expected): (&str, &str)) -> Option<T>
5168where
5169 T: FromStr,
5170{
5171 let val = match std::env::var(name) {
5172 Ok(val) => val,
5173 Err(VarError::NotPresent) => return None,
5174 Err(VarError::NotUnicode(_)) => parse_failure(name, expected),
5175 };
5176 Some(
5177 val.parse()
5178 .unwrap_or_else(|_| parse_failure(name, expected)),
5179 )
5180}
5181
5182#[expect(clippy::exit, clippy::print_stderr)]
5184fn parse_failure(name: &str, expected: &str) -> ! {
5185 eprintln!("error: invalid value for {name}, expected {expected}");
5186 process::exit(1)
5187}
5188
5189#[cfg(test)]
5190mod tests {
5191 use crate::{IndexArgs, RegistryClientArgs};
5192
5193 use super::*;
5194
5195 #[test]
5196 fn upgrade_settings_target_only_requested_package() -> anyhow::Result<()> {
5197 let package = PackageName::from_str("anyio")?;
5198 let settings = UpgradeSettings::resolve(
5199 UpgradeArgs {
5200 packages: vec![package.clone()],
5201 exclude: Vec::new(),
5202 index_args: IndexArgs {
5203 index: None,
5204 default_index: None,
5205 index_url: None,
5206 extra_index_url: None,
5207 find_links: None,
5208 no_index: false,
5209 },
5210 registry_client: RegistryClientArgs {
5211 index_strategy: None,
5212 keyring_provider: None,
5213 },
5214 require_build_hashes: false,
5215 no_require_build_hashes: false,
5216 },
5217 None,
5218 EnvironmentOptions::new()?,
5219 )?;
5220 let expected = FxHashSet::from_iter([package]);
5221
5222 assert!(!settings.settings.upgrade.is_all());
5223 assert_eq!(settings.settings.upgrade.packages(), Some(&expected));
5224 Ok(())
5225 }
5226}