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