1#[cfg(feature = "schemars")]
2use std::borrow::Cow;
3use std::{fmt::Debug, num::NonZeroUsize, path::Path, path::PathBuf};
4
5use serde::{Deserialize, Serialize};
6
7use uv_cache_info::CacheKey;
8use uv_configuration::{
9 BuildIsolation, ExcludeDependency, IndexStrategy, KeyringProviderType, PackageNameSpecifier,
10 ProxyUrl, Reinstall, RequiredVersion, TargetTriple, TrustedHost, TrustedPublishing, Upgrade,
11};
12use uv_distribution_types::{
13 ConfigSettings, ExtraBuildVariables, Index, IndexUrl, IndexUrlError, Origin,
14 PackageConfigSettings, PipExtraIndex, PipFindLinks, PipIndex, StaticMetadata,
15};
16use uv_install_wheel::LinkMode;
17use uv_macros::{CombineOptions, OptionsMetadata};
18use uv_normalize::{ExtraName, PackageName, PipGroupName};
19use uv_pep508::Requirement;
20use uv_preview::{MaybePreviewFeature, Preview};
21use uv_pypi_types::{SupportedEnvironments, VerbatimParsedUrl};
22use uv_python::{PythonDownloads, PythonPreference, PythonVersion};
23use uv_redacted::DisplaySafeUrl;
24use uv_resolver::{
25 AnnotationStyle, ExcludeNewerOverride, ExcludeNewerPackage, ExcludeNewerSpan,
26 ExcludeNewerValue, ForkStrategy, PrereleaseMode, ResolutionMode,
27 serialize_exclude_newer_package_with_spans,
28};
29use uv_torch::TorchMode;
30use uv_workspace::pyproject::{ExtraBuildDependencies, OverrideDependency};
31use uv_workspace::pyproject_mut::AddBoundsKind;
32
33use crate::{EnvironmentOptions, FilesystemOptions};
34
35#[allow(dead_code)]
37#[derive(Debug, Clone, Default, Deserialize)]
38pub(crate) struct PyProjectToml {
39 pub(crate) tool: Option<Tools>,
40}
41
42#[allow(dead_code)]
44#[derive(Debug, Clone, Default, Deserialize)]
45pub(crate) struct Tools {
46 pub(crate) uv: Option<Options>,
47}
48
49#[derive(Debug, Clone, Default, Deserialize)]
51pub(crate) struct PyProjectRequiredVersionToml {
52 pub(crate) tool: Option<RequiredVersionTools>,
53}
54
55#[derive(Debug, Clone, Default, Deserialize)]
57pub(crate) struct RequiredVersionTools {
58 pub(crate) uv: Option<RequiredVersionOptions>,
59}
60
61#[derive(Debug, Clone, Default, Deserialize)]
63#[serde(rename_all = "kebab-case")]
64pub(crate) struct RequiredVersionOptions {
65 pub(crate) required_version: Option<RequiredVersion>,
66}
67
68#[derive(Debug, Clone, Default, Deserialize)]
70#[serde(rename_all = "kebab-case")]
71pub(crate) struct UvRequiredVersionToml {
72 pub(crate) required_version: Option<RequiredVersion>,
73}
74
75#[allow(dead_code)]
77#[derive(Debug, Clone, Default, Deserialize, CombineOptions, OptionsMetadata)]
78#[serde(try_from = "OptionsWire", rename_all = "kebab-case")]
79#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
80#[cfg_attr(feature = "schemars", schemars(!try_from))]
81pub struct Options {
82 #[serde(flatten)]
83 pub globals: GlobalOptions,
84
85 #[serde(flatten)]
86 pub top_level: ResolverInstallerSchema,
87
88 #[serde(flatten)]
89 pub install_mirrors: PythonInstallMirrors,
90
91 #[serde(flatten)]
92 pub publish: PublishOptions,
93
94 #[serde(flatten)]
95 pub add: AddOptions,
96
97 #[option_group]
98 pub audit: Option<AuditOptions>,
99
100 #[option_group]
101 pub pip: Option<PipOptions>,
102
103 #[option(
139 default = r#"[{ file = "pyproject.toml" }, { file = "setup.py" }, { file = "setup.cfg" }]"#,
140 value_type = "list[dict]",
141 example = r#"
142 cache-keys = [{ file = "pyproject.toml" }, { file = "requirements.txt" }, { git = { commit = true } }]
143 "#
144 )]
145 pub cache_keys: Option<Vec<CacheKey>>,
146
147 #[cfg_attr(feature = "schemars", schemars(skip))]
151 pub override_dependencies: Option<Vec<OverrideDependency>>,
152
153 #[cfg_attr(feature = "schemars", schemars(skip))]
154 pub exclude_dependencies: Option<Vec<ExcludeDependency>>,
155
156 #[cfg_attr(feature = "schemars", schemars(skip))]
157 pub constraint_dependencies: Option<Vec<Requirement<VerbatimParsedUrl>>>,
158
159 #[cfg_attr(feature = "schemars", schemars(skip))]
160 pub build_constraint_dependencies: Option<Vec<Requirement<VerbatimParsedUrl>>>,
161
162 #[cfg_attr(feature = "schemars", schemars(skip))]
163 pub environments: Option<SupportedEnvironments>,
164
165 #[cfg_attr(feature = "schemars", schemars(skip))]
166 pub required_environments: Option<SupportedEnvironments>,
167
168 #[cfg_attr(feature = "schemars", schemars(skip))]
172 pub(crate) conflicts: Option<serde::de::IgnoredAny>,
173
174 #[cfg_attr(feature = "schemars", schemars(skip))]
175 pub(crate) workspace: Option<serde::de::IgnoredAny>,
176
177 #[cfg_attr(feature = "schemars", schemars(skip))]
178 pub(crate) sources: Option<serde::de::IgnoredAny>,
179
180 #[cfg_attr(feature = "schemars", schemars(skip))]
181 pub(crate) dev_dependencies: Option<serde::de::IgnoredAny>,
182
183 #[cfg_attr(feature = "schemars", schemars(skip))]
184 pub(crate) default_groups: Option<serde::de::IgnoredAny>,
185
186 #[cfg_attr(feature = "schemars", schemars(skip))]
187 pub(crate) dependency_groups: Option<serde::de::IgnoredAny>,
188
189 #[cfg_attr(feature = "schemars", schemars(skip))]
190 pub(crate) managed: Option<serde::de::IgnoredAny>,
191
192 #[cfg_attr(feature = "schemars", schemars(skip))]
193 pub(crate) r#package: Option<serde::de::IgnoredAny>,
194
195 #[cfg_attr(feature = "schemars", schemars(skip))]
196 pub(crate) build_backend: Option<serde::de::IgnoredAny>,
197}
198
199impl Options {
200 pub fn simple(globals: GlobalOptions, top_level: ResolverInstallerSchema) -> Self {
202 Self {
203 globals,
204 top_level,
205 ..Default::default()
206 }
207 }
208
209 #[must_use]
211 pub(crate) fn with_origin(mut self, origin: Origin) -> Self {
212 if let Some(indexes) = &mut self.top_level.index {
213 for index in indexes {
214 index.origin.get_or_insert(origin);
215 }
216 }
217 if let Some(index_url) = &mut self.top_level.index_url {
218 index_url.try_set_origin(origin);
219 }
220 if let Some(extra_index_urls) = &mut self.top_level.extra_index_url {
221 for index_url in extra_index_urls {
222 index_url.try_set_origin(origin);
223 }
224 }
225 if let Some(pip) = &mut self.pip {
226 if let Some(indexes) = &mut pip.index {
227 for index in indexes {
228 index.origin.get_or_insert(origin);
229 }
230 }
231 if let Some(index_url) = &mut pip.index_url {
232 index_url.try_set_origin(origin);
233 }
234 if let Some(extra_index_urls) = &mut pip.extra_index_url {
235 for index_url in extra_index_urls {
236 index_url.try_set_origin(origin);
237 }
238 }
239 }
240 self
241 }
242
243 pub(crate) fn relative_to(self, root_dir: &Path) -> Result<Self, IndexUrlError> {
245 Ok(Self {
246 top_level: self.top_level.relative_to(root_dir)?,
247 pip: self.pip.map(|pip| pip.relative_to(root_dir)).transpose()?,
248 ..self
249 })
250 }
251}
252
253#[derive(Debug, Clone, Default, Deserialize, CombineOptions, OptionsMetadata)]
255#[serde(try_from = "GlobalOptionsWire", rename_all = "kebab-case")]
256#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
257#[cfg_attr(feature = "schemars", schemars(!try_from))]
258pub struct GlobalOptions {
259 #[option(
266 default = "null",
267 value_type = "str",
268 example = r#"
269 required-version = ">=0.5.0"
270 "#
271 )]
272 pub required_version: Option<RequiredVersion>,
273 #[option(
278 default = "false",
279 value_type = "bool",
280 uv_toml_only = true,
281 example = r#"
282 system-certs = true
283 "#
284 )]
285 pub system_certs: Option<bool>,
286 #[deprecated(note = "use `system-certs` instead")]
293 #[option(
294 default = "false",
295 value_type = "bool",
296 uv_toml_only = true,
297 example = r#"
298 native-tls = true
299 "#
300 )]
301 pub native_tls: Option<bool>,
302 #[option(
304 default = "false",
305 value_type = "bool",
306 example = r#"
307 offline = true
308 "#
309 )]
310 pub offline: Option<bool>,
311 #[option(
314 default = "false",
315 value_type = "bool",
316 example = r#"
317 no-cache = true
318 "#
319 )]
320 pub no_cache: Option<bool>,
321 #[option(
326 default = "None",
327 value_type = "str",
328 uv_toml_only = true,
329 example = r#"
330 cache-dir = "./.uv_cache"
331 "#
332 )]
333 pub cache_dir: Option<PathBuf>,
334
335 #[serde(flatten)]
337 pub preview: Option<PreviewOption>,
338
339 #[option(
342 default = "\"managed\"",
343 value_type = "str",
344 example = r#"
345 python-preference = "managed"
346 "#,
347 possible_values = true
348 )]
349 pub python_preference: Option<PythonPreference>,
350 #[option(
352 default = "\"automatic\"",
353 value_type = "str",
354 example = r#"
355 python-downloads = "manual"
356 "#,
357 possible_values = true
358 )]
359 pub python_downloads: Option<PythonDownloads>,
360 #[option(
363 default = "50",
364 value_type = "int",
365 example = r#"
366 concurrent-downloads = 4
367 "#
368 )]
369 pub concurrent_downloads: Option<NonZeroUsize>,
370 #[option(
375 default = "None",
376 value_type = "int",
377 example = r#"
378 concurrent-builds = 4
379 "#
380 )]
381 pub concurrent_builds: Option<NonZeroUsize>,
382 #[option(
386 default = "None",
387 value_type = "int",
388 example = r#"
389 concurrent-installs = 4
390 "#
391 )]
392 pub concurrent_installs: Option<NonZeroUsize>,
393 #[option(
395 default = "None",
396 value_type = "str",
397 uv_toml_only = true,
398 example = r#"
399 http-proxy = "http://proxy.example.com"
400 "#
401 )]
402 pub http_proxy: Option<ProxyUrl>,
403 #[option(
405 default = "None",
406 value_type = "str",
407 uv_toml_only = true,
408 example = r#"
409 https-proxy = "https://proxy.example.com"
410 "#
411 )]
412 pub https_proxy: Option<ProxyUrl>,
413 #[option(
415 default = "None",
416 value_type = "list[str]",
417 uv_toml_only = true,
418 example = r#"
419 no-proxy = ["localhost", "127.0.0.1"]
420 "#
421 )]
422 pub no_proxy: Option<Vec<String>>,
423 #[option(
432 default = "[]",
433 value_type = "list[str]",
434 example = r#"
435 allow-insecure-host = ["localhost:8080"]
436 "#
437 )]
438 pub allow_insecure_host: Option<Vec<TrustedHost>>,
439}
440
441#[derive(Debug, Clone, Default, Deserialize)]
444#[serde(rename_all = "kebab-case")]
445struct GlobalOptionsWire {
446 required_version: Option<RequiredVersion>,
447 system_certs: Option<bool>,
448 native_tls: Option<bool>,
449 offline: Option<bool>,
450 no_cache: Option<bool>,
451 cache_dir: Option<PathBuf>,
452
453 preview: Option<bool>,
454 preview_features: Option<PreviewFeaturesOption>,
455
456 python_preference: Option<PythonPreference>,
457 python_downloads: Option<PythonDownloads>,
458 concurrent_downloads: Option<NonZeroUsize>,
459 concurrent_builds: Option<NonZeroUsize>,
460 concurrent_installs: Option<NonZeroUsize>,
461 http_proxy: Option<ProxyUrl>,
462 https_proxy: Option<ProxyUrl>,
463 no_proxy: Option<Vec<String>>,
464 allow_insecure_host: Option<Vec<TrustedHost>>,
465}
466
467impl TryFrom<GlobalOptionsWire> for GlobalOptions {
468 type Error = &'static str;
469
470 #[allow(deprecated)]
471 fn try_from(value: GlobalOptionsWire) -> Result<Self, Self::Error> {
472 let GlobalOptionsWire {
473 required_version,
474 system_certs,
475 native_tls,
476 offline,
477 no_cache,
478 cache_dir,
479 preview,
480 preview_features,
481 python_preference,
482 python_downloads,
483 concurrent_downloads,
484 concurrent_builds,
485 concurrent_installs,
486 http_proxy,
487 https_proxy,
488 no_proxy,
489 allow_insecure_host,
490 } = value;
491
492 Ok(Self {
493 required_version,
494 system_certs,
495 native_tls,
496 offline,
497 no_cache,
498 cache_dir,
499 preview: PreviewOption::try_from(preview, preview_features)?,
500 python_preference,
501 python_downloads,
502 concurrent_downloads,
503 concurrent_builds,
504 concurrent_installs,
505 http_proxy,
506 https_proxy,
507 no_proxy,
508 allow_insecure_host,
509 })
510 }
511}
512
513fn rebase_indexes(
515 root_dir: &Path,
516 indexes: &mut Option<Vec<Index>>,
517 index_url: &mut Option<PipIndex>,
518 extra_index_urls: &mut Option<Vec<PipExtraIndex>>,
519 find_links: &mut Option<Vec<PipFindLinks>>,
520) -> Result<(), IndexUrlError> {
521 *indexes = indexes
522 .take()
523 .map(|indexes| {
524 indexes
525 .into_iter()
526 .map(|index| index.relative_to(root_dir))
527 .collect::<Result<Vec<_>, _>>()
528 })
529 .transpose()?;
530 *index_url = index_url
531 .take()
532 .map(|index| index.relative_to(root_dir))
533 .transpose()?;
534 *extra_index_urls = extra_index_urls
535 .take()
536 .map(|indexes| {
537 indexes
538 .into_iter()
539 .map(|index| index.relative_to(root_dir))
540 .collect::<Result<Vec<_>, _>>()
541 })
542 .transpose()?;
543 *find_links = find_links
544 .take()
545 .map(|find_links| {
546 find_links
547 .into_iter()
548 .map(|find_link| find_link.relative_to(root_dir))
549 .collect::<Result<Vec<_>, _>>()
550 })
551 .transpose()?;
552
553 Ok(())
554}
555
556#[derive(Debug, Clone, Default, CombineOptions)]
558pub struct InstallerOptions {
559 index: Option<Vec<Index>>,
560 index_url: Option<PipIndex>,
561 extra_index_url: Option<Vec<PipExtraIndex>>,
562 no_index: Option<bool>,
563 find_links: Option<Vec<PipFindLinks>>,
564 index_strategy: Option<IndexStrategy>,
565 keyring_provider: Option<KeyringProviderType>,
566 config_settings: Option<ConfigSettings>,
567 exclude_newer: Option<ExcludeNewerOverride>,
568 link_mode: Option<LinkMode>,
569 compile_bytecode: Option<bool>,
570 reinstall: Option<Reinstall>,
571 build_isolation: Option<BuildIsolation>,
572 no_build: Option<bool>,
573 no_build_package: Option<Vec<PackageName>>,
574 no_binary: Option<bool>,
575 no_binary_package: Option<Vec<PackageName>>,
576 no_sources: Option<bool>,
577 no_sources_package: Option<Vec<PackageName>>,
578}
579
580#[derive(Debug, Clone, Default, CombineOptions)]
582pub struct ResolverOptions {
583 pub index: Option<Vec<Index>>,
584 pub index_url: Option<PipIndex>,
585 pub extra_index_url: Option<Vec<PipExtraIndex>>,
586 pub no_index: Option<bool>,
587 pub find_links: Option<Vec<PipFindLinks>>,
588 pub index_strategy: Option<IndexStrategy>,
589 pub keyring_provider: Option<KeyringProviderType>,
590 pub resolution: Option<ResolutionMode>,
591 pub prerelease: Option<PrereleaseMode>,
592 pub fork_strategy: Option<ForkStrategy>,
593 pub dependency_metadata: Option<Vec<StaticMetadata>>,
594 pub config_settings: Option<ConfigSettings>,
595 pub config_settings_package: Option<PackageConfigSettings>,
596 pub exclude_newer: Option<ExcludeNewerOverride>,
597 pub exclude_newer_package: Option<ExcludeNewerPackage>,
598 pub link_mode: Option<LinkMode>,
599 pub torch_backend: Option<TorchMode>,
600 pub upgrade: Option<Upgrade>,
601 pub build_isolation: Option<BuildIsolation>,
602 pub no_build: Option<bool>,
603 pub no_build_package: Option<Vec<PackageName>>,
604 pub no_binary: Option<bool>,
605 pub no_binary_package: Option<Vec<PackageName>>,
606 pub extra_build_dependencies: Option<ExtraBuildDependencies>,
607 pub extra_build_variables: Option<ExtraBuildVariables>,
608 pub no_sources: Option<bool>,
609 pub no_sources_package: Option<Vec<PackageName>>,
610}
611
612impl ResolverOptions {
613 pub fn relative_to(mut self, root_dir: &Path) -> Result<Self, IndexUrlError> {
615 rebase_indexes(
616 root_dir,
617 &mut self.index,
618 &mut self.index_url,
619 &mut self.extra_index_url,
620 &mut self.find_links,
621 )?;
622
623 Ok(self)
624 }
625}
626
627#[derive(Debug, Clone, Default, CombineOptions)]
630pub struct ResolverInstallerOptions {
631 pub index: Option<Vec<Index>>,
632 pub index_url: Option<PipIndex>,
633 pub extra_index_url: Option<Vec<PipExtraIndex>>,
634 pub no_index: Option<bool>,
635 pub find_links: Option<Vec<PipFindLinks>>,
636 pub index_strategy: Option<IndexStrategy>,
637 pub keyring_provider: Option<KeyringProviderType>,
638 pub resolution: Option<ResolutionMode>,
639 pub prerelease: Option<PrereleaseMode>,
640 pub fork_strategy: Option<ForkStrategy>,
641 pub dependency_metadata: Option<Vec<StaticMetadata>>,
642 pub config_settings: Option<ConfigSettings>,
643 pub config_settings_package: Option<PackageConfigSettings>,
644 pub build_isolation: Option<BuildIsolation>,
645 pub extra_build_dependencies: Option<ExtraBuildDependencies>,
646 pub extra_build_variables: Option<ExtraBuildVariables>,
647 pub exclude_newer: Option<ExcludeNewerOverride>,
648 pub exclude_newer_package: Option<ExcludeNewerPackage>,
649 pub link_mode: Option<LinkMode>,
650 pub torch_backend: Option<TorchMode>,
651 pub compile_bytecode: Option<bool>,
652 pub no_sources: Option<bool>,
653 pub no_sources_package: Option<Vec<PackageName>>,
654 pub upgrade: Option<Upgrade>,
655 pub reinstall: Option<Reinstall>,
656 pub no_build: Option<bool>,
657 pub no_build_package: Option<Vec<PackageName>>,
658 pub no_binary: Option<bool>,
659 pub no_binary_package: Option<Vec<PackageName>>,
660}
661
662impl ResolverInstallerOptions {
663 pub fn relative_to(mut self, root_dir: &Path) -> Result<Self, IndexUrlError> {
665 rebase_indexes(
666 root_dir,
667 &mut self.index,
668 &mut self.index_url,
669 &mut self.extra_index_url,
670 &mut self.find_links,
671 )?;
672
673 Ok(self)
674 }
675}
676
677impl From<ResolverInstallerSchema> for ResolverInstallerOptions {
678 fn from(value: ResolverInstallerSchema) -> Self {
679 let ResolverInstallerSchema {
680 index,
681 index_url,
682 extra_index_url,
683 no_index,
684 find_links,
685 index_strategy,
686 keyring_provider,
687 resolution,
688 prerelease,
689 fork_strategy,
690 dependency_metadata,
691 config_settings,
692 config_settings_package,
693 no_build_isolation,
694 no_build_isolation_package,
695 extra_build_dependencies,
696 extra_build_variables,
697 exclude_newer,
698 exclude_newer_package,
699 link_mode,
700 torch_backend,
701 compile_bytecode,
702 no_sources,
703 no_sources_package,
704 upgrade,
705 upgrade_package,
706 reinstall,
707 reinstall_package,
708 no_build,
709 no_build_package,
710 no_binary,
711 no_binary_package,
712 } = value;
713 Self {
714 index,
715 index_url,
716 extra_index_url,
717 no_index,
718 find_links,
719 index_strategy,
720 keyring_provider,
721 resolution,
722 prerelease,
723 fork_strategy,
724 dependency_metadata,
725 config_settings,
726 config_settings_package,
727 build_isolation: BuildIsolation::from_args(
728 no_build_isolation,
729 no_build_isolation_package.into_iter().flatten().collect(),
730 ),
731 extra_build_dependencies,
732 extra_build_variables,
733 exclude_newer,
734 exclude_newer_package,
735 link_mode,
736 torch_backend,
737 compile_bytecode,
738 no_sources,
739 no_sources_package,
740 upgrade: Upgrade::from_args(
741 upgrade,
742 upgrade_package
743 .into_iter()
744 .flatten()
745 .map(Into::into)
746 .collect(),
747 Vec::new(),
748 ),
749 reinstall: Reinstall::from_args(reinstall, reinstall_package.unwrap_or_default()),
750 no_build,
751 no_build_package,
752 no_binary,
753 no_binary_package,
754 }
755 }
756}
757
758impl ResolverInstallerSchema {
759 fn relative_to(mut self, root_dir: &Path) -> Result<Self, IndexUrlError> {
761 rebase_indexes(
762 root_dir,
763 &mut self.index,
764 &mut self.index_url,
765 &mut self.extra_index_url,
766 &mut self.find_links,
767 )?;
768
769 Ok(self)
770 }
771}
772
773#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, CombineOptions, OptionsMetadata)]
775#[serde(rename_all = "kebab-case")]
776#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
777pub struct ResolverInstallerSchema {
778 #[option(
806 default = "\"[]\"",
807 value_type = "dict",
808 example = r#"
809 [[tool.uv.index]]
810 name = "pytorch"
811 url = "https://download.pytorch.org/whl/cu130"
812 "#
813 )]
814 pub index: Option<Vec<Index>>,
815 #[option(
825 default = "\"https://pypi.org/simple\"",
826 value_type = "str",
827 example = r#"
828 index-url = "https://test.pypi.org/simple"
829 "#
830 )]
831 pub index_url: Option<PipIndex>,
832 #[option(
846 default = "[]",
847 value_type = "list[str]",
848 example = r#"
849 extra-index-url = ["https://download.pytorch.org/whl/cpu"]
850 "#
851 )]
852 pub extra_index_url: Option<Vec<PipExtraIndex>>,
853 #[option(
856 default = "false",
857 value_type = "bool",
858 example = r#"
859 no-index = true
860 "#
861 )]
862 pub no_index: Option<bool>,
863 #[option(
872 default = "[]",
873 value_type = "list[str]",
874 example = r#"
875 find-links = ["https://download.pytorch.org/whl/torch_stable.html"]
876 "#
877 )]
878 pub find_links: Option<Vec<PipFindLinks>>,
879 #[option(
886 default = "\"first-index\"",
887 value_type = "str",
888 example = r#"
889 index-strategy = "unsafe-best-match"
890 "#,
891 possible_values = true
892 )]
893 pub index_strategy: Option<IndexStrategy>,
894 #[option(
899 default = "\"disabled\"",
900 value_type = "str",
901 example = r#"
902 keyring-provider = "subprocess"
903 "#
904 )]
905 pub keyring_provider: Option<KeyringProviderType>,
906 #[option(
911 default = "\"highest\"",
912 value_type = "str",
913 example = r#"
914 resolution = "lowest-direct"
915 "#,
916 possible_values = true
917 )]
918 pub resolution: Option<ResolutionMode>,
919 #[option(
925 default = "\"if-necessary\"",
926 value_type = "str",
927 example = r#"
928 prerelease = "allow"
929 "#,
930 possible_values = true
931 )]
932 pub prerelease: Option<PrereleaseMode>,
933 #[option(
944 default = "\"requires-python\"",
945 value_type = "str",
946 example = r#"
947 fork-strategy = "fewest"
948 "#,
949 possible_values = true
950 )]
951 pub fork_strategy: Option<ForkStrategy>,
952 #[option(
966 default = r#"[]"#,
967 value_type = "list[dict]",
968 example = r#"
969 dependency-metadata = [
970 { name = "flask", version = "1.0.0", requires-dist = ["werkzeug"], requires-python = ">=3.6" },
971 ]
972 "#
973 )]
974 pub dependency_metadata: Option<Vec<StaticMetadata>>,
975 #[option(
978 default = "{}",
979 value_type = "dict",
980 example = r#"
981 config-settings = { editable_mode = "compat" }
982 "#
983 )]
984 pub config_settings: Option<ConfigSettings>,
985 #[option(
990 default = "{}",
991 value_type = "dict",
992 example = r#"
993 config-settings-package = { numpy = { editable_mode = "compat" } }
994 "#
995 )]
996 pub config_settings_package: Option<PackageConfigSettings>,
997 #[option(
1002 default = "false",
1003 value_type = "bool",
1004 example = r#"
1005 no-build-isolation = true
1006 "#
1007 )]
1008 pub no_build_isolation: Option<bool>,
1009 #[option(
1014 default = "[]",
1015 value_type = "list[str]",
1016 example = r#"
1017 no-build-isolation-package = ["package1", "package2"]
1018 "#
1019 )]
1020 pub no_build_isolation_package: Option<Vec<PackageName>>,
1021 #[option(
1027 default = "[]",
1028 value_type = "dict",
1029 example = r#"
1030 extra-build-dependencies = { pytest = ["setuptools"] }
1031 "#
1032 )]
1033 pub extra_build_dependencies: Option<ExtraBuildDependencies>,
1034 #[option(
1039 default = r#"{}"#,
1040 value_type = r#"dict[str, dict[str, str]]"#,
1041 example = r#"
1042 extra-build-variables = { flash-attn = { FLASH_ATTENTION_SKIP_CUDA_BUILD = "TRUE" } }
1043 "#
1044 )]
1045 pub extra_build_variables: Option<ExtraBuildVariables>,
1046 #[option(
1061 default = "None",
1062 value_type = "str | false",
1063 example = r#"
1064 exclude-newer = "2006-12-02T02:07:43Z"
1065 "#
1066 )]
1067 pub exclude_newer: Option<ExcludeNewerOverride>,
1068 #[option(
1082 default = "None",
1083 value_type = "dict",
1084 example = r#"
1085 exclude-newer-package = { tqdm = "2022-04-04T00:00:00Z", markupsafe = false }
1086 "#
1087 )]
1088 pub exclude_newer_package: Option<ExcludeNewerPackage>,
1089 #[option(
1099 default = "\"clone\" (macOS, Linux) or \"hardlink\" (Windows)",
1100 value_type = "str",
1101 example = r#"
1102 link-mode = "copy"
1103 "#,
1104 possible_values = true
1105 )]
1106 pub link_mode: Option<LinkMode>,
1107 #[option(
1118 default = "false",
1119 value_type = "bool",
1120 example = r#"
1121 compile-bytecode = true
1122 "#
1123 )]
1124 pub compile_bytecode: Option<bool>,
1125 #[option(
1129 default = "false",
1130 value_type = "bool",
1131 example = r#"
1132 no-sources = true
1133 "#
1134 )]
1135 pub no_sources: Option<bool>,
1136 #[option(
1138 default = "[]",
1139 value_type = "list[str]",
1140 example = r#"
1141 no-sources-package = ["ruff"]
1142 "#
1143 )]
1144 pub no_sources_package: Option<Vec<PackageName>>,
1145 #[option(
1147 default = "false",
1148 value_type = "bool",
1149 example = r#"
1150 upgrade = true
1151 "#
1152 )]
1153 pub upgrade: Option<bool>,
1154 #[option(
1159 default = "[]",
1160 value_type = "list[str]",
1161 example = r#"
1162 upgrade-package = ["ruff"]
1163 "#
1164 )]
1165 pub upgrade_package: Option<Vec<Requirement<VerbatimParsedUrl>>>,
1166 #[option(
1168 default = "false",
1169 value_type = "bool",
1170 example = r#"
1171 reinstall = true
1172 "#
1173 )]
1174 pub reinstall: Option<bool>,
1175 #[option(
1178 default = "[]",
1179 value_type = "list[str]",
1180 example = r#"
1181 reinstall-package = ["ruff"]
1182 "#
1183 )]
1184 pub reinstall_package: Option<Vec<PackageName>>,
1185 #[option(
1191 default = "false",
1192 value_type = "bool",
1193 example = r#"
1194 no-build = true
1195 "#
1196 )]
1197 pub no_build: Option<bool>,
1198 #[option(
1200 default = "[]",
1201 value_type = "list[str]",
1202 example = r#"
1203 no-build-package = ["ruff"]
1204 "#
1205 )]
1206 pub no_build_package: Option<Vec<PackageName>>,
1207 #[option(
1212 default = "false",
1213 value_type = "bool",
1214 example = r#"
1215 no-binary = true
1216 "#
1217 )]
1218 pub no_binary: Option<bool>,
1219 #[option(
1221 default = "[]",
1222 value_type = "list[str]",
1223 example = r#"
1224 no-binary-package = ["ruff"]
1225 "#
1226 )]
1227 pub no_binary_package: Option<Vec<PackageName>>,
1228 #[option(
1243 default = "null",
1244 value_type = "str",
1245 example = r#"
1246 torch-backend = "auto"
1247 "#
1248 )]
1249 pub torch_backend: Option<TorchMode>,
1250}
1251
1252#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, CombineOptions, OptionsMetadata)]
1254#[serde(rename_all = "kebab-case")]
1255#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1256pub struct PythonInstallMirrors {
1257 #[option(
1265 default = "None",
1266 value_type = "str",
1267 uv_toml_only = true,
1268 example = r#"
1269 python-install-mirror = "https://github.com/astral-sh/python-build-standalone/releases/download"
1270 "#
1271 )]
1272 pub python_install_mirror: Option<String>,
1273 #[option(
1282 default = "None",
1283 value_type = "str",
1284 uv_toml_only = true,
1285 example = r#"
1286 pypy-install-mirror = "https://downloads.python.org/pypy"
1287 "#
1288 )]
1289 pub pypy_install_mirror: Option<String>,
1290
1291 #[option(
1293 default = "None",
1294 value_type = "str",
1295 uv_toml_only = true,
1296 example = r#"
1297 python-downloads-json-url = "/etc/uv/python-downloads.json"
1298 "#
1299 )]
1300 pub python_downloads_json_url: Option<String>,
1301}
1302
1303impl PythonInstallMirrors {
1304 #[must_use]
1305 pub fn combine(self, other: Self) -> Self {
1306 Self {
1307 python_install_mirror: self.python_install_mirror.or(other.python_install_mirror),
1308 pypy_install_mirror: self.pypy_install_mirror.or(other.pypy_install_mirror),
1309 python_downloads_json_url: self
1310 .python_downloads_json_url
1311 .or(other.python_downloads_json_url),
1312 }
1313 }
1314}
1315
1316#[derive(Debug, Clone, Default, Deserialize, CombineOptions, OptionsMetadata)]
1321#[serde(deny_unknown_fields, rename_all = "kebab-case")]
1322#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1323pub struct PipOptions {
1324 #[option(
1337 default = "None",
1338 value_type = "str",
1339 example = r#"
1340 python = "3.10"
1341 "#
1342 )]
1343 pub python: Option<String>,
1344 #[option(
1353 default = "false",
1354 value_type = "bool",
1355 example = r#"
1356 system = true
1357 "#
1358 )]
1359 pub system: Option<bool>,
1360 #[option(
1367 default = "false",
1368 value_type = "bool",
1369 example = r#"
1370 break-system-packages = true
1371 "#
1372 )]
1373 pub break_system_packages: Option<bool>,
1374 #[option(
1377 default = "None",
1378 value_type = "str",
1379 example = r#"
1380 target = "./target"
1381 "#
1382 )]
1383 pub target: Option<PathBuf>,
1384 #[option(
1392 default = "None",
1393 value_type = "str",
1394 example = r#"
1395 prefix = "./prefix"
1396 "#
1397 )]
1398 pub prefix: Option<PathBuf>,
1399 #[serde(skip)]
1400 #[cfg_attr(feature = "schemars", schemars(skip))]
1401 pub index: Option<Vec<Index>>,
1402 #[option(
1410 default = "\"https://pypi.org/simple\"",
1411 value_type = "str",
1412 example = r#"
1413 index-url = "https://test.pypi.org/simple"
1414 "#
1415 )]
1416 pub index_url: Option<PipIndex>,
1417 #[option(
1428 default = "[]",
1429 value_type = "list[str]",
1430 example = r#"
1431 extra-index-url = ["https://download.pytorch.org/whl/cpu"]
1432 "#
1433 )]
1434 pub extra_index_url: Option<Vec<PipExtraIndex>>,
1435 #[option(
1438 default = "false",
1439 value_type = "bool",
1440 example = r#"
1441 no-index = true
1442 "#
1443 )]
1444 pub no_index: Option<bool>,
1445 #[option(
1454 default = "[]",
1455 value_type = "list[str]",
1456 example = r#"
1457 find-links = ["https://download.pytorch.org/whl/torch_stable.html"]
1458 "#
1459 )]
1460 pub find_links: Option<Vec<PipFindLinks>>,
1461 #[option(
1468 default = "\"first-index\"",
1469 value_type = "str",
1470 example = r#"
1471 index-strategy = "unsafe-best-match"
1472 "#,
1473 possible_values = true
1474 )]
1475 pub index_strategy: Option<IndexStrategy>,
1476 #[option(
1481 default = "disabled",
1482 value_type = "str",
1483 example = r#"
1484 keyring-provider = "subprocess"
1485 "#
1486 )]
1487 pub keyring_provider: Option<KeyringProviderType>,
1488 #[option(
1496 default = "false",
1497 value_type = "bool",
1498 example = r#"
1499 no-build = true
1500 "#
1501 )]
1502 pub no_build: Option<bool>,
1503 #[option(
1511 default = "[]",
1512 value_type = "list[str]",
1513 example = r#"
1514 no-binary = ["ruff"]
1515 "#
1516 )]
1517 pub no_binary: Option<Vec<PackageNameSpecifier>>,
1518 #[option(
1528 default = "[]",
1529 value_type = "list[str]",
1530 example = r#"
1531 only-binary = ["ruff"]
1532 "#
1533 )]
1534 pub only_binary: Option<Vec<PackageNameSpecifier>>,
1535 #[option(
1540 default = "false",
1541 value_type = "bool",
1542 example = r#"
1543 no-build-isolation = true
1544 "#
1545 )]
1546 pub no_build_isolation: Option<bool>,
1547 #[option(
1552 default = "[]",
1553 value_type = "list[str]",
1554 example = r#"
1555 no-build-isolation-package = ["package1", "package2"]
1556 "#
1557 )]
1558 pub no_build_isolation_package: Option<Vec<PackageName>>,
1559 #[option(
1565 default = "[]",
1566 value_type = "dict",
1567 example = r#"
1568 extra-build-dependencies = { pytest = ["setuptools"] }
1569 "#
1570 )]
1571 pub extra_build_dependencies: Option<ExtraBuildDependencies>,
1572 #[option(
1577 default = r#"{}"#,
1578 value_type = r#"dict[str, dict[str, str]]"#,
1579 example = r#"
1580 extra-build-variables = { flash-attn = { FLASH_ATTENTION_SKIP_CUDA_BUILD = "TRUE" } }
1581 "#
1582 )]
1583 pub extra_build_variables: Option<ExtraBuildVariables>,
1584 #[option(
1587 default = "false",
1588 value_type = "bool",
1589 example = r#"
1590 strict = true
1591 "#
1592 )]
1593 pub strict: Option<bool>,
1594 #[option(
1598 default = "[]",
1599 value_type = "list[str]",
1600 example = r#"
1601 extra = ["dev", "docs"]
1602 "#
1603 )]
1604 pub extra: Option<Vec<ExtraName>>,
1605 #[option(
1609 default = "false",
1610 value_type = "bool",
1611 example = r#"
1612 all-extras = true
1613 "#
1614 )]
1615 pub all_extras: Option<bool>,
1616 #[option(
1618 default = "[]",
1619 value_type = "list[str]",
1620 example = r#"
1621 all-extras = true
1622 no-extra = ["dev", "docs"]
1623 "#
1624 )]
1625 pub no_extra: Option<Vec<ExtraName>>,
1626 #[option(
1629 default = "false",
1630 value_type = "bool",
1631 example = r#"
1632 no-deps = true
1633 "#
1634 )]
1635 pub no_deps: Option<bool>,
1636 #[option(
1638 default = "None",
1639 value_type = "list[str]",
1640 example = r#"
1641 group = ["dev", "docs"]
1642 "#
1643 )]
1644 pub group: Option<Vec<PipGroupName>>,
1645 #[option(
1648 default = "false",
1649 value_type = "bool",
1650 example = r#"
1651 allow-empty-requirements = true
1652 "#
1653 )]
1654 pub allow_empty_requirements: Option<bool>,
1655 #[option(
1660 default = "\"highest\"",
1661 value_type = "str",
1662 example = r#"
1663 resolution = "lowest-direct"
1664 "#,
1665 possible_values = true
1666 )]
1667 pub resolution: Option<ResolutionMode>,
1668 #[option(
1674 default = "\"if-necessary\"",
1675 value_type = "str",
1676 example = r#"
1677 prerelease = "allow"
1678 "#,
1679 possible_values = true
1680 )]
1681 pub prerelease: Option<PrereleaseMode>,
1682 #[option(
1693 default = "\"requires-python\"",
1694 value_type = "str",
1695 example = r#"
1696 fork-strategy = "fewest"
1697 "#,
1698 possible_values = true
1699 )]
1700 pub fork_strategy: Option<ForkStrategy>,
1701 #[option(
1715 default = r#"[]"#,
1716 value_type = "list[dict]",
1717 example = r#"
1718 dependency-metadata = [
1719 { name = "flask", version = "1.0.0", requires-dist = ["werkzeug"], requires-python = ">=3.6" },
1720 ]
1721 "#
1722 )]
1723 pub dependency_metadata: Option<Vec<StaticMetadata>>,
1724 #[option(
1729 default = "None",
1730 value_type = "str",
1731 example = r#"
1732 output-file = "requirements.txt"
1733 "#
1734 )]
1735 pub output_file: Option<PathBuf>,
1736 #[option(
1742 default = "false",
1743 value_type = "bool",
1744 example = r#"
1745 no-strip-extras = true
1746 "#
1747 )]
1748 pub no_strip_extras: Option<bool>,
1749 #[option(
1754 default = "false",
1755 value_type = "bool",
1756 example = r#"
1757 no-strip-markers = true
1758 "#
1759 )]
1760 pub no_strip_markers: Option<bool>,
1761 #[option(
1764 default = "false",
1765 value_type = "bool",
1766 example = r#"
1767 no-annotate = true
1768 "#
1769 )]
1770 pub no_annotate: Option<bool>,
1771 #[option(
1773 default = r#"false"#,
1774 value_type = "bool",
1775 example = r#"
1776 no-header = true
1777 "#
1778 )]
1779 pub no_header: Option<bool>,
1780 #[option(
1784 default = "None",
1785 value_type = "str",
1786 example = r#"
1787 custom-compile-command = "./custom-uv-compile.sh"
1788 "#
1789 )]
1790 pub custom_compile_command: Option<String>,
1791 #[option(
1793 default = "false",
1794 value_type = "bool",
1795 example = r#"
1796 generate-hashes = true
1797 "#
1798 )]
1799 pub generate_hashes: Option<bool>,
1800 #[option(
1803 default = "{}",
1804 value_type = "dict",
1805 example = r#"
1806 config-settings = { editable_mode = "compat" }
1807 "#
1808 )]
1809 pub config_settings: Option<ConfigSettings>,
1810 #[option(
1813 default = "{}",
1814 value_type = "dict",
1815 example = r#"
1816 config-settings-package = { numpy = { editable_mode = "compat" } }
1817 "#
1818 )]
1819 pub config_settings_package: Option<PackageConfigSettings>,
1820 #[option(
1826 default = "None",
1827 value_type = "str",
1828 example = r#"
1829 python-version = "3.8"
1830 "#
1831 )]
1832 pub python_version: Option<PythonVersion>,
1833 #[option(
1839 default = "None",
1840 value_type = "str",
1841 example = r#"
1842 python-platform = "x86_64-unknown-linux-gnu"
1843 "#
1844 )]
1845 pub python_platform: Option<TargetTriple>,
1846 #[option(
1854 default = "false",
1855 value_type = "bool",
1856 example = r#"
1857 universal = true
1858 "#
1859 )]
1860 pub universal: Option<bool>,
1861 #[option(
1876 default = "None",
1877 value_type = "str | false",
1878 example = r#"
1879 exclude-newer = "2006-12-02T02:07:43Z"
1880 "#
1881 )]
1882 pub exclude_newer: Option<ExcludeNewerOverride>,
1883 #[option(
1896 default = "None",
1897 value_type = "dict",
1898 example = r#"
1899 exclude-newer-package = { tqdm = "2022-04-04T00:00:00Z", markupsafe = false }
1900 "#
1901 )]
1902 pub exclude_newer_package: Option<ExcludeNewerPackage>,
1903 #[option(
1906 default = "[]",
1907 value_type = "list[str]",
1908 example = r#"
1909 no-emit-package = ["ruff"]
1910 "#
1911 )]
1912 pub no_emit_package: Option<Vec<PackageName>>,
1913 #[option(
1915 default = "false",
1916 value_type = "bool",
1917 example = r#"
1918 emit-index-url = true
1919 "#
1920 )]
1921 pub emit_index_url: Option<bool>,
1922 #[option(
1924 default = "false",
1925 value_type = "bool",
1926 example = r#"
1927 emit-find-links = true
1928 "#
1929 )]
1930 pub emit_find_links: Option<bool>,
1931 #[option(
1933 default = "false",
1934 value_type = "bool",
1935 example = r#"
1936 emit-build-options = true
1937 "#
1938 )]
1939 pub emit_build_options: Option<bool>,
1940 #[option(
1947 default = "false",
1948 value_type = "bool",
1949 example = r#"
1950 emit-marker-expression = true
1951 "#
1952 )]
1953 pub emit_marker_expression: Option<bool>,
1954 #[option(
1957 default = "false",
1958 value_type = "bool",
1959 example = r#"
1960 emit-index-annotation = true
1961 "#
1962 )]
1963 pub emit_index_annotation: Option<bool>,
1964 #[option(
1967 default = "\"split\"",
1968 value_type = "str",
1969 example = r#"
1970 annotation-style = "line"
1971 "#,
1972 possible_values = true
1973 )]
1974 pub annotation_style: Option<AnnotationStyle>,
1975 #[option(
1985 default = "\"clone\" (macOS, Linux) or \"hardlink\" (Windows)",
1986 value_type = "str",
1987 example = r#"
1988 link-mode = "copy"
1989 "#,
1990 possible_values = true
1991 )]
1992 pub link_mode: Option<LinkMode>,
1993 #[option(
2004 default = "false",
2005 value_type = "bool",
2006 example = r#"
2007 compile-bytecode = true
2008 "#
2009 )]
2010 pub compile_bytecode: Option<bool>,
2011 #[option(
2024 default = "false",
2025 value_type = "bool",
2026 example = r#"
2027 require-hashes = true
2028 "#
2029 )]
2030 pub require_hashes: Option<bool>,
2031 #[option(
2037 default = "true",
2038 value_type = "bool",
2039 example = r#"
2040 verify-hashes = true
2041 "#
2042 )]
2043 pub verify_hashes: Option<bool>,
2044 #[option(
2048 default = "false",
2049 value_type = "bool",
2050 example = r#"
2051 no-sources = true
2052 "#
2053 )]
2054 pub no_sources: Option<bool>,
2055 #[option(
2057 default = "[]",
2058 value_type = "list[str]",
2059 example = r#"
2060 no-sources-package = ["ruff"]
2061 "#
2062 )]
2063 pub no_sources_package: Option<Vec<PackageName>>,
2064 #[option(
2066 default = "false",
2067 value_type = "bool",
2068 example = r#"
2069 upgrade = true
2070 "#
2071 )]
2072 pub upgrade: Option<bool>,
2073 #[option(
2078 default = "[]",
2079 value_type = "list[str]",
2080 example = r#"
2081 upgrade-package = ["ruff"]
2082 "#
2083 )]
2084 pub upgrade_package: Option<Vec<Requirement<VerbatimParsedUrl>>>,
2085 #[option(
2087 default = "false",
2088 value_type = "bool",
2089 example = r#"
2090 reinstall = true
2091 "#
2092 )]
2093 pub reinstall: Option<bool>,
2094 #[option(
2097 default = "[]",
2098 value_type = "list[str]",
2099 example = r#"
2100 reinstall-package = ["ruff"]
2101 "#
2102 )]
2103 pub reinstall_package: Option<Vec<PackageName>>,
2104 #[option(
2119 default = "null",
2120 value_type = "str",
2121 example = r#"
2122 torch-backend = "auto"
2123 "#
2124 )]
2125 pub torch_backend: Option<TorchMode>,
2126}
2127
2128impl PipOptions {
2129 pub fn relative_to(mut self, root_dir: &Path) -> Result<Self, IndexUrlError> {
2131 rebase_indexes(
2132 root_dir,
2133 &mut self.index,
2134 &mut self.index_url,
2135 &mut self.extra_index_url,
2136 &mut self.find_links,
2137 )?;
2138
2139 Ok(self)
2140 }
2141}
2142
2143impl From<ResolverInstallerSchema> for ResolverOptions {
2144 fn from(value: ResolverInstallerSchema) -> Self {
2145 Self {
2146 index: value.index,
2147 index_url: value.index_url,
2148 extra_index_url: value.extra_index_url,
2149 no_index: value.no_index,
2150 find_links: value.find_links,
2151 index_strategy: value.index_strategy,
2152 keyring_provider: value.keyring_provider,
2153 resolution: value.resolution,
2154 prerelease: value.prerelease,
2155 fork_strategy: value.fork_strategy,
2156 dependency_metadata: value.dependency_metadata,
2157 config_settings: value.config_settings,
2158 config_settings_package: value.config_settings_package,
2159 exclude_newer: value.exclude_newer,
2160 exclude_newer_package: value.exclude_newer_package,
2161 link_mode: value.link_mode,
2162 upgrade: Upgrade::from_args(
2163 value.upgrade,
2164 value
2165 .upgrade_package
2166 .into_iter()
2167 .flatten()
2168 .map(Into::into)
2169 .collect(),
2170 Vec::new(),
2171 ),
2172 no_build: value.no_build,
2173 no_build_package: value.no_build_package,
2174 no_binary: value.no_binary,
2175 no_binary_package: value.no_binary_package,
2176 build_isolation: BuildIsolation::from_args(
2177 value.no_build_isolation,
2178 value.no_build_isolation_package.unwrap_or_default(),
2179 ),
2180 extra_build_dependencies: value.extra_build_dependencies,
2181 extra_build_variables: value.extra_build_variables,
2182 no_sources: value.no_sources,
2183 no_sources_package: value.no_sources_package,
2184 torch_backend: value.torch_backend,
2185 }
2186 }
2187}
2188
2189impl From<ResolverInstallerSchema> for InstallerOptions {
2190 fn from(value: ResolverInstallerSchema) -> Self {
2191 Self {
2192 index: value.index,
2193 index_url: value.index_url,
2194 extra_index_url: value.extra_index_url,
2195 no_index: value.no_index,
2196 find_links: value.find_links,
2197 index_strategy: value.index_strategy,
2198 keyring_provider: value.keyring_provider,
2199 config_settings: value.config_settings,
2200 exclude_newer: value.exclude_newer,
2201 link_mode: value.link_mode,
2202 compile_bytecode: value.compile_bytecode,
2203 reinstall: Reinstall::from_args(
2204 value.reinstall,
2205 value.reinstall_package.unwrap_or_default(),
2206 ),
2207 build_isolation: BuildIsolation::from_args(
2208 value.no_build_isolation,
2209 value.no_build_isolation_package.unwrap_or_default(),
2210 ),
2211 no_build: value.no_build,
2212 no_build_package: value.no_build_package,
2213 no_binary: value.no_binary,
2214 no_binary_package: value.no_binary_package,
2215 no_sources: value.no_sources,
2216 no_sources_package: value.no_sources_package,
2217 }
2218 }
2219}
2220
2221#[derive(
2226 Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, CombineOptions, OptionsMetadata,
2227)]
2228#[serde(deny_unknown_fields, rename_all = "kebab-case")]
2229#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2230pub struct ToolOptions {
2231 index: Option<Vec<Index>>,
2232 index_url: Option<PipIndex>,
2233 extra_index_url: Option<Vec<PipExtraIndex>>,
2234 no_index: Option<bool>,
2235 find_links: Option<Vec<PipFindLinks>>,
2236 index_strategy: Option<IndexStrategy>,
2237 keyring_provider: Option<KeyringProviderType>,
2238 resolution: Option<ResolutionMode>,
2239 prerelease: Option<PrereleaseMode>,
2240 fork_strategy: Option<ForkStrategy>,
2241 dependency_metadata: Option<Vec<StaticMetadata>>,
2242 config_settings: Option<ConfigSettings>,
2243 config_settings_package: Option<PackageConfigSettings>,
2244 build_isolation: Option<BuildIsolation>,
2245 extra_build_dependencies: Option<ExtraBuildDependencies>,
2246 extra_build_variables: Option<ExtraBuildVariables>,
2247 exclude_newer: Option<ExcludeNewerOverride>,
2248 exclude_newer_package: Option<ExcludeNewerPackage>,
2249 link_mode: Option<LinkMode>,
2250 compile_bytecode: Option<bool>,
2251 no_sources: Option<bool>,
2252 no_sources_package: Option<Vec<PackageName>>,
2253 no_build: Option<bool>,
2254 no_build_package: Option<Vec<PackageName>>,
2255 no_binary: Option<bool>,
2256 no_binary_package: Option<Vec<PackageName>>,
2257 torch_backend: Option<TorchMode>,
2258}
2259
2260#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2262#[serde(deny_unknown_fields, rename_all = "kebab-case")]
2263pub struct ToolOptionsWire {
2264 index: Option<Vec<Index>>,
2265 index_url: Option<PipIndex>,
2266 extra_index_url: Option<Vec<PipExtraIndex>>,
2267 no_index: Option<bool>,
2268 find_links: Option<Vec<PipFindLinks>>,
2269 index_strategy: Option<IndexStrategy>,
2270 keyring_provider: Option<KeyringProviderType>,
2271 resolution: Option<ResolutionMode>,
2272 prerelease: Option<PrereleaseMode>,
2273 fork_strategy: Option<ForkStrategy>,
2274 dependency_metadata: Option<Vec<StaticMetadata>>,
2275 config_settings: Option<ConfigSettings>,
2276 config_settings_package: Option<PackageConfigSettings>,
2277 build_isolation: Option<BuildIsolation>,
2278 extra_build_dependencies: Option<ExtraBuildDependencies>,
2279 extra_build_variables: Option<ExtraBuildVariables>,
2280 exclude_newer: Option<ExcludeNewerOverride>,
2281 exclude_newer_span: Option<ExcludeNewerSpan>,
2282 #[serde(serialize_with = "serialize_exclude_newer_package_with_spans")]
2283 exclude_newer_package: Option<ExcludeNewerPackage>,
2284 link_mode: Option<LinkMode>,
2285 compile_bytecode: Option<bool>,
2286 no_sources: Option<bool>,
2287 no_sources_package: Option<Vec<PackageName>>,
2288 no_build: Option<bool>,
2289 no_build_package: Option<Vec<PackageName>>,
2290 no_binary: Option<bool>,
2291 no_binary_package: Option<Vec<PackageName>>,
2292 torch_backend: Option<TorchMode>,
2293}
2294
2295impl From<ResolverInstallerOptions> for ToolOptions {
2296 fn from(value: ResolverInstallerOptions) -> Self {
2297 Self {
2298 index: value.index.map(|indexes| {
2299 indexes
2300 .into_iter()
2301 .map(Index::with_promoted_auth_policy)
2302 .collect()
2303 }),
2304 index_url: value.index_url,
2305 extra_index_url: value.extra_index_url,
2306 no_index: value.no_index,
2307 find_links: value.find_links,
2308 index_strategy: value.index_strategy,
2309 keyring_provider: value.keyring_provider,
2310 resolution: value.resolution,
2311 prerelease: value.prerelease,
2312 fork_strategy: value.fork_strategy,
2313 dependency_metadata: value.dependency_metadata,
2314 config_settings: value.config_settings,
2315 config_settings_package: value.config_settings_package,
2316 build_isolation: value.build_isolation,
2317 extra_build_dependencies: value.extra_build_dependencies,
2318 extra_build_variables: value.extra_build_variables,
2319 exclude_newer: value.exclude_newer,
2320 exclude_newer_package: value.exclude_newer_package,
2321 link_mode: value.link_mode,
2322 compile_bytecode: value.compile_bytecode,
2323 no_sources: value.no_sources,
2324 no_sources_package: value.no_sources_package,
2325 no_build: value.no_build,
2326 no_build_package: value.no_build_package,
2327 no_binary: value.no_binary,
2328 no_binary_package: value.no_binary_package,
2329 torch_backend: value.torch_backend,
2330 }
2331 }
2332}
2333
2334impl From<ToolOptionsWire> for ToolOptions {
2335 fn from(value: ToolOptionsWire) -> Self {
2336 let exclude_newer = value
2337 .exclude_newer
2338 .map(|exclude_newer| match exclude_newer {
2339 ExcludeNewerOverride::Disabled => ExcludeNewerOverride::Disabled,
2340 ExcludeNewerOverride::Enabled(exclude_newer) => {
2341 let exclude_newer = *exclude_newer;
2342 if let Some(span) = value.exclude_newer_span
2343 && exclude_newer.span().is_none()
2344 {
2345 ExcludeNewerValue::relative(span).into()
2346 } else {
2347 exclude_newer.into()
2348 }
2349 }
2350 });
2351
2352 Self {
2353 index: value.index,
2354 index_url: value.index_url,
2355 extra_index_url: value.extra_index_url,
2356 no_index: value.no_index,
2357 find_links: value.find_links,
2358 index_strategy: value.index_strategy,
2359 keyring_provider: value.keyring_provider,
2360 resolution: value.resolution,
2361 prerelease: value.prerelease,
2362 fork_strategy: value.fork_strategy,
2363 dependency_metadata: value.dependency_metadata,
2364 config_settings: value.config_settings,
2365 config_settings_package: value.config_settings_package,
2366 build_isolation: value.build_isolation,
2367 extra_build_dependencies: value.extra_build_dependencies,
2368 extra_build_variables: value.extra_build_variables,
2369 exclude_newer,
2370 exclude_newer_package: value.exclude_newer_package,
2371 link_mode: value.link_mode,
2372 compile_bytecode: value.compile_bytecode,
2373 no_sources: value.no_sources,
2374 no_sources_package: value.no_sources_package,
2375 no_build: value.no_build,
2376 no_build_package: value.no_build_package,
2377 no_binary: value.no_binary,
2378 no_binary_package: value.no_binary_package,
2379 torch_backend: value.torch_backend,
2380 }
2381 }
2382}
2383
2384impl From<ToolOptions> for ToolOptionsWire {
2385 fn from(value: ToolOptions) -> Self {
2386 let (exclude_newer, exclude_newer_span) = match &value.exclude_newer {
2387 Some(ExcludeNewerOverride::Disabled) => (Some(ExcludeNewerOverride::Disabled), None),
2388 Some(ExcludeNewerOverride::Enabled(value)) => match value.as_ref() {
2389 ExcludeNewerValue::Absolute(_) => {
2390 (Some(ExcludeNewerOverride::Enabled(value.clone())), None)
2391 }
2392 ExcludeNewerValue::Relative(span) => (
2393 Some(ExcludeNewerValue::absolute(value.timestamp()).into()),
2394 Some(*span),
2395 ),
2396 },
2397 None => (None, None),
2398 };
2399
2400 Self {
2401 index: value.index,
2402 index_url: value.index_url,
2403 extra_index_url: value.extra_index_url,
2404 no_index: value.no_index,
2405 find_links: value.find_links,
2406 index_strategy: value.index_strategy,
2407 keyring_provider: value.keyring_provider,
2408 resolution: value.resolution,
2409 prerelease: value.prerelease,
2410 fork_strategy: value.fork_strategy,
2411 dependency_metadata: value.dependency_metadata,
2412 config_settings: value.config_settings,
2413 config_settings_package: value.config_settings_package,
2414 build_isolation: value.build_isolation,
2415 extra_build_dependencies: value.extra_build_dependencies,
2416 extra_build_variables: value.extra_build_variables,
2417 exclude_newer,
2418 exclude_newer_span,
2419 exclude_newer_package: value.exclude_newer_package,
2420 link_mode: value.link_mode,
2421 compile_bytecode: value.compile_bytecode,
2422 no_sources: value.no_sources,
2423 no_sources_package: value.no_sources_package,
2424 no_build: value.no_build,
2425 no_build_package: value.no_build_package,
2426 no_binary: value.no_binary,
2427 no_binary_package: value.no_binary_package,
2428 torch_backend: value.torch_backend,
2429 }
2430 }
2431}
2432
2433impl From<ToolOptions> for ResolverInstallerOptions {
2434 fn from(value: ToolOptions) -> Self {
2435 Self {
2436 index: value.index,
2437 index_url: value.index_url,
2438 extra_index_url: value.extra_index_url,
2439 no_index: value.no_index,
2440 find_links: value.find_links,
2441 index_strategy: value.index_strategy,
2442 keyring_provider: value.keyring_provider,
2443 resolution: value.resolution,
2444 prerelease: value.prerelease,
2445 fork_strategy: value.fork_strategy,
2446 dependency_metadata: value.dependency_metadata,
2447 config_settings: value.config_settings,
2448 config_settings_package: value.config_settings_package,
2449 build_isolation: value.build_isolation,
2450 extra_build_dependencies: value.extra_build_dependencies,
2451 extra_build_variables: value.extra_build_variables,
2452 exclude_newer: value.exclude_newer,
2453 exclude_newer_package: value.exclude_newer_package,
2454 link_mode: value.link_mode,
2455 compile_bytecode: value.compile_bytecode,
2456 no_sources: value.no_sources,
2457 no_sources_package: value.no_sources_package,
2458 upgrade: None,
2459 reinstall: None,
2460 no_build: value.no_build,
2461 no_build_package: value.no_build_package,
2462 no_binary: value.no_binary,
2463 no_binary_package: value.no_binary_package,
2464 torch_backend: value.torch_backend,
2465 }
2466 }
2467}
2468
2469#[derive(Debug, Clone, Default, Deserialize)]
2472#[serde(rename_all = "kebab-case", deny_unknown_fields)]
2473struct OptionsWire {
2474 required_version: Option<RequiredVersion>,
2477 system_certs: Option<bool>,
2478 native_tls: Option<bool>,
2479 offline: Option<bool>,
2480 no_cache: Option<bool>,
2481 cache_dir: Option<PathBuf>,
2482 preview: Option<bool>,
2483 preview_features: Option<PreviewFeaturesOption>,
2484 python_preference: Option<PythonPreference>,
2485 python_downloads: Option<PythonDownloads>,
2486 concurrent_downloads: Option<NonZeroUsize>,
2487 concurrent_builds: Option<NonZeroUsize>,
2488 concurrent_installs: Option<NonZeroUsize>,
2489
2490 index: Option<Vec<Index>>,
2493 index_url: Option<PipIndex>,
2494 extra_index_url: Option<Vec<PipExtraIndex>>,
2495 no_index: Option<bool>,
2496 find_links: Option<Vec<PipFindLinks>>,
2497 index_strategy: Option<IndexStrategy>,
2498 keyring_provider: Option<KeyringProviderType>,
2499 http_proxy: Option<ProxyUrl>,
2500 https_proxy: Option<ProxyUrl>,
2501 no_proxy: Option<Vec<String>>,
2502 allow_insecure_host: Option<Vec<TrustedHost>>,
2503 resolution: Option<ResolutionMode>,
2504 prerelease: Option<PrereleaseMode>,
2505 fork_strategy: Option<ForkStrategy>,
2506 dependency_metadata: Option<Vec<StaticMetadata>>,
2507 config_settings: Option<ConfigSettings>,
2508 config_settings_package: Option<PackageConfigSettings>,
2509 no_build_isolation: Option<bool>,
2510 no_build_isolation_package: Option<Vec<PackageName>>,
2511 extra_build_dependencies: Option<ExtraBuildDependencies>,
2512 extra_build_variables: Option<ExtraBuildVariables>,
2513 exclude_newer: Option<ExcludeNewerOverride>,
2514 exclude_newer_package: Option<ExcludeNewerPackage>,
2515 link_mode: Option<LinkMode>,
2516 compile_bytecode: Option<bool>,
2517 no_sources: Option<bool>,
2518 no_sources_package: Option<Vec<PackageName>>,
2519 upgrade: Option<bool>,
2520 upgrade_package: Option<Vec<Requirement<VerbatimParsedUrl>>>,
2521 reinstall: Option<bool>,
2522 reinstall_package: Option<Vec<PackageName>>,
2523 no_build: Option<bool>,
2524 no_build_package: Option<Vec<PackageName>>,
2525 no_binary: Option<bool>,
2526 no_binary_package: Option<Vec<PackageName>>,
2527 torch_backend: Option<TorchMode>,
2528
2529 python_install_mirror: Option<String>,
2532 pypy_install_mirror: Option<String>,
2533 python_downloads_json_url: Option<String>,
2534
2535 publish_url: Option<DisplaySafeUrl>,
2538 trusted_publishing: Option<TrustedPublishing>,
2539 check_url: Option<IndexUrl>,
2540
2541 add_bounds: Option<AddBoundsKind>,
2544
2545 audit: Option<AuditOptions>,
2546 pip: Option<PipOptions>,
2547 cache_keys: Option<Vec<CacheKey>>,
2548
2549 override_dependencies: Option<Vec<OverrideDependency>>,
2553 exclude_dependencies: Option<Vec<ExcludeDependency>>,
2554 constraint_dependencies: Option<Vec<Requirement<VerbatimParsedUrl>>>,
2555 build_constraint_dependencies: Option<Vec<Requirement<VerbatimParsedUrl>>>,
2556 environments: Option<SupportedEnvironments>,
2557 required_environments: Option<SupportedEnvironments>,
2558
2559 conflicts: Option<serde::de::IgnoredAny>,
2563 workspace: Option<serde::de::IgnoredAny>,
2564 sources: Option<serde::de::IgnoredAny>,
2565 managed: Option<serde::de::IgnoredAny>,
2566 r#package: Option<serde::de::IgnoredAny>,
2567 default_groups: Option<serde::de::IgnoredAny>,
2568 dependency_groups: Option<serde::de::IgnoredAny>,
2569 dev_dependencies: Option<serde::de::IgnoredAny>,
2570
2571 build_backend: Option<serde::de::IgnoredAny>,
2573}
2574
2575impl TryFrom<OptionsWire> for Options {
2576 type Error = &'static str;
2577
2578 #[allow(deprecated)]
2579 fn try_from(value: OptionsWire) -> Result<Self, Self::Error> {
2580 let OptionsWire {
2581 required_version,
2582 system_certs,
2583 native_tls,
2584 offline,
2585 no_cache,
2586 cache_dir,
2587 preview,
2588 preview_features,
2589 python_preference,
2590 python_downloads,
2591 python_install_mirror,
2592 pypy_install_mirror,
2593 python_downloads_json_url,
2594 concurrent_downloads,
2595 concurrent_builds,
2596 concurrent_installs,
2597 index,
2598 index_url,
2599 extra_index_url,
2600 no_index,
2601 find_links,
2602 index_strategy,
2603 keyring_provider,
2604 http_proxy,
2605 https_proxy,
2606 no_proxy,
2607 allow_insecure_host,
2608 resolution,
2609 prerelease,
2610 fork_strategy,
2611 dependency_metadata,
2612 config_settings,
2613 config_settings_package,
2614 no_build_isolation,
2615 no_build_isolation_package,
2616 exclude_newer,
2617 exclude_newer_package,
2618 link_mode,
2619 compile_bytecode,
2620 no_sources,
2621 no_sources_package,
2622 upgrade,
2623 upgrade_package,
2624 reinstall,
2625 reinstall_package,
2626 no_build,
2627 no_build_package,
2628 no_binary,
2629 no_binary_package,
2630 torch_backend,
2631 audit,
2632 pip,
2633 cache_keys,
2634 override_dependencies,
2635 exclude_dependencies,
2636 constraint_dependencies,
2637 build_constraint_dependencies,
2638 environments,
2639 required_environments,
2640 conflicts,
2641 publish_url,
2642 trusted_publishing,
2643 check_url,
2644 workspace,
2645 sources,
2646 default_groups,
2647 dependency_groups,
2648 extra_build_dependencies,
2649 extra_build_variables,
2650 dev_dependencies,
2651 managed,
2652 package,
2653 add_bounds: bounds,
2654 build_backend,
2656 } = value;
2657
2658 Ok(Self {
2659 globals: GlobalOptions {
2660 required_version,
2661 system_certs,
2662 native_tls,
2663 offline,
2664 no_cache,
2665 cache_dir,
2666 preview: PreviewOption::try_from(preview, preview_features)?,
2667 python_preference,
2668 python_downloads,
2669 concurrent_downloads,
2670 concurrent_builds,
2671 concurrent_installs,
2672 http_proxy,
2673 https_proxy,
2674 no_proxy,
2675 allow_insecure_host: allow_insecure_host.clone(),
2677 },
2678 top_level: ResolverInstallerSchema {
2679 index,
2680 index_url,
2681 extra_index_url,
2682 no_index,
2683 find_links,
2684 index_strategy,
2685 keyring_provider,
2686 resolution,
2687 prerelease,
2688 fork_strategy,
2689 dependency_metadata,
2690 config_settings,
2691 config_settings_package,
2692 no_build_isolation,
2693 no_build_isolation_package,
2694 extra_build_dependencies,
2695 extra_build_variables,
2696 exclude_newer,
2697 exclude_newer_package,
2698 link_mode,
2699 compile_bytecode,
2700 no_sources,
2701 no_sources_package,
2702 upgrade,
2703 upgrade_package,
2704 reinstall,
2705 reinstall_package,
2706 no_build,
2707 no_build_package,
2708 no_binary,
2709 no_binary_package,
2710 torch_backend,
2711 },
2712 pip,
2713 cache_keys,
2714 build_backend,
2715 override_dependencies,
2716 exclude_dependencies,
2717 constraint_dependencies,
2718 build_constraint_dependencies,
2719 environments,
2720 required_environments,
2721 install_mirrors: PythonInstallMirrors {
2722 python_install_mirror,
2723 pypy_install_mirror,
2724 python_downloads_json_url,
2725 },
2726 conflicts,
2727 publish: PublishOptions {
2728 publish_url,
2729 trusted_publishing,
2730 check_url,
2731 },
2732 add: AddOptions { add_bounds: bounds },
2733 audit,
2734 workspace,
2735 sources,
2736 dev_dependencies,
2737 default_groups,
2738 dependency_groups,
2739 managed,
2740 package,
2741 })
2742 }
2743}
2744
2745#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, CombineOptions, OptionsMetadata)]
2746#[serde(rename_all = "kebab-case")]
2747#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2748pub struct PublishOptions {
2749 #[option(
2752 default = "\"https://upload.pypi.org/legacy/\"",
2753 value_type = "str",
2754 example = r#"
2755 publish-url = "https://test.pypi.org/legacy/"
2756 "#
2757 )]
2758 pub publish_url: Option<DisplaySafeUrl>,
2759
2760 #[option(
2767 default = "automatic",
2768 value_type = "str",
2769 example = r#"
2770 trusted-publishing = "always"
2771 "#
2772 )]
2773 pub trusted_publishing: Option<TrustedPublishing>,
2774
2775 #[option(
2789 default = "None",
2790 value_type = "str",
2791 example = r#"
2792 check-url = "https://test.pypi.org/simple"
2793 "#
2794 )]
2795 pub check_url: Option<IndexUrl>,
2796}
2797
2798#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, CombineOptions, OptionsMetadata)]
2799#[serde(rename_all = "kebab-case")]
2800#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2801pub struct AddOptions {
2802 #[option(
2813 default = "\"lower\"",
2814 value_type = "str",
2815 example = r#"
2816 add-bounds = "major"
2817 "#,
2818 possible_values = true
2819 )]
2820 pub add_bounds: Option<AddBoundsKind>,
2821}
2822
2823#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, CombineOptions, OptionsMetadata)]
2824#[serde(rename_all = "kebab-case")]
2825#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2826pub struct AuditOptions {
2827 #[option(
2829 default = "false",
2830 value_type = "bool",
2831 example = r#"
2832 malware-check = true
2833 "#
2834 )]
2835 pub malware_check: Option<bool>,
2836
2837 #[option(
2839 default = "\"https://api.osv.dev/\"",
2840 value_type = "str",
2841 example = r#"
2842 malware-check-url = "https://example.com"
2843 "#
2844 )]
2845 pub malware_check_url: Option<DisplaySafeUrl>,
2846
2847 #[option(
2852 default = "[]",
2853 value_type = "list[str]",
2854 example = r#"
2855 ignore = ["PYSEC-2022-43017", "GHSA-5239-wwwm-4pmq"]
2856 "#
2857 )]
2858 pub ignore: Option<Vec<String>>,
2859
2860 #[option(
2866 default = "[]",
2867 value_type = "list[str]",
2868 example = r#"
2869 ignore-until-fixed = ["PYSEC-2022-43017"]
2870 "#
2871 )]
2872 pub ignore_until_fixed: Option<Vec<String>>,
2873}
2874
2875#[derive(Debug, Clone)]
2876pub struct MalwareCheckSettings {
2877 pub enabled: bool,
2879 pub malware_check_url: Option<DisplaySafeUrl>,
2881}
2882
2883impl MalwareCheckSettings {
2884 pub fn resolve(
2885 filesystem: Option<&FilesystemOptions>,
2886 environment: &EnvironmentOptions,
2887 ) -> Self {
2888 let audit = filesystem.and_then(|options| options.audit.as_ref());
2889
2890 Self {
2891 enabled: environment
2892 .malware_check
2893 .value
2894 .or(audit.and_then(|audit| audit.malware_check))
2895 .unwrap_or_default(),
2896 malware_check_url: environment
2897 .malware_check_url
2898 .clone()
2899 .or_else(|| audit.and_then(|audit| audit.malware_check_url.clone())),
2900 }
2901 }
2902}
2903
2904#[derive(Debug, Clone)]
2906#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2907#[cfg_attr(feature = "schemars", schemars(untagged))]
2908pub enum PreviewFeaturesOption {
2909 Toggle(bool),
2910 Features(Vec<MaybePreviewFeature>),
2911}
2912
2913impl<'de> Deserialize<'de> for PreviewFeaturesOption {
2916 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2917 where
2918 D: serde::Deserializer<'de>,
2919 {
2920 serde_untagged::UntaggedEnumVisitor::new()
2921 .expecting("a boolean or a list of preview feature names")
2922 .bool(|value| Ok(Self::Toggle(value)))
2923 .seq(|sequence| sequence.deserialize().map(Self::Features))
2924 .deserialize(deserializer)
2925 }
2926}
2927
2928#[expect(
2929 dead_code,
2930 reason = "Fields are only used by the OptionsMetadata and JsonSchema derives"
2931)]
2932#[derive(OptionsMetadata)]
2933#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2934#[cfg_attr(feature = "schemars", schemars(rename_all = "kebab-case"))]
2935struct PreviewOptionsDefinition {
2936 #[deprecated(note = "use `preview-features` instead")]
2942 preview: Option<bool>,
2943 #[option(
2947 default = "false",
2948 value_type = "bool | list[str]",
2949 example = r#"
2950 preview-features = true
2951 # or
2952 preview-features = ["json-output"]
2953 "#
2954 )]
2955 preview_features: Option<PreviewFeaturesOption>,
2956}
2957
2958#[derive(Debug, Clone)]
2960pub enum PreviewOption {
2961 Preview(bool),
2963 PreviewFeatures(PreviewFeaturesOption),
2965}
2966
2967impl uv_options_metadata::OptionsMetadata for PreviewOption {
2968 fn record(visit: &mut dyn uv_options_metadata::Visit) {
2969 <PreviewOptionsDefinition as uv_options_metadata::OptionsMetadata>::record(visit);
2970 }
2971}
2972
2973#[cfg(feature = "schemars")]
2974struct ConflictingPreviewOptions;
2975
2976#[cfg(feature = "schemars")]
2977impl schemars::JsonSchema for ConflictingPreviewOptions {
2978 fn schema_name() -> Cow<'static, str> {
2979 Cow::Borrowed("ConflictingPreviewOptions")
2980 }
2981
2982 fn json_schema(_generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
2983 schemars::json_schema!({
2984 "type": "object",
2985 "properties": {
2986 "preview": {},
2987 "preview-features": {},
2988 },
2989 "required": ["preview", "preview-features"],
2990 })
2991 }
2992}
2993
2994#[cfg(feature = "schemars")]
2995impl schemars::JsonSchema for PreviewOption {
2996 fn schema_name() -> Cow<'static, str> {
2997 Cow::Borrowed("PreviewOption")
2998 }
2999
3000 fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
3001 let mut schema = <PreviewOptionsDefinition as schemars::JsonSchema>::json_schema(generator);
3002 schema.insert(
3005 "not".to_string(),
3006 generator
3007 .subschema_for::<ConflictingPreviewOptions>()
3008 .into(),
3009 );
3010 schema
3011 }
3012}
3013
3014impl PreviewOption {
3015 fn try_from(
3016 preview: Option<bool>,
3017 preview_features: Option<PreviewFeaturesOption>,
3018 ) -> Result<Option<Self>, &'static str> {
3019 match (preview, preview_features) {
3020 (Some(_), Some(_)) => Err("cannot specify both `preview` and `preview-features`"),
3021 (Some(b), None) => Ok(Some(Self::Preview(b))),
3022 (None, Some(features)) => Ok(Some(Self::PreviewFeatures(features))),
3023 (None, None) => Ok(None),
3024 }
3025 }
3026
3027 pub fn resolve(&self) -> Preview {
3029 use PreviewFeaturesOption::{Features, Toggle};
3030
3031 match self {
3032 Self::Preview(false) | Self::PreviewFeatures(Toggle(false)) => Preview::default(),
3033 Self::Preview(true) | Self::PreviewFeatures(Toggle(true)) => Preview::all(),
3034 Self::PreviewFeatures(Features(features)) => Preview::from_feature_names(features),
3035 }
3036 }
3037}