uv_settings/
settings.rs

1use std::{fmt::Debug, num::NonZeroUsize, path::Path, path::PathBuf};
2
3use serde::{Deserialize, Serialize};
4
5use uv_cache_info::CacheKey;
6use uv_configuration::{
7    BuildIsolation, IndexStrategy, KeyringProviderType, PackageNameSpecifier, Reinstall,
8    RequiredVersion, TargetTriple, TrustedHost, TrustedPublishing, Upgrade,
9};
10use uv_distribution_types::{
11    ConfigSettings, ExtraBuildVariables, Index, IndexUrl, IndexUrlError, PackageConfigSettings,
12    PipExtraIndex, PipFindLinks, PipIndex, StaticMetadata,
13};
14use uv_install_wheel::LinkMode;
15use uv_macros::{CombineOptions, OptionsMetadata};
16use uv_normalize::{ExtraName, PackageName, PipGroupName};
17use uv_pep508::Requirement;
18use uv_pypi_types::{SupportedEnvironments, VerbatimParsedUrl};
19use uv_python::{PythonDownloads, PythonPreference, PythonVersion};
20use uv_redacted::DisplaySafeUrl;
21use uv_resolver::{
22    AnnotationStyle, ExcludeNewer, ExcludeNewerPackage, ExcludeNewerValue, ForkStrategy,
23    PrereleaseMode, ResolutionMode,
24};
25use uv_torch::TorchMode;
26use uv_workspace::pyproject::ExtraBuildDependencies;
27use uv_workspace::pyproject_mut::AddBoundsKind;
28
29/// A `pyproject.toml` with an (optional) `[tool.uv]` section.
30#[allow(dead_code)]
31#[derive(Debug, Clone, Default, Deserialize)]
32pub(crate) struct PyProjectToml {
33    pub(crate) tool: Option<Tools>,
34}
35
36/// A `[tool]` section.
37#[allow(dead_code)]
38#[derive(Debug, Clone, Default, Deserialize)]
39pub(crate) struct Tools {
40    pub(crate) uv: Option<Options>,
41}
42
43/// A `[tool.uv]` section.
44#[allow(dead_code)]
45#[derive(Debug, Clone, Default, Deserialize, CombineOptions, OptionsMetadata)]
46#[serde(from = "OptionsWire", rename_all = "kebab-case")]
47#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
48#[cfg_attr(feature = "schemars", schemars(!from))]
49pub struct Options {
50    #[serde(flatten)]
51    pub globals: GlobalOptions,
52
53    #[serde(flatten)]
54    pub top_level: ResolverInstallerSchema,
55
56    #[serde(flatten)]
57    pub install_mirrors: PythonInstallMirrors,
58
59    #[serde(flatten)]
60    pub publish: PublishOptions,
61
62    #[serde(flatten)]
63    pub add: AddOptions,
64
65    #[option_group]
66    pub pip: Option<PipOptions>,
67
68    /// The keys to consider when caching builds for the project.
69    ///
70    /// Cache keys enable you to specify the files or directories that should trigger a rebuild when
71    /// modified. By default, uv will rebuild a project whenever the `pyproject.toml`, `setup.py`,
72    /// or `setup.cfg` files in the project directory are modified, or if a `src` directory is
73    /// added or removed, i.e.:
74    ///
75    /// ```toml
76    /// cache-keys = [{ file = "pyproject.toml" }, { file = "setup.py" }, { file = "setup.cfg" }, { dir = "src" }]
77    /// ```
78    ///
79    /// As an example: if a project uses dynamic metadata to read its dependencies from a
80    /// `requirements.txt` file, you can specify `cache-keys = [{ file = "requirements.txt" }, { file = "pyproject.toml" }]`
81    /// to ensure that the project is rebuilt whenever the `requirements.txt` file is modified (in
82    /// addition to watching the `pyproject.toml`).
83    ///
84    /// Globs are supported, following the syntax of the [`glob`](https://docs.rs/glob/0.3.1/glob/struct.Pattern.html)
85    /// crate. For example, to invalidate the cache whenever a `.toml` file in the project directory
86    /// or any of its subdirectories is modified, you can specify `cache-keys = [{ file = "**/*.toml" }]`.
87    /// Note that the use of globs can be expensive, as uv may need to walk the filesystem to
88    /// determine whether any files have changed.
89    ///
90    /// Cache keys can also include version control information. For example, if a project uses
91    /// `setuptools_scm` to read its version from a Git commit, you can specify `cache-keys = [{ git = { commit = true }, { file = "pyproject.toml" }]`
92    /// to include the current Git commit hash in the cache key (in addition to the
93    /// `pyproject.toml`). Git tags are also supported via `cache-keys = [{ git = { commit = true, tags = true } }]`.
94    ///
95    /// Cache keys can also include environment variables. For example, if a project relies on
96    /// `MACOSX_DEPLOYMENT_TARGET` or other environment variables to determine its behavior, you can
97    /// specify `cache-keys = [{ env = "MACOSX_DEPLOYMENT_TARGET" }]` to invalidate the cache
98    /// whenever the environment variable changes.
99    ///
100    /// Cache keys only affect the project defined by the `pyproject.toml` in which they're
101    /// specified (as opposed to, e.g., affecting all members in a workspace), and all paths and
102    /// globs are interpreted as relative to the project directory.
103    #[option(
104        default = r#"[{ file = "pyproject.toml" }, { file = "setup.py" }, { file = "setup.cfg" }]"#,
105        value_type = "list[dict]",
106        example = r#"
107            cache-keys = [{ file = "pyproject.toml" }, { file = "requirements.txt" }, { git = { commit = true } }]
108        "#
109    )]
110    pub cache_keys: Option<Vec<CacheKey>>,
111
112    // NOTE(charlie): These fields are shared with `ToolUv` in
113    // `crates/uv-workspace/src/pyproject.rs`. The documentation lives on that struct.
114    // They're respected in both `pyproject.toml` and `uv.toml` files.
115    #[cfg_attr(feature = "schemars", schemars(skip))]
116    pub override_dependencies: Option<Vec<Requirement<VerbatimParsedUrl>>>,
117
118    #[cfg_attr(feature = "schemars", schemars(skip))]
119    pub exclude_dependencies: Option<Vec<uv_normalize::PackageName>>,
120
121    #[cfg_attr(feature = "schemars", schemars(skip))]
122    pub constraint_dependencies: Option<Vec<Requirement<VerbatimParsedUrl>>>,
123
124    #[cfg_attr(feature = "schemars", schemars(skip))]
125    pub build_constraint_dependencies: Option<Vec<Requirement<VerbatimParsedUrl>>>,
126
127    #[cfg_attr(feature = "schemars", schemars(skip))]
128    pub environments: Option<SupportedEnvironments>,
129
130    #[cfg_attr(feature = "schemars", schemars(skip))]
131    pub required_environments: Option<SupportedEnvironments>,
132
133    // NOTE(charlie): These fields should be kept in-sync with `ToolUv` in
134    // `crates/uv-workspace/src/pyproject.rs`. The documentation lives on that struct.
135    // They're only respected in `pyproject.toml` files, and should be rejected in `uv.toml` files.
136    #[cfg_attr(feature = "schemars", schemars(skip))]
137    pub conflicts: Option<serde::de::IgnoredAny>,
138
139    #[cfg_attr(feature = "schemars", schemars(skip))]
140    pub workspace: Option<serde::de::IgnoredAny>,
141
142    #[cfg_attr(feature = "schemars", schemars(skip))]
143    pub sources: Option<serde::de::IgnoredAny>,
144
145    #[cfg_attr(feature = "schemars", schemars(skip))]
146    pub dev_dependencies: Option<serde::de::IgnoredAny>,
147
148    #[cfg_attr(feature = "schemars", schemars(skip))]
149    pub default_groups: Option<serde::de::IgnoredAny>,
150
151    #[cfg_attr(feature = "schemars", schemars(skip))]
152    pub dependency_groups: Option<serde::de::IgnoredAny>,
153
154    #[cfg_attr(feature = "schemars", schemars(skip))]
155    pub managed: Option<serde::de::IgnoredAny>,
156
157    #[cfg_attr(feature = "schemars", schemars(skip))]
158    pub r#package: Option<serde::de::IgnoredAny>,
159
160    #[cfg_attr(feature = "schemars", schemars(skip))]
161    pub build_backend: Option<serde::de::IgnoredAny>,
162}
163
164impl Options {
165    /// Construct an [`Options`] with the given global and top-level settings.
166    pub fn simple(globals: GlobalOptions, top_level: ResolverInstallerSchema) -> Self {
167        Self {
168            globals,
169            top_level,
170            ..Default::default()
171        }
172    }
173
174    /// Resolve the [`Options`] relative to the given root directory.
175    pub fn relative_to(self, root_dir: &Path) -> Result<Self, IndexUrlError> {
176        Ok(Self {
177            top_level: self.top_level.relative_to(root_dir)?,
178            pip: self.pip.map(|pip| pip.relative_to(root_dir)).transpose()?,
179            ..self
180        })
181    }
182}
183
184/// Global settings, relevant to all invocations.
185#[derive(Debug, Clone, Default, Deserialize, CombineOptions, OptionsMetadata)]
186#[serde(rename_all = "kebab-case")]
187#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
188pub struct GlobalOptions {
189    /// Enforce a requirement on the version of uv.
190    ///
191    /// If the version of uv does not meet the requirement at runtime, uv will exit
192    /// with an error.
193    ///
194    /// Accepts a [PEP 440](https://peps.python.org/pep-0440/) specifier, like `==0.5.0` or `>=0.5.0`.
195    #[option(
196        default = "null",
197        value_type = "str",
198        example = r#"
199            required-version = ">=0.5.0"
200        "#
201    )]
202    pub required_version: Option<RequiredVersion>,
203    /// Whether to load TLS certificates from the platform's native certificate store.
204    ///
205    /// By default, uv loads certificates from the bundled `webpki-roots` crate. The
206    /// `webpki-roots` are a reliable set of trust roots from Mozilla, and including them in uv
207    /// improves portability and performance (especially on macOS).
208    ///
209    /// However, in some cases, you may want to use the platform's native certificate store,
210    /// especially if you're relying on a corporate trust root (e.g., for a mandatory proxy) that's
211    /// included in your system's certificate store.
212    #[option(
213        default = "false",
214        value_type = "bool",
215        example = r#"
216            native-tls = true
217        "#
218    )]
219    pub native_tls: Option<bool>,
220    /// Disable network access, relying only on locally cached data and locally available files.
221    #[option(
222        default = "false",
223        value_type = "bool",
224        example = r#"
225            offline = true
226        "#
227    )]
228    pub offline: Option<bool>,
229    /// Avoid reading from or writing to the cache, instead using a temporary directory for the
230    /// duration of the operation.
231    #[option(
232        default = "false",
233        value_type = "bool",
234        example = r#"
235            no-cache = true
236        "#
237    )]
238    pub no_cache: Option<bool>,
239    /// Path to the cache directory.
240    ///
241    /// Defaults to `$XDG_CACHE_HOME/uv` or `$HOME/.cache/uv` on Linux and macOS, and
242    /// `%LOCALAPPDATA%\uv\cache` on Windows.
243    #[option(
244        default = "None",
245        value_type = "str",
246        example = r#"
247            cache-dir = "./.uv_cache"
248        "#
249    )]
250    pub cache_dir: Option<PathBuf>,
251    /// Whether to enable experimental, preview features.
252    #[option(
253        default = "false",
254        value_type = "bool",
255        example = r#"
256            preview = true
257        "#
258    )]
259    pub preview: Option<bool>,
260    /// Whether to prefer using Python installations that are already present on the system, or
261    /// those that are downloaded and installed by uv.
262    #[option(
263        default = "\"managed\"",
264        value_type = "str",
265        example = r#"
266            python-preference = "managed"
267        "#,
268        possible_values = true
269    )]
270    pub python_preference: Option<PythonPreference>,
271    /// Whether to allow Python downloads.
272    #[option(
273        default = "\"automatic\"",
274        value_type = "str",
275        example = r#"
276            python-downloads = "manual"
277        "#,
278        possible_values = true
279    )]
280    pub python_downloads: Option<PythonDownloads>,
281    /// The maximum number of in-flight concurrent downloads that uv will perform at any given
282    /// time.
283    #[option(
284        default = "50",
285        value_type = "int",
286        example = r#"
287            concurrent-downloads = 4
288        "#
289    )]
290    pub concurrent_downloads: Option<NonZeroUsize>,
291    /// The maximum number of source distributions that uv will build concurrently at any given
292    /// time.
293    ///
294    /// Defaults to the number of available CPU cores.
295    #[option(
296        default = "None",
297        value_type = "int",
298        example = r#"
299            concurrent-builds = 4
300        "#
301    )]
302    pub concurrent_builds: Option<NonZeroUsize>,
303    /// The number of threads used when installing and unzipping packages.
304    ///
305    /// Defaults to the number of available CPU cores.
306    #[option(
307        default = "None",
308        value_type = "int",
309        example = r#"
310            concurrent-installs = 4
311        "#
312    )]
313    pub concurrent_installs: Option<NonZeroUsize>,
314    /// Allow insecure connections to host.
315    ///
316    /// Expects to receive either a hostname (e.g., `localhost`), a host-port pair (e.g.,
317    /// `localhost:8080`), or a URL (e.g., `https://localhost`).
318    ///
319    /// WARNING: Hosts included in this list will not be verified against the system's certificate
320    /// store. Only use `--allow-insecure-host` in a secure network with verified sources, as it
321    /// bypasses SSL verification and could expose you to MITM attacks.
322    #[option(
323        default = "[]",
324        value_type = "list[str]",
325        example = r#"
326            allow-insecure-host = ["localhost:8080"]
327        "#
328    )]
329    pub allow_insecure_host: Option<Vec<TrustedHost>>,
330}
331
332/// Settings relevant to all installer operations.
333#[derive(Debug, Clone, Default, CombineOptions)]
334pub struct InstallerOptions {
335    pub index: Option<Vec<Index>>,
336    pub index_url: Option<PipIndex>,
337    pub extra_index_url: Option<Vec<PipExtraIndex>>,
338    pub no_index: Option<bool>,
339    pub find_links: Option<Vec<PipFindLinks>>,
340    pub index_strategy: Option<IndexStrategy>,
341    pub keyring_provider: Option<KeyringProviderType>,
342    pub config_settings: Option<ConfigSettings>,
343    pub exclude_newer: Option<ExcludeNewerValue>,
344    pub link_mode: Option<LinkMode>,
345    pub compile_bytecode: Option<bool>,
346    pub reinstall: Option<Reinstall>,
347    pub build_isolation: Option<BuildIsolation>,
348    pub no_build: Option<bool>,
349    pub no_build_package: Option<Vec<PackageName>>,
350    pub no_binary: Option<bool>,
351    pub no_binary_package: Option<Vec<PackageName>>,
352    pub no_sources: Option<bool>,
353}
354
355/// Settings relevant to all resolver operations.
356#[derive(Debug, Clone, Default, CombineOptions)]
357pub struct ResolverOptions {
358    pub index: Option<Vec<Index>>,
359    pub index_url: Option<PipIndex>,
360    pub extra_index_url: Option<Vec<PipExtraIndex>>,
361    pub no_index: Option<bool>,
362    pub find_links: Option<Vec<PipFindLinks>>,
363    pub index_strategy: Option<IndexStrategy>,
364    pub keyring_provider: Option<KeyringProviderType>,
365    pub resolution: Option<ResolutionMode>,
366    pub prerelease: Option<PrereleaseMode>,
367    pub fork_strategy: Option<ForkStrategy>,
368    pub dependency_metadata: Option<Vec<StaticMetadata>>,
369    pub config_settings: Option<ConfigSettings>,
370    pub config_settings_package: Option<PackageConfigSettings>,
371    pub exclude_newer: ExcludeNewer,
372    pub link_mode: Option<LinkMode>,
373    pub torch_backend: Option<TorchMode>,
374    pub upgrade: Option<Upgrade>,
375    pub build_isolation: Option<BuildIsolation>,
376    pub no_build: Option<bool>,
377    pub no_build_package: Option<Vec<PackageName>>,
378    pub no_binary: Option<bool>,
379    pub no_binary_package: Option<Vec<PackageName>>,
380    pub extra_build_dependencies: Option<ExtraBuildDependencies>,
381    pub extra_build_variables: Option<ExtraBuildVariables>,
382    pub no_sources: Option<bool>,
383}
384
385/// Shared settings, relevant to all operations that must resolve and install dependencies. The
386/// union of [`InstallerOptions`] and [`ResolverOptions`].
387#[derive(Debug, Clone, Default, CombineOptions)]
388pub struct ResolverInstallerOptions {
389    pub index: Option<Vec<Index>>,
390    pub index_url: Option<PipIndex>,
391    pub extra_index_url: Option<Vec<PipExtraIndex>>,
392    pub no_index: Option<bool>,
393    pub find_links: Option<Vec<PipFindLinks>>,
394    pub index_strategy: Option<IndexStrategy>,
395    pub keyring_provider: Option<KeyringProviderType>,
396    pub resolution: Option<ResolutionMode>,
397    pub prerelease: Option<PrereleaseMode>,
398    pub fork_strategy: Option<ForkStrategy>,
399    pub dependency_metadata: Option<Vec<StaticMetadata>>,
400    pub config_settings: Option<ConfigSettings>,
401    pub config_settings_package: Option<PackageConfigSettings>,
402    pub build_isolation: Option<BuildIsolation>,
403    pub extra_build_dependencies: Option<ExtraBuildDependencies>,
404    pub extra_build_variables: Option<ExtraBuildVariables>,
405    pub exclude_newer: Option<ExcludeNewerValue>,
406    pub exclude_newer_package: Option<ExcludeNewerPackage>,
407    pub link_mode: Option<LinkMode>,
408    pub torch_backend: Option<TorchMode>,
409    pub compile_bytecode: Option<bool>,
410    pub no_sources: Option<bool>,
411    pub upgrade: Option<Upgrade>,
412    pub reinstall: Option<Reinstall>,
413    pub no_build: Option<bool>,
414    pub no_build_package: Option<Vec<PackageName>>,
415    pub no_binary: Option<bool>,
416    pub no_binary_package: Option<Vec<PackageName>>,
417}
418
419impl From<ResolverInstallerSchema> for ResolverInstallerOptions {
420    fn from(value: ResolverInstallerSchema) -> Self {
421        let ResolverInstallerSchema {
422            index,
423            index_url,
424            extra_index_url,
425            no_index,
426            find_links,
427            index_strategy,
428            keyring_provider,
429            resolution,
430            prerelease,
431            fork_strategy,
432            dependency_metadata,
433            config_settings,
434            config_settings_package,
435            no_build_isolation,
436            no_build_isolation_package,
437            extra_build_dependencies,
438            extra_build_variables,
439            exclude_newer,
440            exclude_newer_package,
441            link_mode,
442            torch_backend,
443            compile_bytecode,
444            no_sources,
445            upgrade,
446            upgrade_package,
447            reinstall,
448            reinstall_package,
449            no_build,
450            no_build_package,
451            no_binary,
452            no_binary_package,
453        } = value;
454        Self {
455            index,
456            index_url,
457            extra_index_url,
458            no_index,
459            find_links,
460            index_strategy,
461            keyring_provider,
462            resolution,
463            prerelease,
464            fork_strategy,
465            dependency_metadata,
466            config_settings,
467            config_settings_package,
468            build_isolation: BuildIsolation::from_args(
469                no_build_isolation,
470                no_build_isolation_package.into_iter().flatten().collect(),
471            ),
472            extra_build_dependencies,
473            extra_build_variables,
474            exclude_newer,
475            exclude_newer_package,
476            link_mode,
477            torch_backend,
478            compile_bytecode,
479            no_sources,
480            upgrade: Upgrade::from_args(
481                upgrade,
482                upgrade_package
483                    .into_iter()
484                    .flatten()
485                    .map(Into::into)
486                    .collect(),
487            ),
488            reinstall: Reinstall::from_args(reinstall, reinstall_package.unwrap_or_default()),
489            no_build,
490            no_build_package,
491            no_binary,
492            no_binary_package,
493        }
494    }
495}
496
497impl ResolverInstallerSchema {
498    /// Resolve the [`ResolverInstallerSchema`] relative to the given root directory.
499    pub fn relative_to(self, root_dir: &Path) -> Result<Self, IndexUrlError> {
500        Ok(Self {
501            index: self
502                .index
503                .map(|index| {
504                    index
505                        .into_iter()
506                        .map(|index| index.relative_to(root_dir))
507                        .collect::<Result<Vec<_>, _>>()
508                })
509                .transpose()?,
510            index_url: self
511                .index_url
512                .map(|index_url| index_url.relative_to(root_dir))
513                .transpose()?,
514            extra_index_url: self
515                .extra_index_url
516                .map(|extra_index_url| {
517                    extra_index_url
518                        .into_iter()
519                        .map(|extra_index_url| extra_index_url.relative_to(root_dir))
520                        .collect::<Result<Vec<_>, _>>()
521                })
522                .transpose()?,
523            find_links: self
524                .find_links
525                .map(|find_links| {
526                    find_links
527                        .into_iter()
528                        .map(|find_link| find_link.relative_to(root_dir))
529                        .collect::<Result<Vec<_>, _>>()
530                })
531                .transpose()?,
532            ..self
533        })
534    }
535}
536
537/// The JSON schema for the `[tool.uv]` section of a `pyproject.toml` file.
538#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, CombineOptions, OptionsMetadata)]
539#[serde(rename_all = "kebab-case")]
540#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
541pub struct ResolverInstallerSchema {
542    /// The package indexes to use when resolving dependencies.
543    ///
544    /// Accepts either a repository compliant with [PEP 503](https://peps.python.org/pep-0503/)
545    /// (the simple repository API), or a local directory laid out in the same format.
546    ///
547    /// Indexes are considered in the order in which they're defined, such that the first-defined
548    /// index has the highest priority. Further, the indexes provided by this setting are given
549    /// higher priority than any indexes specified via [`index_url`](#index-url) or
550    /// [`extra_index_url`](#extra-index-url). uv will only consider the first index that contains
551    /// a given package, unless an alternative [index strategy](#index-strategy) is specified.
552    ///
553    /// If an index is marked as `explicit = true`, it will be used exclusively for those
554    /// dependencies that select it explicitly via `[tool.uv.sources]`, as in:
555    ///
556    /// ```toml
557    /// [[tool.uv.index]]
558    /// name = "pytorch"
559    /// url = "https://download.pytorch.org/whl/cu121"
560    /// explicit = true
561    ///
562    /// [tool.uv.sources]
563    /// torch = { index = "pytorch" }
564    /// ```
565    ///
566    /// If an index is marked as `default = true`, it will be moved to the end of the prioritized list, such that it is
567    /// given the lowest priority when resolving packages. Additionally, marking an index as default will disable the
568    /// PyPI default index.
569    #[option(
570        default = "\"[]\"",
571        value_type = "dict",
572        example = r#"
573            [[tool.uv.index]]
574            name = "pytorch"
575            url = "https://download.pytorch.org/whl/cu121"
576        "#
577    )]
578    pub index: Option<Vec<Index>>,
579    /// The URL of the Python package index (by default: <https://pypi.org/simple>).
580    ///
581    /// Accepts either a repository compliant with [PEP 503](https://peps.python.org/pep-0503/)
582    /// (the simple repository API), or a local directory laid out in the same format.
583    ///
584    /// The index provided by this setting is given lower priority than any indexes specified via
585    /// [`extra_index_url`](#extra-index-url) or [`index`](#index).
586    ///
587    /// (Deprecated: use `index` instead.)
588    #[option(
589        default = "\"https://pypi.org/simple\"",
590        value_type = "str",
591        example = r#"
592            index-url = "https://test.pypi.org/simple"
593        "#
594    )]
595    pub index_url: Option<PipIndex>,
596    /// Extra URLs of package indexes to use, in addition to `--index-url`.
597    ///
598    /// Accepts either a repository compliant with [PEP 503](https://peps.python.org/pep-0503/)
599    /// (the simple repository API), or a local directory laid out in the same format.
600    ///
601    /// All indexes provided via this flag take priority over the index specified by
602    /// [`index_url`](#index-url) or [`index`](#index) with `default = true`. When multiple indexes
603    /// are provided, earlier values take priority.
604    ///
605    /// To control uv's resolution strategy when multiple indexes are present, see
606    /// [`index_strategy`](#index-strategy).
607    ///
608    /// (Deprecated: use `index` instead.)
609    #[option(
610        default = "[]",
611        value_type = "list[str]",
612        example = r#"
613            extra-index-url = ["https://download.pytorch.org/whl/cpu"]
614        "#
615    )]
616    pub extra_index_url: Option<Vec<PipExtraIndex>>,
617    /// Ignore all registry indexes (e.g., PyPI), instead relying on direct URL dependencies and
618    /// those provided via `--find-links`.
619    #[option(
620        default = "false",
621        value_type = "bool",
622        example = r#"
623            no-index = true
624        "#
625    )]
626    pub no_index: Option<bool>,
627    /// Locations to search for candidate distributions, in addition to those found in the registry
628    /// indexes.
629    ///
630    /// If a path, the target must be a directory that contains packages as wheel files (`.whl`) or
631    /// source distributions (e.g., `.tar.gz` or `.zip`) at the top level.
632    ///
633    /// If a URL, the page must contain a flat list of links to package files adhering to the
634    /// formats described above.
635    #[option(
636        default = "[]",
637        value_type = "list[str]",
638        example = r#"
639            find-links = ["https://download.pytorch.org/whl/torch_stable.html"]
640        "#
641    )]
642    pub find_links: Option<Vec<PipFindLinks>>,
643    /// The strategy to use when resolving against multiple index URLs.
644    ///
645    /// By default, uv will stop at the first index on which a given package is available, and
646    /// limit resolutions to those present on that first index (`first-index`). This prevents
647    /// "dependency confusion" attacks, whereby an attacker can upload a malicious package under the
648    /// same name to an alternate index.
649    #[option(
650        default = "\"first-index\"",
651        value_type = "str",
652        example = r#"
653            index-strategy = "unsafe-best-match"
654        "#,
655        possible_values = true
656    )]
657    pub index_strategy: Option<IndexStrategy>,
658    /// Attempt to use `keyring` for authentication for index URLs.
659    ///
660    /// At present, only `--keyring-provider subprocess` is supported, which configures uv to
661    /// use the `keyring` CLI to handle authentication.
662    #[option(
663        default = "\"disabled\"",
664        value_type = "str",
665        example = r#"
666            keyring-provider = "subprocess"
667        "#
668    )]
669    pub keyring_provider: Option<KeyringProviderType>,
670    /// The strategy to use when selecting between the different compatible versions for a given
671    /// package requirement.
672    ///
673    /// By default, uv will use the latest compatible version of each package (`highest`).
674    #[option(
675        default = "\"highest\"",
676        value_type = "str",
677        example = r#"
678            resolution = "lowest-direct"
679        "#,
680        possible_values = true
681    )]
682    pub resolution: Option<ResolutionMode>,
683    /// The strategy to use when considering pre-release versions.
684    ///
685    /// By default, uv will accept pre-releases for packages that _only_ publish pre-releases,
686    /// along with first-party requirements that contain an explicit pre-release marker in the
687    /// declared specifiers (`if-necessary-or-explicit`).
688    #[option(
689        default = "\"if-necessary-or-explicit\"",
690        value_type = "str",
691        example = r#"
692            prerelease = "allow"
693        "#,
694        possible_values = true
695    )]
696    pub prerelease: Option<PrereleaseMode>,
697    /// The strategy to use when selecting multiple versions of a given package across Python
698    /// versions and platforms.
699    ///
700    /// By default, uv will optimize for selecting the latest version of each package for each
701    /// supported Python version (`requires-python`), while minimizing the number of selected
702    /// versions across platforms.
703    ///
704    /// Under `fewest`, uv will minimize the number of selected versions for each package,
705    /// preferring older versions that are compatible with a wider range of supported Python
706    /// versions or platforms.
707    #[option(
708        default = "\"requires-python\"",
709        value_type = "str",
710        example = r#"
711            fork-strategy = "fewest"
712        "#,
713        possible_values = true
714    )]
715    pub fork_strategy: Option<ForkStrategy>,
716    /// Pre-defined static metadata for dependencies of the project (direct or transitive). When
717    /// provided, enables the resolver to use the specified metadata instead of querying the
718    /// registry or building the relevant package from source.
719    ///
720    /// Metadata should be provided in adherence with the [Metadata 2.3](https://packaging.python.org/en/latest/specifications/core-metadata/)
721    /// standard, though only the following fields are respected:
722    ///
723    /// - `name`: The name of the package.
724    /// - (Optional) `version`: The version of the package. If omitted, the metadata will be applied
725    ///   to all versions of the package.
726    /// - (Optional) `requires-dist`: The dependencies of the package (e.g., `werkzeug>=0.14`).
727    /// - (Optional) `requires-python`: The Python version required by the package (e.g., `>=3.10`).
728    /// - (Optional) `provides-extra`: The extras provided by the package.
729    #[option(
730        default = r#"[]"#,
731        value_type = "list[dict]",
732        example = r#"
733            dependency-metadata = [
734                { name = "flask", version = "1.0.0", requires-dist = ["werkzeug"], requires-python = ">=3.6" },
735            ]
736        "#
737    )]
738    pub dependency_metadata: Option<Vec<StaticMetadata>>,
739    /// Settings to pass to the [PEP 517](https://peps.python.org/pep-0517/) build backend,
740    /// specified as `KEY=VALUE` pairs.
741    #[option(
742        default = "{}",
743        value_type = "dict",
744        example = r#"
745            config-settings = { editable_mode = "compat" }
746        "#
747    )]
748    pub config_settings: Option<ConfigSettings>,
749    /// Settings to pass to the [PEP 517](https://peps.python.org/pep-0517/) build backend for specific packages,
750    /// specified as `KEY=VALUE` pairs.
751    ///
752    /// Accepts a map from package names to string key-value pairs.
753    #[option(
754        default = "{}",
755        value_type = "dict",
756        example = r#"
757            config-settings-package = { numpy = { editable_mode = "compat" } }
758        "#
759    )]
760    pub config_settings_package: Option<PackageConfigSettings>,
761    /// Disable isolation when building source distributions.
762    ///
763    /// Assumes that build dependencies specified by [PEP 518](https://peps.python.org/pep-0518/)
764    /// are already installed.
765    #[option(
766        default = "false",
767        value_type = "bool",
768        example = r#"
769            no-build-isolation = true
770        "#
771    )]
772    pub no_build_isolation: Option<bool>,
773    /// Disable isolation when building source distributions for a specific package.
774    ///
775    /// Assumes that the packages' build dependencies specified by [PEP 518](https://peps.python.org/pep-0518/)
776    /// are already installed.
777    #[option(
778        default = "[]",
779        value_type = "list[str]",
780        example = r#"
781        no-build-isolation-package = ["package1", "package2"]
782    "#
783    )]
784    pub no_build_isolation_package: Option<Vec<PackageName>>,
785    /// Additional build dependencies for packages.
786    ///
787    /// This allows extending the PEP 517 build environment for the project's dependencies with
788    /// additional packages. This is useful for packages that assume the presence of packages like
789    /// `pip`, and do not declare them as build dependencies.
790    #[option(
791        default = "[]",
792        value_type = "dict",
793        example = r#"
794            extra-build-dependencies = { pytest = ["setuptools"] }
795        "#
796    )]
797    pub extra_build_dependencies: Option<ExtraBuildDependencies>,
798    /// Extra environment variables to set when building certain packages.
799    ///
800    /// Environment variables will be added to the environment when building the
801    /// specified packages.
802    #[option(
803        default = r#"{}"#,
804        value_type = r#"dict[str, dict[str, str]]"#,
805        example = r#"
806            extra-build-variables = { flash-attn = { FLASH_ATTENTION_SKIP_CUDA_BUILD = "TRUE" } }
807        "#
808    )]
809    pub extra_build_variables: Option<ExtraBuildVariables>,
810    /// Limit candidate packages to those that were uploaded prior to the given date.
811    ///
812    /// Accepts RFC 3339 timestamps (e.g., `2006-12-02T02:07:43Z`), a "friendly" duration (e.g.,
813    /// `24 hours`, `1 week`, `30 days`), or an ISO 8601 duration (e.g., `PT24H`, `P7D`, `P30D`).
814    ///
815    /// Durations do not respect semantics of the local time zone and are always resolved to a fixed
816    /// number of seconds assuming that a day is 24 hours (e.g., DST transitions are ignored).
817    /// Calendar units such as months and years are not allowed.
818    #[option(
819        default = "None",
820        value_type = "str",
821        example = r#"
822            exclude-newer = "2006-12-02T02:07:43Z"
823        "#
824    )]
825    pub exclude_newer: Option<ExcludeNewerValue>,
826    /// Limit candidate packages for specific packages to those that were uploaded prior to the
827    /// given date.
828    ///
829    /// Accepts a dictionary format of `PACKAGE = "DATE"` pairs, where `DATE` is an RFC 3339
830    /// timestamp (e.g., `2006-12-02T02:07:43Z`), a "friendly" duration (e.g., `24 hours`, `1 week`,
831    /// `30 days`), or a ISO 8601 duration (e.g., `PT24H`, `P7D`, `P30D`).
832    ///
833    /// Durations do not respect semantics of the local time zone and are always resolved to a fixed
834    /// number of seconds assuming that a day is 24 hours (e.g., DST transitions are ignored).
835    /// Calendar units such as months and years are not allowed.
836    #[option(
837        default = "None",
838        value_type = "dict",
839        example = r#"
840            exclude-newer-package = { tqdm = "2022-04-04T00:00:00Z" }
841        "#
842    )]
843    pub exclude_newer_package: Option<ExcludeNewerPackage>,
844    /// The method to use when installing packages from the global cache.
845    ///
846    /// Defaults to `clone` (also known as Copy-on-Write) on macOS, and `hardlink` on Linux and
847    /// Windows.
848    ///
849    /// WARNING: The use of symlink link mode is discouraged, as they create tight coupling between
850    /// the cache and the target environment. For example, clearing the cache (`uv cache clean`)
851    /// will break all installed packages by way of removing the underlying source files. Use
852    /// symlinks with caution.
853    #[option(
854        default = "\"clone\" (macOS) or \"hardlink\" (Linux, Windows)",
855        value_type = "str",
856        example = r#"
857            link-mode = "copy"
858        "#,
859        possible_values = true
860    )]
861    pub link_mode: Option<LinkMode>,
862    /// Compile Python files to bytecode after installation.
863    ///
864    /// By default, uv does not compile Python (`.py`) files to bytecode (`__pycache__/*.pyc`);
865    /// instead, compilation is performed lazily the first time a module is imported. For use-cases
866    /// in which start time is critical, such as CLI applications and Docker containers, this option
867    /// can be enabled to trade longer installation times for faster start times.
868    ///
869    /// When enabled, uv will process the entire site-packages directory (including packages that
870    /// are not being modified by the current operation) for consistency. Like pip, it will also
871    /// ignore errors.
872    #[option(
873        default = "false",
874        value_type = "bool",
875        example = r#"
876            compile-bytecode = true
877        "#
878    )]
879    pub compile_bytecode: Option<bool>,
880    /// Ignore the `tool.uv.sources` table when resolving dependencies. Used to lock against the
881    /// standards-compliant, publishable package metadata, as opposed to using any local or Git
882    /// sources.
883    #[option(
884        default = "false",
885        value_type = "bool",
886        example = r#"
887            no-sources = true
888        "#
889    )]
890    pub no_sources: Option<bool>,
891    /// Allow package upgrades, ignoring pinned versions in any existing output file.
892    #[option(
893        default = "false",
894        value_type = "bool",
895        example = r#"
896            upgrade = true
897        "#
898    )]
899    pub upgrade: Option<bool>,
900    /// Allow upgrades for a specific package, ignoring pinned versions in any existing output
901    /// file.
902    ///
903    /// Accepts both standalone package names (`ruff`) and version specifiers (`ruff<0.5.0`).
904    #[option(
905        default = "[]",
906        value_type = "list[str]",
907        example = r#"
908            upgrade-package = ["ruff"]
909        "#
910    )]
911    pub upgrade_package: Option<Vec<Requirement<VerbatimParsedUrl>>>,
912    /// Reinstall all packages, regardless of whether they're already installed. Implies `refresh`.
913    #[option(
914        default = "false",
915        value_type = "bool",
916        example = r#"
917            reinstall = true
918        "#
919    )]
920    pub reinstall: Option<bool>,
921    /// Reinstall a specific package, regardless of whether it's already installed. Implies
922    /// `refresh-package`.
923    #[option(
924        default = "[]",
925        value_type = "list[str]",
926        example = r#"
927            reinstall-package = ["ruff"]
928        "#
929    )]
930    pub reinstall_package: Option<Vec<PackageName>>,
931    /// Don't build source distributions.
932    ///
933    /// When enabled, resolving will not run arbitrary Python code. The cached wheels of
934    /// already-built source distributions will be reused, but operations that require building
935    /// distributions will exit with an error.
936    #[option(
937        default = "false",
938        value_type = "bool",
939        example = r#"
940            no-build = true
941        "#
942    )]
943    pub no_build: Option<bool>,
944    /// Don't build source distributions for a specific package.
945    #[option(
946        default = "[]",
947        value_type = "list[str]",
948        example = r#"
949            no-build-package = ["ruff"]
950        "#
951    )]
952    pub no_build_package: Option<Vec<PackageName>>,
953    /// Don't install pre-built wheels.
954    ///
955    /// The given packages will be built and installed from source. The resolver will still use
956    /// pre-built wheels to extract package metadata, if available.
957    #[option(
958        default = "false",
959        value_type = "bool",
960        example = r#"
961            no-binary = true
962        "#
963    )]
964    pub no_binary: Option<bool>,
965    /// Don't install pre-built wheels for a specific package.
966    #[option(
967        default = "[]",
968        value_type = "list[str]",
969        example = r#"
970            no-binary-package = ["ruff"]
971        "#
972    )]
973    pub no_binary_package: Option<Vec<PackageName>>,
974    /// The backend to use when fetching packages in the PyTorch ecosystem.
975    ///
976    /// When set, uv will ignore the configured index URLs for packages in the PyTorch ecosystem,
977    /// and will instead use the defined backend.
978    ///
979    /// For example, when set to `cpu`, uv will use the CPU-only PyTorch index; when set to `cu126`,
980    /// uv will use the PyTorch index for CUDA 12.6.
981    ///
982    /// The `auto` mode will attempt to detect the appropriate PyTorch index based on the currently
983    /// installed CUDA drivers.
984    ///
985    /// This setting is only respected by `uv pip` commands.
986    ///
987    /// This option is in preview and may change in any future release.
988    #[option(
989        default = "null",
990        value_type = "str",
991        example = r#"
992            torch-backend = "auto"
993        "#
994    )]
995    pub torch_backend: Option<TorchMode>,
996}
997
998/// Shared settings, relevant to all operations that might create managed python installations.
999#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, CombineOptions, OptionsMetadata)]
1000#[serde(rename_all = "kebab-case")]
1001#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1002pub struct PythonInstallMirrors {
1003    /// Mirror URL for downloading managed Python installations.
1004    ///
1005    /// By default, managed Python installations are downloaded from [`python-build-standalone`](https://github.com/astral-sh/python-build-standalone).
1006    /// This variable can be set to a mirror URL to use a different source for Python installations.
1007    /// The provided URL will replace `https://github.com/astral-sh/python-build-standalone/releases/download` in, e.g., `https://github.com/astral-sh/python-build-standalone/releases/download/20240713/cpython-3.12.4%2B20240713-aarch64-apple-darwin-install_only.tar.gz`.
1008    ///
1009    /// Distributions can be read from a local directory by using the `file://` URL scheme.
1010    #[option(
1011        default = "None",
1012        value_type = "str",
1013        example = r#"
1014            python-install-mirror = "https://github.com/astral-sh/python-build-standalone/releases/download"
1015        "#
1016    )]
1017    pub python_install_mirror: Option<String>,
1018    /// Mirror URL to use for downloading managed PyPy installations.
1019    ///
1020    /// By default, managed PyPy installations are downloaded from [downloads.python.org](https://downloads.python.org/).
1021    /// This variable can be set to a mirror URL to use a different source for PyPy installations.
1022    /// The provided URL will replace `https://downloads.python.org/pypy` in, e.g., `https://downloads.python.org/pypy/pypy3.8-v7.3.7-osx64.tar.bz2`.
1023    ///
1024    /// Distributions can be read from a
1025    /// local directory by using the `file://` URL scheme.
1026    #[option(
1027        default = "None",
1028        value_type = "str",
1029        example = r#"
1030            pypy-install-mirror = "https://downloads.python.org/pypy"
1031        "#
1032    )]
1033    pub pypy_install_mirror: Option<String>,
1034
1035    /// URL pointing to JSON of custom Python installations.
1036    #[option(
1037        default = "None",
1038        value_type = "str",
1039        example = r#"
1040            python-downloads-json-url = "/etc/uv/python-downloads.json"
1041        "#
1042    )]
1043    pub python_downloads_json_url: Option<String>,
1044}
1045
1046impl PythonInstallMirrors {
1047    #[must_use]
1048    pub fn combine(self, other: Self) -> Self {
1049        Self {
1050            python_install_mirror: self.python_install_mirror.or(other.python_install_mirror),
1051            pypy_install_mirror: self.pypy_install_mirror.or(other.pypy_install_mirror),
1052            python_downloads_json_url: self
1053                .python_downloads_json_url
1054                .or(other.python_downloads_json_url),
1055        }
1056    }
1057}
1058
1059/// Settings that are specific to the `uv pip` command-line interface.
1060///
1061/// These values will be ignored when running commands outside the `uv pip` namespace (e.g.,
1062/// `uv lock`, `uvx`).
1063#[derive(Debug, Clone, Default, Deserialize, CombineOptions, OptionsMetadata)]
1064#[serde(deny_unknown_fields, rename_all = "kebab-case")]
1065#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1066pub struct PipOptions {
1067    /// The Python interpreter into which packages should be installed.
1068    ///
1069    /// By default, uv installs into the virtual environment in the current working directory or
1070    /// any parent directory. The `--python` option allows you to specify a different interpreter,
1071    /// which is intended for use in continuous integration (CI) environments or other automated
1072    /// workflows.
1073    ///
1074    /// Supported formats:
1075    /// - `3.10` looks for an installed Python 3.10 in the registry on Windows (see
1076    ///   `py --list-paths`), or `python3.10` on Linux and macOS.
1077    /// - `python3.10` or `python.exe` looks for a binary with the given name in `PATH`.
1078    /// - `/home/ferris/.local/bin/python3.10` uses the exact Python at the given path.
1079    #[option(
1080        default = "None",
1081        value_type = "str",
1082        example = r#"
1083            python = "3.10"
1084        "#
1085    )]
1086    pub python: Option<String>,
1087    /// Install packages into the system Python environment.
1088    ///
1089    /// By default, uv installs into the virtual environment in the current working directory or
1090    /// any parent directory. The `--system` option instructs uv to instead use the first Python
1091    /// found in the system `PATH`.
1092    ///
1093    /// WARNING: `--system` is intended for use in continuous integration (CI) environments and
1094    /// should be used with caution, as it can modify the system Python installation.
1095    #[option(
1096        default = "false",
1097        value_type = "bool",
1098        example = r#"
1099            system = true
1100        "#
1101    )]
1102    pub system: Option<bool>,
1103    /// Allow uv to modify an `EXTERNALLY-MANAGED` Python installation.
1104    ///
1105    /// WARNING: `--break-system-packages` is intended for use in continuous integration (CI)
1106    /// environments, when installing into Python installations that are managed by an external
1107    /// package manager, like `apt`. It should be used with caution, as such Python installations
1108    /// explicitly recommend against modifications by other package managers (like uv or pip).
1109    #[option(
1110        default = "false",
1111        value_type = "bool",
1112        example = r#"
1113            break-system-packages = true
1114        "#
1115    )]
1116    pub break_system_packages: Option<bool>,
1117    /// Install packages into the specified directory, rather than into the virtual or system Python
1118    /// environment. The packages will be installed at the top-level of the directory.
1119    #[option(
1120        default = "None",
1121        value_type = "str",
1122        example = r#"
1123            target = "./target"
1124        "#
1125    )]
1126    pub target: Option<PathBuf>,
1127    /// Install packages into `lib`, `bin`, and other top-level folders under the specified
1128    /// directory, as if a virtual environment were present at that location.
1129    ///
1130    /// In general, prefer the use of `--python` to install into an alternate environment, as
1131    /// scripts and other artifacts installed via `--prefix` will reference the installing
1132    /// interpreter, rather than any interpreter added to the `--prefix` directory, rendering them
1133    /// non-portable.
1134    #[option(
1135        default = "None",
1136        value_type = "str",
1137        example = r#"
1138            prefix = "./prefix"
1139        "#
1140    )]
1141    pub prefix: Option<PathBuf>,
1142    #[serde(skip)]
1143    #[cfg_attr(feature = "schemars", schemars(skip))]
1144    pub index: Option<Vec<Index>>,
1145    /// The URL of the Python package index (by default: <https://pypi.org/simple>).
1146    ///
1147    /// Accepts either a repository compliant with [PEP 503](https://peps.python.org/pep-0503/)
1148    /// (the simple repository API), or a local directory laid out in the same format.
1149    ///
1150    /// The index provided by this setting is given lower priority than any indexes specified via
1151    /// [`extra_index_url`](#extra-index-url).
1152    #[option(
1153        default = "\"https://pypi.org/simple\"",
1154        value_type = "str",
1155        example = r#"
1156            index-url = "https://test.pypi.org/simple"
1157        "#
1158    )]
1159    pub index_url: Option<PipIndex>,
1160    /// Extra URLs of package indexes to use, in addition to `--index-url`.
1161    ///
1162    /// Accepts either a repository compliant with [PEP 503](https://peps.python.org/pep-0503/)
1163    /// (the simple repository API), or a local directory laid out in the same format.
1164    ///
1165    /// All indexes provided via this flag take priority over the index specified by
1166    /// [`index_url`](#index-url). When multiple indexes are provided, earlier values take priority.
1167    ///
1168    /// To control uv's resolution strategy when multiple indexes are present, see
1169    /// [`index_strategy`](#index-strategy).
1170    #[option(
1171        default = "[]",
1172        value_type = "list[str]",
1173        example = r#"
1174            extra-index-url = ["https://download.pytorch.org/whl/cpu"]
1175        "#
1176    )]
1177    pub extra_index_url: Option<Vec<PipExtraIndex>>,
1178    /// Ignore all registry indexes (e.g., PyPI), instead relying on direct URL dependencies and
1179    /// those provided via `--find-links`.
1180    #[option(
1181        default = "false",
1182        value_type = "bool",
1183        example = r#"
1184            no-index = true
1185        "#
1186    )]
1187    pub no_index: Option<bool>,
1188    /// Locations to search for candidate distributions, in addition to those found in the registry
1189    /// indexes.
1190    ///
1191    /// If a path, the target must be a directory that contains packages as wheel files (`.whl`) or
1192    /// source distributions (e.g., `.tar.gz` or `.zip`) at the top level.
1193    ///
1194    /// If a URL, the page must contain a flat list of links to package files adhering to the
1195    /// formats described above.
1196    #[option(
1197        default = "[]",
1198        value_type = "list[str]",
1199        example = r#"
1200            find-links = ["https://download.pytorch.org/whl/torch_stable.html"]
1201        "#
1202    )]
1203    pub find_links: Option<Vec<PipFindLinks>>,
1204    /// The strategy to use when resolving against multiple index URLs.
1205    ///
1206    /// By default, uv will stop at the first index on which a given package is available, and
1207    /// limit resolutions to those present on that first index (`first-index`). This prevents
1208    /// "dependency confusion" attacks, whereby an attacker can upload a malicious package under the
1209    /// same name to an alternate index.
1210    #[option(
1211        default = "\"first-index\"",
1212        value_type = "str",
1213        example = r#"
1214            index-strategy = "unsafe-best-match"
1215        "#,
1216        possible_values = true
1217    )]
1218    pub index_strategy: Option<IndexStrategy>,
1219    /// Attempt to use `keyring` for authentication for index URLs.
1220    ///
1221    /// At present, only `--keyring-provider subprocess` is supported, which configures uv to
1222    /// use the `keyring` CLI to handle authentication.
1223    #[option(
1224        default = "disabled",
1225        value_type = "str",
1226        example = r#"
1227            keyring-provider = "subprocess"
1228        "#
1229    )]
1230    pub keyring_provider: Option<KeyringProviderType>,
1231    /// Don't build source distributions.
1232    ///
1233    /// When enabled, resolving will not run arbitrary Python code. The cached wheels of
1234    /// already-built source distributions will be reused, but operations that require building
1235    /// distributions will exit with an error.
1236    ///
1237    /// Alias for `--only-binary :all:`.
1238    #[option(
1239        default = "false",
1240        value_type = "bool",
1241        example = r#"
1242            no-build = true
1243        "#
1244    )]
1245    pub no_build: Option<bool>,
1246    /// Don't install pre-built wheels.
1247    ///
1248    /// The given packages will be built and installed from source. The resolver will still use
1249    /// pre-built wheels to extract package metadata, if available.
1250    ///
1251    /// Multiple packages may be provided. Disable binaries for all packages with `:all:`.
1252    /// Clear previously specified packages with `:none:`.
1253    #[option(
1254        default = "[]",
1255        value_type = "list[str]",
1256        example = r#"
1257            no-binary = ["ruff"]
1258        "#
1259    )]
1260    pub no_binary: Option<Vec<PackageNameSpecifier>>,
1261    /// Only use pre-built wheels; don't build source distributions.
1262    ///
1263    /// When enabled, resolving will not run code from the given packages. The cached wheels of already-built
1264    /// source distributions will be reused, but operations that require building distributions will
1265    /// exit with an error.
1266    ///
1267    /// Multiple packages may be provided. Disable binaries for all packages with `:all:`.
1268    /// Clear previously specified packages with `:none:`.
1269    #[option(
1270        default = "[]",
1271        value_type = "list[str]",
1272        example = r#"
1273            only-binary = ["ruff"]
1274        "#
1275    )]
1276    pub only_binary: Option<Vec<PackageNameSpecifier>>,
1277    /// Disable isolation when building source distributions.
1278    ///
1279    /// Assumes that build dependencies specified by [PEP 518](https://peps.python.org/pep-0518/)
1280    /// are already installed.
1281    #[option(
1282        default = "false",
1283        value_type = "bool",
1284        example = r#"
1285            no-build-isolation = true
1286        "#
1287    )]
1288    pub no_build_isolation: Option<bool>,
1289    /// Disable isolation when building source distributions for a specific package.
1290    ///
1291    /// Assumes that the packages' build dependencies specified by [PEP 518](https://peps.python.org/pep-0518/)
1292    /// are already installed.
1293    #[option(
1294        default = "[]",
1295        value_type = "list[str]",
1296        example = r#"
1297            no-build-isolation-package = ["package1", "package2"]
1298        "#
1299    )]
1300    pub no_build_isolation_package: Option<Vec<PackageName>>,
1301    /// Additional build dependencies for packages.
1302    ///
1303    /// This allows extending the PEP 517 build environment for the project's dependencies with
1304    /// additional packages. This is useful for packages that assume the presence of packages like
1305    /// `pip`, and do not declare them as build dependencies.
1306    #[option(
1307        default = "[]",
1308        value_type = "dict",
1309        example = r#"
1310            extra-build-dependencies = { pytest = ["setuptools"] }
1311        "#
1312    )]
1313    pub extra_build_dependencies: Option<ExtraBuildDependencies>,
1314    /// Extra environment variables to set when building certain packages.
1315    ///
1316    /// Environment variables will be added to the environment when building the
1317    /// specified packages.
1318    #[option(
1319        default = r#"{}"#,
1320        value_type = r#"dict[str, dict[str, str]]"#,
1321        example = r#"
1322            extra-build-variables = { flash-attn = { FLASH_ATTENTION_SKIP_CUDA_BUILD = "TRUE" } }
1323        "#
1324    )]
1325    pub extra_build_variables: Option<ExtraBuildVariables>,
1326    /// Validate the Python environment, to detect packages with missing dependencies and other
1327    /// issues.
1328    #[option(
1329        default = "false",
1330        value_type = "bool",
1331        example = r#"
1332            strict = true
1333        "#
1334    )]
1335    pub strict: Option<bool>,
1336    /// Include optional dependencies from the specified extra; may be provided more than once.
1337    ///
1338    /// Only applies to `pyproject.toml`, `setup.py`, and `setup.cfg` sources.
1339    #[option(
1340        default = "[]",
1341        value_type = "list[str]",
1342        example = r#"
1343            extra = ["dev", "docs"]
1344        "#
1345    )]
1346    pub extra: Option<Vec<ExtraName>>,
1347    /// Include all optional dependencies.
1348    ///
1349    /// Only applies to `pyproject.toml`, `setup.py`, and `setup.cfg` sources.
1350    #[option(
1351        default = "false",
1352        value_type = "bool",
1353        example = r#"
1354            all-extras = true
1355        "#
1356    )]
1357    pub all_extras: Option<bool>,
1358    /// Exclude the specified optional dependencies if `all-extras` is supplied.
1359    #[option(
1360        default = "[]",
1361        value_type = "list[str]",
1362        example = r#"
1363            all-extras = true
1364            no-extra = ["dev", "docs"]
1365        "#
1366    )]
1367    pub no_extra: Option<Vec<ExtraName>>,
1368    /// Ignore package dependencies, instead only add those packages explicitly listed
1369    /// on the command line to the resulting requirements file.
1370    #[option(
1371        default = "false",
1372        value_type = "bool",
1373        example = r#"
1374            no-deps = true
1375        "#
1376    )]
1377    pub no_deps: Option<bool>,
1378    /// Include the following dependency groups.
1379    #[option(
1380        default = "None",
1381        value_type = "list[str]",
1382        example = r#"
1383            group = ["dev", "docs"]
1384        "#
1385    )]
1386    pub group: Option<Vec<PipGroupName>>,
1387    /// Allow `uv pip sync` with empty requirements, which will clear the environment of all
1388    /// packages.
1389    #[option(
1390        default = "false",
1391        value_type = "bool",
1392        example = r#"
1393            allow-empty-requirements = true
1394        "#
1395    )]
1396    pub allow_empty_requirements: Option<bool>,
1397    /// The strategy to use when selecting between the different compatible versions for a given
1398    /// package requirement.
1399    ///
1400    /// By default, uv will use the latest compatible version of each package (`highest`).
1401    #[option(
1402        default = "\"highest\"",
1403        value_type = "str",
1404        example = r#"
1405            resolution = "lowest-direct"
1406        "#,
1407        possible_values = true
1408    )]
1409    pub resolution: Option<ResolutionMode>,
1410    /// The strategy to use when considering pre-release versions.
1411    ///
1412    /// By default, uv will accept pre-releases for packages that _only_ publish pre-releases,
1413    /// along with first-party requirements that contain an explicit pre-release marker in the
1414    /// declared specifiers (`if-necessary-or-explicit`).
1415    #[option(
1416        default = "\"if-necessary-or-explicit\"",
1417        value_type = "str",
1418        example = r#"
1419            prerelease = "allow"
1420        "#,
1421        possible_values = true
1422    )]
1423    pub prerelease: Option<PrereleaseMode>,
1424    /// The strategy to use when selecting multiple versions of a given package across Python
1425    /// versions and platforms.
1426    ///
1427    /// By default, uv will optimize for selecting the latest version of each package for each
1428    /// supported Python version (`requires-python`), while minimizing the number of selected
1429    /// versions across platforms.
1430    ///
1431    /// Under `fewest`, uv will minimize the number of selected versions for each package,
1432    /// preferring older versions that are compatible with a wider range of supported Python
1433    /// versions or platforms.
1434    #[option(
1435        default = "\"requires-python\"",
1436        value_type = "str",
1437        example = r#"
1438            fork-strategy = "fewest"
1439        "#,
1440        possible_values = true
1441    )]
1442    pub fork_strategy: Option<ForkStrategy>,
1443    /// Pre-defined static metadata for dependencies of the project (direct or transitive). When
1444    /// provided, enables the resolver to use the specified metadata instead of querying the
1445    /// registry or building the relevant package from source.
1446    ///
1447    /// Metadata should be provided in adherence with the [Metadata 2.3](https://packaging.python.org/en/latest/specifications/core-metadata/)
1448    /// standard, though only the following fields are respected:
1449    ///
1450    /// - `name`: The name of the package.
1451    /// - (Optional) `version`: The version of the package. If omitted, the metadata will be applied
1452    ///   to all versions of the package.
1453    /// - (Optional) `requires-dist`: The dependencies of the package (e.g., `werkzeug>=0.14`).
1454    /// - (Optional) `requires-python`: The Python version required by the package (e.g., `>=3.10`).
1455    /// - (Optional) `provides-extra`: The extras provided by the package.
1456    #[option(
1457        default = r#"[]"#,
1458        value_type = "list[dict]",
1459        example = r#"
1460            dependency-metadata = [
1461                { name = "flask", version = "1.0.0", requires-dist = ["werkzeug"], requires-python = ">=3.6" },
1462            ]
1463        "#
1464    )]
1465    pub dependency_metadata: Option<Vec<StaticMetadata>>,
1466    /// Write the requirements generated by `uv pip compile` to the given `requirements.txt` file.
1467    ///
1468    /// If the file already exists, the existing versions will be preferred when resolving
1469    /// dependencies, unless `--upgrade` is also specified.
1470    #[option(
1471        default = "None",
1472        value_type = "str",
1473        example = r#"
1474            output-file = "requirements.txt"
1475        "#
1476    )]
1477    pub output_file: Option<PathBuf>,
1478    /// Include extras in the output file.
1479    ///
1480    /// By default, uv strips extras, as any packages pulled in by the extras are already included
1481    /// as dependencies in the output file directly. Further, output files generated with
1482    /// `--no-strip-extras` cannot be used as constraints files in `install` and `sync` invocations.
1483    #[option(
1484        default = "false",
1485        value_type = "bool",
1486        example = r#"
1487            no-strip-extras = true
1488        "#
1489    )]
1490    pub no_strip_extras: Option<bool>,
1491    /// Include environment markers in the output file generated by `uv pip compile`.
1492    ///
1493    /// By default, uv strips environment markers, as the resolution generated by `compile` is
1494    /// only guaranteed to be correct for the target environment.
1495    #[option(
1496        default = "false",
1497        value_type = "bool",
1498        example = r#"
1499            no-strip-markers = true
1500        "#
1501    )]
1502    pub no_strip_markers: Option<bool>,
1503    /// Exclude comment annotations indicating the source of each package from the output file
1504    /// generated by `uv pip compile`.
1505    #[option(
1506        default = "false",
1507        value_type = "bool",
1508        example = r#"
1509            no-annotate = true
1510        "#
1511    )]
1512    pub no_annotate: Option<bool>,
1513    /// Exclude the comment header at the top of output file generated by `uv pip compile`.
1514    #[option(
1515        default = r#"false"#,
1516        value_type = "bool",
1517        example = r#"
1518            no-header = true
1519        "#
1520    )]
1521    pub no_header: Option<bool>,
1522    /// The header comment to include at the top of the output file generated by `uv pip compile`.
1523    ///
1524    /// Used to reflect custom build scripts and commands that wrap `uv pip compile`.
1525    #[option(
1526        default = "None",
1527        value_type = "str",
1528        example = r#"
1529            custom-compile-command = "./custom-uv-compile.sh"
1530        "#
1531    )]
1532    pub custom_compile_command: Option<String>,
1533    /// Include distribution hashes in the output file.
1534    #[option(
1535        default = "false",
1536        value_type = "bool",
1537        example = r#"
1538            generate-hashes = true
1539        "#
1540    )]
1541    pub generate_hashes: Option<bool>,
1542    /// Settings to pass to the [PEP 517](https://peps.python.org/pep-0517/) build backend,
1543    /// specified as `KEY=VALUE` pairs.
1544    #[option(
1545        default = "{}",
1546        value_type = "dict",
1547        example = r#"
1548            config-settings = { editable_mode = "compat" }
1549        "#
1550    )]
1551    pub config_settings: Option<ConfigSettings>,
1552    /// Settings to pass to the [PEP 517](https://peps.python.org/pep-0517/) build backend for specific packages,
1553    /// specified as `KEY=VALUE` pairs.
1554    #[option(
1555        default = "{}",
1556        value_type = "dict",
1557        example = r#"
1558            config-settings-package = { numpy = { editable_mode = "compat" } }
1559        "#
1560    )]
1561    pub config_settings_package: Option<PackageConfigSettings>,
1562    /// The minimum Python version that should be supported by the resolved requirements (e.g.,
1563    /// `3.8` or `3.8.17`).
1564    ///
1565    /// If a patch version is omitted, the minimum patch version is assumed. For example, `3.8` is
1566    /// mapped to `3.8.0`.
1567    #[option(
1568        default = "None",
1569        value_type = "str",
1570        example = r#"
1571            python-version = "3.8"
1572        "#
1573    )]
1574    pub python_version: Option<PythonVersion>,
1575    /// The platform for which requirements should be resolved.
1576    ///
1577    /// Represented as a "target triple", a string that describes the target platform in terms of
1578    /// its CPU, vendor, and operating system name, like `x86_64-unknown-linux-gnu` or
1579    /// `aarch64-apple-darwin`.
1580    #[option(
1581        default = "None",
1582        value_type = "str",
1583        example = r#"
1584            python-platform = "x86_64-unknown-linux-gnu"
1585        "#
1586    )]
1587    pub python_platform: Option<TargetTriple>,
1588    /// Perform a universal resolution, attempting to generate a single `requirements.txt` output
1589    /// file that is compatible with all operating systems, architectures, and Python
1590    /// implementations.
1591    ///
1592    /// In universal mode, the current Python version (or user-provided `--python-version`) will be
1593    /// treated as a lower bound. For example, `--universal --python-version 3.7` would produce a
1594    /// universal resolution for Python 3.7 and later.
1595    #[option(
1596        default = "false",
1597        value_type = "bool",
1598        example = r#"
1599            universal = true
1600        "#
1601    )]
1602    pub universal: Option<bool>,
1603    /// Limit candidate packages to those that were uploaded prior to a given point in time.
1604    ///
1605    /// Accepts a superset of [RFC 3339](https://www.rfc-editor.org/rfc/rfc3339.html) (e.g.,
1606    /// `2006-12-02T02:07:43Z`). A full timestamp is required to ensure that the resolver will
1607    /// behave consistently across timezones.
1608    #[option(
1609        default = "None",
1610        value_type = "str",
1611        example = r#"
1612            exclude-newer = "2006-12-02T02:07:43Z"
1613        "#
1614    )]
1615    pub exclude_newer: Option<ExcludeNewerValue>,
1616    /// Limit candidate packages for specific packages to those that were uploaded prior to the given date.
1617    ///
1618    /// Accepts package-date pairs in a dictionary format.
1619    #[option(
1620        default = "None",
1621        value_type = "dict",
1622        example = r#"
1623            exclude-newer-package = { tqdm = "2022-04-04T00:00:00Z" }
1624        "#
1625    )]
1626    pub exclude_newer_package: Option<ExcludeNewerPackage>,
1627    /// Specify a package to omit from the output resolution. Its dependencies will still be
1628    /// included in the resolution. Equivalent to pip-compile's `--unsafe-package` option.
1629    #[option(
1630        default = "[]",
1631        value_type = "list[str]",
1632        example = r#"
1633            no-emit-package = ["ruff"]
1634        "#
1635    )]
1636    pub no_emit_package: Option<Vec<PackageName>>,
1637    /// Include `--index-url` and `--extra-index-url` entries in the output file generated by `uv pip compile`.
1638    #[option(
1639        default = "false",
1640        value_type = "bool",
1641        example = r#"
1642            emit-index-url = true
1643        "#
1644    )]
1645    pub emit_index_url: Option<bool>,
1646    /// Include `--find-links` entries in the output file generated by `uv pip compile`.
1647    #[option(
1648        default = "false",
1649        value_type = "bool",
1650        example = r#"
1651            emit-find-links = true
1652        "#
1653    )]
1654    pub emit_find_links: Option<bool>,
1655    /// Include `--no-binary` and `--only-binary` entries in the output file generated by `uv pip compile`.
1656    #[option(
1657        default = "false",
1658        value_type = "bool",
1659        example = r#"
1660            emit-build-options = true
1661        "#
1662    )]
1663    pub emit_build_options: Option<bool>,
1664    /// Whether to emit a marker string indicating the conditions under which the set of pinned
1665    /// dependencies is valid.
1666    ///
1667    /// The pinned dependencies may be valid even when the marker expression is
1668    /// false, but when the expression is true, the requirements are known to
1669    /// be correct.
1670    #[option(
1671        default = "false",
1672        value_type = "bool",
1673        example = r#"
1674            emit-marker-expression = true
1675        "#
1676    )]
1677    pub emit_marker_expression: Option<bool>,
1678    /// Include comment annotations indicating the index used to resolve each package (e.g.,
1679    /// `# from https://pypi.org/simple`).
1680    #[option(
1681        default = "false",
1682        value_type = "bool",
1683        example = r#"
1684            emit-index-annotation = true
1685        "#
1686    )]
1687    pub emit_index_annotation: Option<bool>,
1688    /// The style of the annotation comments included in the output file, used to indicate the
1689    /// source of each package.
1690    #[option(
1691        default = "\"split\"",
1692        value_type = "str",
1693        example = r#"
1694            annotation-style = "line"
1695        "#,
1696        possible_values = true
1697    )]
1698    pub annotation_style: Option<AnnotationStyle>,
1699    /// The method to use when installing packages from the global cache.
1700    ///
1701    /// Defaults to `clone` (also known as Copy-on-Write) on macOS, and `hardlink` on Linux and
1702    /// Windows.
1703    ///
1704    /// WARNING: The use of symlink link mode is discouraged, as they create tight coupling between
1705    /// the cache and the target environment. For example, clearing the cache (`uv cache clean`)
1706    /// will break all installed packages by way of removing the underlying source files. Use
1707    /// symlinks with caution.
1708    #[option(
1709        default = "\"clone\" (macOS) or \"hardlink\" (Linux, Windows)",
1710        value_type = "str",
1711        example = r#"
1712            link-mode = "copy"
1713        "#,
1714        possible_values = true
1715    )]
1716    pub link_mode: Option<LinkMode>,
1717    /// Compile Python files to bytecode after installation.
1718    ///
1719    /// By default, uv does not compile Python (`.py`) files to bytecode (`__pycache__/*.pyc`);
1720    /// instead, compilation is performed lazily the first time a module is imported. For use-cases
1721    /// in which start time is critical, such as CLI applications and Docker containers, this option
1722    /// can be enabled to trade longer installation times for faster start times.
1723    ///
1724    /// When enabled, uv will process the entire site-packages directory (including packages that
1725    /// are not being modified by the current operation) for consistency. Like pip, it will also
1726    /// ignore errors.
1727    #[option(
1728        default = "false",
1729        value_type = "bool",
1730        example = r#"
1731            compile-bytecode = true
1732        "#
1733    )]
1734    pub compile_bytecode: Option<bool>,
1735    /// Require a matching hash for each requirement.
1736    ///
1737    /// Hash-checking mode is all or nothing. If enabled, _all_ requirements must be provided
1738    /// with a corresponding hash or set of hashes. Additionally, if enabled, _all_ requirements
1739    /// must either be pinned to exact versions (e.g., `==1.0.0`), or be specified via direct URL.
1740    ///
1741    /// Hash-checking mode introduces a number of additional constraints:
1742    ///
1743    /// - Git dependencies are not supported.
1744    /// - Editable installations are not supported.
1745    /// - Local dependencies are not supported, unless they point to a specific wheel (`.whl`) or
1746    ///   source archive (`.zip`, `.tar.gz`), as opposed to a directory.
1747    #[option(
1748        default = "false",
1749        value_type = "bool",
1750        example = r#"
1751            require-hashes = true
1752        "#
1753    )]
1754    pub require_hashes: Option<bool>,
1755    /// Validate any hashes provided in the requirements file.
1756    ///
1757    /// Unlike `--require-hashes`, `--verify-hashes` does not require that all requirements have
1758    /// hashes; instead, it will limit itself to verifying the hashes of those requirements that do
1759    /// include them.
1760    #[option(
1761        default = "true",
1762        value_type = "bool",
1763        example = r#"
1764            verify-hashes = true
1765        "#
1766    )]
1767    pub verify_hashes: Option<bool>,
1768    /// Ignore the `tool.uv.sources` table when resolving dependencies. Used to lock against the
1769    /// standards-compliant, publishable package metadata, as opposed to using any local or Git
1770    /// sources.
1771    #[option(
1772        default = "false",
1773        value_type = "bool",
1774        example = r#"
1775            no-sources = true
1776        "#
1777    )]
1778    pub no_sources: Option<bool>,
1779    /// Allow package upgrades, ignoring pinned versions in any existing output file.
1780    #[option(
1781        default = "false",
1782        value_type = "bool",
1783        example = r#"
1784            upgrade = true
1785        "#
1786    )]
1787    pub upgrade: Option<bool>,
1788    /// Allow upgrades for a specific package, ignoring pinned versions in any existing output
1789    /// file.
1790    ///
1791    /// Accepts both standalone package names (`ruff`) and version specifiers (`ruff<0.5.0`).
1792    #[option(
1793        default = "[]",
1794        value_type = "list[str]",
1795        example = r#"
1796            upgrade-package = ["ruff"]
1797        "#
1798    )]
1799    pub upgrade_package: Option<Vec<Requirement<VerbatimParsedUrl>>>,
1800    /// Reinstall all packages, regardless of whether they're already installed. Implies `refresh`.
1801    #[option(
1802        default = "false",
1803        value_type = "bool",
1804        example = r#"
1805            reinstall = true
1806        "#
1807    )]
1808    pub reinstall: Option<bool>,
1809    /// Reinstall a specific package, regardless of whether it's already installed. Implies
1810    /// `refresh-package`.
1811    #[option(
1812        default = "[]",
1813        value_type = "list[str]",
1814        example = r#"
1815            reinstall-package = ["ruff"]
1816        "#
1817    )]
1818    pub reinstall_package: Option<Vec<PackageName>>,
1819    /// The backend to use when fetching packages in the PyTorch ecosystem.
1820    ///
1821    /// When set, uv will ignore the configured index URLs for packages in the PyTorch ecosystem,
1822    /// and will instead use the defined backend.
1823    ///
1824    /// For example, when set to `cpu`, uv will use the CPU-only PyTorch index; when set to `cu126`,
1825    /// uv will use the PyTorch index for CUDA 12.6.
1826    ///
1827    /// The `auto` mode will attempt to detect the appropriate PyTorch index based on the currently
1828    /// installed CUDA drivers.
1829    ///
1830    /// This setting is only respected by `uv pip` commands.
1831    ///
1832    /// This option is in preview and may change in any future release.
1833    #[option(
1834        default = "null",
1835        value_type = "str",
1836        example = r#"
1837            torch-backend = "auto"
1838        "#
1839    )]
1840    pub torch_backend: Option<TorchMode>,
1841}
1842
1843impl PipOptions {
1844    /// Resolve the [`PipOptions`] relative to the given root directory.
1845    pub fn relative_to(self, root_dir: &Path) -> Result<Self, IndexUrlError> {
1846        Ok(Self {
1847            index: self
1848                .index
1849                .map(|index| {
1850                    index
1851                        .into_iter()
1852                        .map(|index| index.relative_to(root_dir))
1853                        .collect::<Result<Vec<_>, _>>()
1854                })
1855                .transpose()?,
1856            index_url: self
1857                .index_url
1858                .map(|index_url| index_url.relative_to(root_dir))
1859                .transpose()?,
1860            extra_index_url: self
1861                .extra_index_url
1862                .map(|extra_index_url| {
1863                    extra_index_url
1864                        .into_iter()
1865                        .map(|extra_index_url| extra_index_url.relative_to(root_dir))
1866                        .collect::<Result<Vec<_>, _>>()
1867                })
1868                .transpose()?,
1869            find_links: self
1870                .find_links
1871                .map(|find_links| {
1872                    find_links
1873                        .into_iter()
1874                        .map(|find_link| find_link.relative_to(root_dir))
1875                        .collect::<Result<Vec<_>, _>>()
1876                })
1877                .transpose()?,
1878            ..self
1879        })
1880    }
1881}
1882
1883impl From<ResolverInstallerSchema> for ResolverOptions {
1884    fn from(value: ResolverInstallerSchema) -> Self {
1885        Self {
1886            index: value.index,
1887            index_url: value.index_url,
1888            extra_index_url: value.extra_index_url,
1889            no_index: value.no_index,
1890            find_links: value.find_links,
1891            index_strategy: value.index_strategy,
1892            keyring_provider: value.keyring_provider,
1893            resolution: value.resolution,
1894            prerelease: value.prerelease,
1895            fork_strategy: value.fork_strategy,
1896            dependency_metadata: value.dependency_metadata,
1897            config_settings: value.config_settings,
1898            config_settings_package: value.config_settings_package,
1899            exclude_newer: ExcludeNewer::from_args(
1900                value.exclude_newer,
1901                value
1902                    .exclude_newer_package
1903                    .unwrap_or_default()
1904                    .into_iter()
1905                    .map(Into::into)
1906                    .collect(),
1907            ),
1908            link_mode: value.link_mode,
1909            upgrade: Upgrade::from_args(
1910                value.upgrade,
1911                value
1912                    .upgrade_package
1913                    .into_iter()
1914                    .flatten()
1915                    .map(Into::into)
1916                    .collect(),
1917            ),
1918            no_build: value.no_build,
1919            no_build_package: value.no_build_package,
1920            no_binary: value.no_binary,
1921            no_binary_package: value.no_binary_package,
1922            build_isolation: BuildIsolation::from_args(
1923                value.no_build_isolation,
1924                value.no_build_isolation_package.unwrap_or_default(),
1925            ),
1926            extra_build_dependencies: value.extra_build_dependencies,
1927            extra_build_variables: value.extra_build_variables,
1928            no_sources: value.no_sources,
1929            torch_backend: value.torch_backend,
1930        }
1931    }
1932}
1933
1934impl From<ResolverInstallerSchema> for InstallerOptions {
1935    fn from(value: ResolverInstallerSchema) -> Self {
1936        Self {
1937            index: value.index,
1938            index_url: value.index_url,
1939            extra_index_url: value.extra_index_url,
1940            no_index: value.no_index,
1941            find_links: value.find_links,
1942            index_strategy: value.index_strategy,
1943            keyring_provider: value.keyring_provider,
1944            config_settings: value.config_settings,
1945            exclude_newer: ExcludeNewer::from_args(
1946                value.exclude_newer,
1947                value
1948                    .exclude_newer_package
1949                    .unwrap_or_default()
1950                    .into_iter()
1951                    .map(Into::into)
1952                    .collect(),
1953            )
1954            .global,
1955            link_mode: value.link_mode,
1956            compile_bytecode: value.compile_bytecode,
1957            reinstall: Reinstall::from_args(
1958                value.reinstall,
1959                value.reinstall_package.unwrap_or_default(),
1960            ),
1961            build_isolation: BuildIsolation::from_args(
1962                value.no_build_isolation,
1963                value.no_build_isolation_package.unwrap_or_default(),
1964            ),
1965            no_build: value.no_build,
1966            no_build_package: value.no_build_package,
1967            no_binary: value.no_binary,
1968            no_binary_package: value.no_binary_package,
1969            no_sources: value.no_sources,
1970        }
1971    }
1972}
1973
1974/// The options persisted alongside an installed tool.
1975///
1976/// A mirror of [`ResolverInstallerSchema`], without upgrades and reinstalls, which shouldn't be
1977/// persisted in a tool receipt.
1978#[derive(
1979    Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, CombineOptions, OptionsMetadata,
1980)]
1981#[serde(deny_unknown_fields, rename_all = "kebab-case")]
1982#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1983pub struct ToolOptions {
1984    pub index: Option<Vec<Index>>,
1985    pub index_url: Option<PipIndex>,
1986    pub extra_index_url: Option<Vec<PipExtraIndex>>,
1987    pub no_index: Option<bool>,
1988    pub find_links: Option<Vec<PipFindLinks>>,
1989    pub index_strategy: Option<IndexStrategy>,
1990    pub keyring_provider: Option<KeyringProviderType>,
1991    pub resolution: Option<ResolutionMode>,
1992    pub prerelease: Option<PrereleaseMode>,
1993    pub fork_strategy: Option<ForkStrategy>,
1994    pub dependency_metadata: Option<Vec<StaticMetadata>>,
1995    pub config_settings: Option<ConfigSettings>,
1996    pub config_settings_package: Option<PackageConfigSettings>,
1997    pub build_isolation: Option<BuildIsolation>,
1998    pub extra_build_dependencies: Option<ExtraBuildDependencies>,
1999    pub extra_build_variables: Option<ExtraBuildVariables>,
2000    pub exclude_newer: Option<ExcludeNewerValue>,
2001    pub exclude_newer_package: Option<ExcludeNewerPackage>,
2002    pub link_mode: Option<LinkMode>,
2003    pub compile_bytecode: Option<bool>,
2004    pub no_sources: Option<bool>,
2005    pub no_build: Option<bool>,
2006    pub no_build_package: Option<Vec<PackageName>>,
2007    pub no_binary: Option<bool>,
2008    pub no_binary_package: Option<Vec<PackageName>>,
2009    pub torch_backend: Option<TorchMode>,
2010}
2011
2012impl From<ResolverInstallerOptions> for ToolOptions {
2013    fn from(value: ResolverInstallerOptions) -> Self {
2014        Self {
2015            index: value.index,
2016            index_url: value.index_url,
2017            extra_index_url: value.extra_index_url,
2018            no_index: value.no_index,
2019            find_links: value.find_links,
2020            index_strategy: value.index_strategy,
2021            keyring_provider: value.keyring_provider,
2022            resolution: value.resolution,
2023            prerelease: value.prerelease,
2024            fork_strategy: value.fork_strategy,
2025            dependency_metadata: value.dependency_metadata,
2026            config_settings: value.config_settings,
2027            config_settings_package: value.config_settings_package,
2028            build_isolation: value.build_isolation,
2029            extra_build_dependencies: value.extra_build_dependencies,
2030            extra_build_variables: value.extra_build_variables,
2031            exclude_newer: value.exclude_newer,
2032            exclude_newer_package: value.exclude_newer_package,
2033            link_mode: value.link_mode,
2034            compile_bytecode: value.compile_bytecode,
2035            no_sources: value.no_sources,
2036            no_build: value.no_build,
2037            no_build_package: value.no_build_package,
2038            no_binary: value.no_binary,
2039            no_binary_package: value.no_binary_package,
2040            torch_backend: value.torch_backend,
2041        }
2042    }
2043}
2044
2045impl From<ToolOptions> for ResolverInstallerOptions {
2046    fn from(value: ToolOptions) -> Self {
2047        Self {
2048            index: value.index,
2049            index_url: value.index_url,
2050            extra_index_url: value.extra_index_url,
2051            no_index: value.no_index,
2052            find_links: value.find_links,
2053            index_strategy: value.index_strategy,
2054            keyring_provider: value.keyring_provider,
2055            resolution: value.resolution,
2056            prerelease: value.prerelease,
2057            fork_strategy: value.fork_strategy,
2058            dependency_metadata: value.dependency_metadata,
2059            config_settings: value.config_settings,
2060            config_settings_package: value.config_settings_package,
2061            build_isolation: value.build_isolation,
2062            extra_build_dependencies: value.extra_build_dependencies,
2063            extra_build_variables: value.extra_build_variables,
2064            exclude_newer: value.exclude_newer,
2065            exclude_newer_package: value.exclude_newer_package,
2066            link_mode: value.link_mode,
2067            compile_bytecode: value.compile_bytecode,
2068            no_sources: value.no_sources,
2069            upgrade: None,
2070            reinstall: None,
2071            no_build: value.no_build,
2072            no_build_package: value.no_build_package,
2073            no_binary: value.no_binary,
2074            no_binary_package: value.no_binary_package,
2075            torch_backend: value.torch_backend,
2076        }
2077    }
2078}
2079
2080/// Like [`Options]`, but with any `#[serde(flatten)]` fields inlined. This leads to far, far
2081/// better error messages when deserializing.
2082#[derive(Debug, Clone, Default, Deserialize)]
2083#[serde(rename_all = "kebab-case", deny_unknown_fields)]
2084pub struct OptionsWire {
2085    // #[serde(flatten)]
2086    // globals: GlobalOptions
2087    required_version: Option<RequiredVersion>,
2088    native_tls: Option<bool>,
2089    offline: Option<bool>,
2090    no_cache: Option<bool>,
2091    cache_dir: Option<PathBuf>,
2092    preview: Option<bool>,
2093    python_preference: Option<PythonPreference>,
2094    python_downloads: Option<PythonDownloads>,
2095    concurrent_downloads: Option<NonZeroUsize>,
2096    concurrent_builds: Option<NonZeroUsize>,
2097    concurrent_installs: Option<NonZeroUsize>,
2098
2099    // #[serde(flatten)]
2100    // top_level: ResolverInstallerOptions
2101    index: Option<Vec<Index>>,
2102    index_url: Option<PipIndex>,
2103    extra_index_url: Option<Vec<PipExtraIndex>>,
2104    no_index: Option<bool>,
2105    find_links: Option<Vec<PipFindLinks>>,
2106    index_strategy: Option<IndexStrategy>,
2107    keyring_provider: Option<KeyringProviderType>,
2108    allow_insecure_host: Option<Vec<TrustedHost>>,
2109    resolution: Option<ResolutionMode>,
2110    prerelease: Option<PrereleaseMode>,
2111    fork_strategy: Option<ForkStrategy>,
2112    dependency_metadata: Option<Vec<StaticMetadata>>,
2113    config_settings: Option<ConfigSettings>,
2114    config_settings_package: Option<PackageConfigSettings>,
2115    no_build_isolation: Option<bool>,
2116    no_build_isolation_package: Option<Vec<PackageName>>,
2117    extra_build_dependencies: Option<ExtraBuildDependencies>,
2118    extra_build_variables: Option<ExtraBuildVariables>,
2119    exclude_newer: Option<ExcludeNewerValue>,
2120    exclude_newer_package: Option<ExcludeNewerPackage>,
2121    link_mode: Option<LinkMode>,
2122    compile_bytecode: Option<bool>,
2123    no_sources: Option<bool>,
2124    upgrade: Option<bool>,
2125    upgrade_package: Option<Vec<Requirement<VerbatimParsedUrl>>>,
2126    reinstall: Option<bool>,
2127    reinstall_package: Option<Vec<PackageName>>,
2128    no_build: Option<bool>,
2129    no_build_package: Option<Vec<PackageName>>,
2130    no_binary: Option<bool>,
2131    no_binary_package: Option<Vec<PackageName>>,
2132    torch_backend: Option<TorchMode>,
2133
2134    // #[serde(flatten)]
2135    // install_mirror: PythonInstallMirrors,
2136    python_install_mirror: Option<String>,
2137    pypy_install_mirror: Option<String>,
2138    python_downloads_json_url: Option<String>,
2139
2140    // #[serde(flatten)]
2141    // publish: PublishOptions
2142    publish_url: Option<DisplaySafeUrl>,
2143    trusted_publishing: Option<TrustedPublishing>,
2144    check_url: Option<IndexUrl>,
2145
2146    // #[serde(flatten)]
2147    // add: AddOptions
2148    add_bounds: Option<AddBoundsKind>,
2149
2150    pip: Option<PipOptions>,
2151    cache_keys: Option<Vec<CacheKey>>,
2152
2153    // NOTE(charlie): These fields are shared with `ToolUv` in
2154    // `crates/uv-workspace/src/pyproject.rs`. The documentation lives on that struct.
2155    // They're respected in both `pyproject.toml` and `uv.toml` files.
2156    override_dependencies: Option<Vec<Requirement<VerbatimParsedUrl>>>,
2157    exclude_dependencies: Option<Vec<PackageName>>,
2158    constraint_dependencies: Option<Vec<Requirement<VerbatimParsedUrl>>>,
2159    build_constraint_dependencies: Option<Vec<Requirement<VerbatimParsedUrl>>>,
2160    environments: Option<SupportedEnvironments>,
2161    required_environments: Option<SupportedEnvironments>,
2162
2163    // NOTE(charlie): These fields should be kept in-sync with `ToolUv` in
2164    // `crates/uv-workspace/src/pyproject.rs`. The documentation lives on that struct.
2165    // They're only respected in `pyproject.toml` files, and should be rejected in `uv.toml` files.
2166    conflicts: Option<serde::de::IgnoredAny>,
2167    workspace: Option<serde::de::IgnoredAny>,
2168    sources: Option<serde::de::IgnoredAny>,
2169    managed: Option<serde::de::IgnoredAny>,
2170    r#package: Option<serde::de::IgnoredAny>,
2171    default_groups: Option<serde::de::IgnoredAny>,
2172    dependency_groups: Option<serde::de::IgnoredAny>,
2173    dev_dependencies: Option<serde::de::IgnoredAny>,
2174
2175    // Build backend
2176    build_backend: Option<serde::de::IgnoredAny>,
2177}
2178
2179impl From<OptionsWire> for Options {
2180    fn from(value: OptionsWire) -> Self {
2181        let OptionsWire {
2182            required_version,
2183            native_tls,
2184            offline,
2185            no_cache,
2186            cache_dir,
2187            preview,
2188            python_preference,
2189            python_downloads,
2190            python_install_mirror,
2191            pypy_install_mirror,
2192            python_downloads_json_url,
2193            concurrent_downloads,
2194            concurrent_builds,
2195            concurrent_installs,
2196            index,
2197            index_url,
2198            extra_index_url,
2199            no_index,
2200            find_links,
2201            index_strategy,
2202            keyring_provider,
2203            allow_insecure_host,
2204            resolution,
2205            prerelease,
2206            fork_strategy,
2207            dependency_metadata,
2208            config_settings,
2209            config_settings_package,
2210            no_build_isolation,
2211            no_build_isolation_package,
2212            exclude_newer,
2213            exclude_newer_package,
2214            link_mode,
2215            compile_bytecode,
2216            no_sources,
2217            upgrade,
2218            upgrade_package,
2219            reinstall,
2220            reinstall_package,
2221            no_build,
2222            no_build_package,
2223            no_binary,
2224            no_binary_package,
2225            torch_backend,
2226            pip,
2227            cache_keys,
2228            override_dependencies,
2229            exclude_dependencies,
2230            constraint_dependencies,
2231            build_constraint_dependencies,
2232            environments,
2233            required_environments,
2234            conflicts,
2235            publish_url,
2236            trusted_publishing,
2237            check_url,
2238            workspace,
2239            sources,
2240            default_groups,
2241            dependency_groups,
2242            extra_build_dependencies,
2243            extra_build_variables,
2244            dev_dependencies,
2245            managed,
2246            package,
2247            add_bounds: bounds,
2248            // Used by the build backend
2249            build_backend,
2250        } = value;
2251
2252        Self {
2253            globals: GlobalOptions {
2254                required_version,
2255                native_tls,
2256                offline,
2257                no_cache,
2258                cache_dir,
2259                preview,
2260                python_preference,
2261                python_downloads,
2262                concurrent_downloads,
2263                concurrent_builds,
2264                concurrent_installs,
2265                // Used twice for backwards compatibility
2266                allow_insecure_host: allow_insecure_host.clone(),
2267            },
2268            top_level: ResolverInstallerSchema {
2269                index,
2270                index_url,
2271                extra_index_url,
2272                no_index,
2273                find_links,
2274                index_strategy,
2275                keyring_provider,
2276                resolution,
2277                prerelease,
2278                fork_strategy,
2279                dependency_metadata,
2280                config_settings,
2281                config_settings_package,
2282                no_build_isolation,
2283                no_build_isolation_package,
2284                extra_build_dependencies,
2285                extra_build_variables,
2286                exclude_newer,
2287                exclude_newer_package,
2288                link_mode,
2289                compile_bytecode,
2290                no_sources,
2291                upgrade,
2292                upgrade_package,
2293                reinstall,
2294                reinstall_package,
2295                no_build,
2296                no_build_package,
2297                no_binary,
2298                no_binary_package,
2299                torch_backend,
2300            },
2301            pip,
2302            cache_keys,
2303            build_backend,
2304            override_dependencies,
2305            exclude_dependencies,
2306            constraint_dependencies,
2307            build_constraint_dependencies,
2308            environments,
2309            required_environments,
2310            install_mirrors: PythonInstallMirrors {
2311                python_install_mirror,
2312                pypy_install_mirror,
2313                python_downloads_json_url,
2314            },
2315            conflicts,
2316            publish: PublishOptions {
2317                publish_url,
2318                trusted_publishing,
2319                check_url,
2320            },
2321            add: AddOptions { add_bounds: bounds },
2322            workspace,
2323            sources,
2324            dev_dependencies,
2325            default_groups,
2326            dependency_groups,
2327            managed,
2328            package,
2329        }
2330    }
2331}
2332
2333#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, CombineOptions, OptionsMetadata)]
2334#[serde(rename_all = "kebab-case")]
2335#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2336pub struct PublishOptions {
2337    /// The URL for publishing packages to the Python package index (by default:
2338    /// <https://upload.pypi.org/legacy/>).
2339    #[option(
2340        default = "\"https://upload.pypi.org/legacy/\"",
2341        value_type = "str",
2342        example = r#"
2343            publish-url = "https://test.pypi.org/legacy/"
2344        "#
2345    )]
2346    pub publish_url: Option<DisplaySafeUrl>,
2347
2348    /// Configure trusted publishing.
2349    ///
2350    /// By default, uv checks for trusted publishing when running in a supported environment, but
2351    /// ignores it if it isn't configured.
2352    ///
2353    /// uv's supported environments for trusted publishing include GitHub Actions and GitLab CI/CD.
2354    #[option(
2355        default = "automatic",
2356        value_type = "str",
2357        example = r#"
2358            trusted-publishing = "always"
2359        "#
2360    )]
2361    pub trusted_publishing: Option<TrustedPublishing>,
2362
2363    /// Check an index URL for existing files to skip duplicate uploads.
2364    ///
2365    /// This option allows retrying publishing that failed after only some, but not all files have
2366    /// been uploaded, and handles error due to parallel uploads of the same file.
2367    ///
2368    /// Before uploading, the index is checked. If the exact same file already exists in the index,
2369    /// the file will not be uploaded. If an error occurred during the upload, the index is checked
2370    /// again, to handle cases where the identical file was uploaded twice in parallel.
2371    ///
2372    /// The exact behavior will vary based on the index. When uploading to PyPI, uploading the same
2373    /// file succeeds even without `--check-url`, while most other indexes error.
2374    ///
2375    /// The index must provide one of the supported hashes (SHA-256, SHA-384, or SHA-512).
2376    #[option(
2377        default = "None",
2378        value_type = "str",
2379        example = r#"
2380            check-url = "https://test.pypi.org/simple"
2381        "#
2382    )]
2383    pub check_url: Option<IndexUrl>,
2384}
2385
2386#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, CombineOptions, OptionsMetadata)]
2387#[serde(rename_all = "kebab-case")]
2388#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2389pub struct AddOptions {
2390    /// The default version specifier when adding a dependency.
2391    ///
2392    /// When adding a dependency to the project, if no constraint or URL is provided, a constraint
2393    /// is added based on the latest compatible version of the package. By default, a lower bound
2394    /// constraint is used, e.g., `>=1.2.3`.
2395    ///
2396    /// When `--frozen` is provided, no resolution is performed, and dependencies are always added
2397    /// without constraints.
2398    ///
2399    /// This option is in preview and may change in any future release.
2400    #[option(
2401        default = "\"lower\"",
2402        value_type = "str",
2403        example = r#"
2404            add-bounds = "major"
2405        "#,
2406        possible_values = true
2407    )]
2408    pub add_bounds: Option<AddBoundsKind>,
2409}