Skip to main content

uv_settings/
resolved.rs

1use uv_configuration::{
2    BuildIsolation, BuildOptions, ExcludeNewer, ForkStrategy, IndexStrategy, KeyringProviderType,
3    NoBinary, NoBuild, NoSources, Prerelease, PrereleaseMode, PrereleasePackage, Reinstall,
4    ResolutionMode, Upgrade,
5};
6use uv_distribution_types::{
7    ConfigSettings, DependencyMetadata, ExtraBuildVariables, IndexLocations, PackageConfigSettings,
8};
9use uv_install_wheel::LinkMode;
10use uv_pep440::Version;
11use uv_torch::{AmdGpuArchitecture, TorchMode};
12use uv_warnings::warn_user_once;
13use uv_workspace::pyproject::ExtraBuildDependencies;
14
15use crate::{ResolverInstallerOptions, ResolverOptions};
16
17/// The CLI flag that requested a lock check.
18#[derive(Debug, Clone, Copy)]
19pub enum LockedFlag {
20    Locked,
21    Check,
22}
23
24impl LockedFlag {
25    /// Return the name of the command-line flag without its leading dashes.
26    pub fn name(self) -> &'static str {
27        match self {
28            Self::Locked => "locked",
29            Self::Check => "check",
30        }
31    }
32}
33
34impl std::fmt::Display for LockedFlag {
35    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36        write!(f, "--{}", self.name())
37    }
38}
39
40/// The source of a lock check operation.
41#[derive(Debug, Clone, Copy)]
42pub enum LockedSource {
43    /// A lock check was requested on the CLI.
44    Cli(LockedFlag),
45    /// The `UV_LOCKED` environment variable was set.
46    Env,
47}
48
49impl std::fmt::Display for LockedSource {
50    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51        match self {
52            Self::Cli(flag) => flag.fmt(f),
53            Self::Env => write!(f, "UV_LOCKED=1"),
54        }
55    }
56}
57
58/// Whether a lockfile check was requested, including the source of the request.
59#[derive(Debug, Clone, Copy)]
60pub enum LockCheck {
61    /// Lockfile check is enabled.
62    Enabled(LockedSource),
63    /// Lockfile check is disabled.
64    Disabled,
65}
66
67/// The CLI flag that requested frozen mode.
68#[derive(Debug, Clone, Copy)]
69pub enum FrozenFlag {
70    Frozen,
71    CheckExists,
72}
73
74impl FrozenFlag {
75    /// Return the name of the command-line flag without its leading dashes.
76    pub fn name(self) -> &'static str {
77        match self {
78            Self::Frozen => "frozen",
79            Self::CheckExists => "check-exists",
80        }
81    }
82}
83
84impl std::fmt::Display for FrozenFlag {
85    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86        write!(f, "--{}", self.name())
87    }
88}
89
90/// The source of the frozen flag.
91#[derive(Debug, Clone, Copy)]
92pub enum FrozenSource {
93    /// Frozen mode was requested on the CLI.
94    Cli(FrozenFlag),
95    /// The `UV_FROZEN` environment variable was set.
96    Env,
97}
98
99impl std::fmt::Display for FrozenSource {
100    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101        match self {
102            Self::Cli(flag) => flag.fmt(f),
103            Self::Env => write!(f, "UV_FROZEN=1"),
104        }
105    }
106}
107
108/// The kinds of Python installations and downloads to list.
109#[derive(Debug, Clone, Default)]
110pub enum PythonListKinds {
111    /// List installed versions and available downloads.
112    #[default]
113    Default,
114    /// Only list version downloads.
115    Downloads,
116    /// Only list installed versions.
117    Installed,
118}
119
120/// The resolved settings to use for an invocation of the uv CLI when installing dependencies.
121///
122/// Borrows the resolved installer options shared by commands.
123#[derive(Debug, Clone)]
124pub struct InstallerSettingsRef<'a> {
125    pub index_locations: &'a IndexLocations,
126    pub index_strategy: IndexStrategy,
127    pub keyring_provider: KeyringProviderType,
128    pub dependency_metadata: &'a DependencyMetadata,
129    pub config_setting: &'a ConfigSettings,
130    pub config_settings_package: &'a PackageConfigSettings,
131    pub build_isolation: &'a BuildIsolation,
132    pub extra_build_dependencies: &'a ExtraBuildDependencies,
133    pub extra_build_variables: &'a ExtraBuildVariables,
134    pub exclude_newer: &'a ExcludeNewer,
135    pub link_mode: LinkMode,
136    pub compile_bytecode: bool,
137    pub reinstall: &'a Reinstall,
138    pub build_options: &'a BuildOptions,
139    pub sources: NoSources,
140}
141
142/// The resolved settings to use for an invocation of the uv CLI when resolving dependencies.
143///
144/// Constructed from the combined [`ResolverOptions`] for an invocation.
145#[derive(Debug, Clone, Default)]
146pub struct ResolverSettings {
147    pub build_options: BuildOptions,
148    pub config_setting: ConfigSettings,
149    pub config_settings_package: PackageConfigSettings,
150    pub dependency_metadata: DependencyMetadata,
151    pub exclude_newer: ExcludeNewer,
152    pub fork_strategy: ForkStrategy,
153    pub index_locations: IndexLocations,
154    pub index_strategy: IndexStrategy,
155    pub keyring_provider: KeyringProviderType,
156    pub link_mode: LinkMode,
157    pub build_isolation: BuildIsolation,
158    pub extra_build_dependencies: ExtraBuildDependencies,
159    pub extra_build_variables: ExtraBuildVariables,
160    pub prerelease: Prerelease,
161    pub resolution: ResolutionMode,
162    pub sources: NoSources,
163    pub torch_backend: Option<TorchMode>,
164    pub cuda_driver_version: Option<Version>,
165    pub amd_gpu_architecture: Option<AmdGpuArchitecture>,
166    pub upgrade: Upgrade,
167}
168
169/// Normalize a deprecated prerelease mode and emit its warning.
170#[expect(deprecated)]
171fn warn_if_deprecated_prerelease_mode(prerelease: PrereleaseMode) -> PrereleaseMode {
172    if matches!(prerelease, PrereleaseMode::IfNecessaryOrExplicit) {
173        warn_user_once!(
174            "The `if-necessary-or-explicit` pre-release mode is deprecated and will be removed in a future release. Use `if-necessary` instead."
175        );
176        PrereleaseMode::IfNecessary
177    } else {
178        prerelease
179    }
180}
181
182/// Normalize the global and per-package prerelease modes, warning about deprecated values.
183pub fn resolve_prerelease(global: PrereleaseMode, mut package: PrereleasePackage) -> Prerelease {
184    for mode in package.values_mut() {
185        *mode = warn_if_deprecated_prerelease_mode(*mode);
186    }
187
188    Prerelease {
189        global: warn_if_deprecated_prerelease_mode(global),
190        package,
191    }
192}
193
194impl From<ResolverOptions> for ResolverSettings {
195    fn from(value: ResolverOptions) -> Self {
196        Self {
197            index_locations: value.indexes.into(),
198            resolution: value.resolution.unwrap_or_default(),
199            prerelease: resolve_prerelease(
200                value.prerelease.unwrap_or_default(),
201                value.prerelease_package.unwrap_or_default(),
202            ),
203            fork_strategy: value.fork_strategy.unwrap_or_default(),
204            dependency_metadata: DependencyMetadata::from_entries(
205                value.dependency_metadata.into_iter().flatten(),
206            ),
207            index_strategy: value.index_strategy.unwrap_or_default(),
208            keyring_provider: value.keyring_provider.unwrap_or_default(),
209            config_setting: value.config_settings.unwrap_or_default(),
210            config_settings_package: value.config_settings_package.unwrap_or_default(),
211            build_isolation: value.build_isolation.unwrap_or_default(),
212            extra_build_dependencies: value.extra_build_dependencies.unwrap_or_default(),
213            extra_build_variables: value.extra_build_variables.unwrap_or_default(),
214            exclude_newer: ExcludeNewer::from_args(
215                value.exclude_newer,
216                value
217                    .exclude_newer_package
218                    .unwrap_or_default()
219                    .into_iter()
220                    .map(Into::into)
221                    .collect(),
222            ),
223            link_mode: value.link_mode.unwrap_or_default(),
224            torch_backend: value.torch_backend,
225            cuda_driver_version: None,
226            amd_gpu_architecture: None,
227            sources: NoSources::from_args(
228                value.no_sources,
229                value.no_sources_package.unwrap_or_default(),
230            ),
231            upgrade: value.upgrade.unwrap_or_default(),
232            build_options: BuildOptions::new(
233                NoBinary::from_args(value.no_binary, value.no_binary_package.unwrap_or_default()),
234                NoBuild::from_args(value.no_build, value.no_build_package.unwrap_or_default()),
235            ),
236        }
237    }
238}
239
240/// The resolved settings to use for an invocation of the uv CLI with both resolver and installer
241/// capabilities.
242///
243/// Represents the shared settings that are used across all uv commands outside the `pip` API.
244/// Constructed from the combined [`ResolverInstallerOptions`] for an invocation.
245#[derive(Debug, Clone, Default)]
246pub struct ResolverInstallerSettings {
247    pub resolver: ResolverSettings,
248    pub compile_bytecode: bool,
249    pub reinstall: Reinstall,
250}
251
252impl From<ResolverInstallerOptions> for ResolverInstallerSettings {
253    fn from(value: ResolverInstallerOptions) -> Self {
254        let index_locations = value.indexes.into();
255        Self {
256            resolver: ResolverSettings {
257                build_options: BuildOptions::new(
258                    NoBinary::from_args(
259                        value.no_binary,
260                        value.no_binary_package.unwrap_or_default(),
261                    ),
262                    NoBuild::from_args(value.no_build, value.no_build_package.unwrap_or_default()),
263                ),
264                config_setting: value.config_settings.unwrap_or_default(),
265                config_settings_package: value.config_settings_package.unwrap_or_default(),
266                dependency_metadata: DependencyMetadata::from_entries(
267                    value.dependency_metadata.into_iter().flatten(),
268                ),
269                exclude_newer: ExcludeNewer::from_args(
270                    value.exclude_newer,
271                    value
272                        .exclude_newer_package
273                        .unwrap_or_default()
274                        .into_iter()
275                        .map(Into::into)
276                        .collect(),
277                ),
278                fork_strategy: value.fork_strategy.unwrap_or_default(),
279                index_locations,
280                index_strategy: value.index_strategy.unwrap_or_default(),
281                keyring_provider: value.keyring_provider.unwrap_or_default(),
282                link_mode: value.link_mode.unwrap_or_default(),
283                build_isolation: value.build_isolation.unwrap_or_default(),
284                extra_build_dependencies: value.extra_build_dependencies.unwrap_or_default(),
285                extra_build_variables: value.extra_build_variables.unwrap_or_default(),
286                prerelease: resolve_prerelease(
287                    value.prerelease.unwrap_or_default(),
288                    value.prerelease_package.unwrap_or_default(),
289                ),
290                resolution: value.resolution.unwrap_or_default(),
291                sources: NoSources::from_args(
292                    value.no_sources,
293                    value.no_sources_package.unwrap_or_default(),
294                ),
295                torch_backend: value.torch_backend,
296                cuda_driver_version: None,
297                amd_gpu_architecture: None,
298                upgrade: value.upgrade.unwrap_or_default(),
299            },
300            compile_bytecode: value.compile_bytecode.unwrap_or_default(),
301            reinstall: value.reinstall.unwrap_or_default(),
302        }
303    }
304}
305
306impl<'a> From<&'a ResolverInstallerSettings> for InstallerSettingsRef<'a> {
307    fn from(settings: &'a ResolverInstallerSettings) -> Self {
308        Self {
309            index_locations: &settings.resolver.index_locations,
310            index_strategy: settings.resolver.index_strategy,
311            keyring_provider: settings.resolver.keyring_provider,
312            dependency_metadata: &settings.resolver.dependency_metadata,
313            config_setting: &settings.resolver.config_setting,
314            config_settings_package: &settings.resolver.config_settings_package,
315            build_isolation: &settings.resolver.build_isolation,
316            extra_build_dependencies: &settings.resolver.extra_build_dependencies,
317            extra_build_variables: &settings.resolver.extra_build_variables,
318            exclude_newer: &settings.resolver.exclude_newer,
319            link_mode: settings.resolver.link_mode,
320            compile_bytecode: settings.compile_bytecode,
321            reinstall: &settings.reinstall,
322            build_options: &settings.resolver.build_options,
323            sources: settings.resolver.sources.clone(),
324        }
325    }
326}