Skip to main content

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