Skip to main content

uv_settings/
resolved.rs

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