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