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