Split preview mode into separate feature flags (#14823)

I think this would give us better hygiene than a global flag. It makes
it easier for users to opt-in to overlapping features, such as Python
upgrades and Python bin installations and to disable warnings for
preview mode without opting in to a bunch of other features. In general,
I want to reduce the burden for putting something under preview.

The `--preview` and `--no-preview` flags are retained as global
overrides. A new `--preview-features` option is added which accepts
comma separated features or can be passed multiple times, e.g.,
`--preview-features add-bounds,pylock`. There's a `UV_PREVIEW_FEATURES`
environment variable for that option (I'm not sure if we should overload
`UV_PREVIEW`, but could be convinced).
This commit is contained in:
Zanie Blue 2025-07-25 11:01:57 -05:00 committed by GitHub
parent 9376cf5482
commit bfb4bc2aeb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
55 changed files with 1327 additions and 304 deletions

2
Cargo.lock generated
View file

@ -5037,6 +5037,7 @@ name = "uv-configuration"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bitflags 2.9.1",
"clap", "clap",
"either", "either",
"fs-err 3.1.1", "fs-err 3.1.1",
@ -5061,6 +5062,7 @@ dependencies = [
"uv-pep508", "uv-pep508",
"uv-platform-tags", "uv-platform-tags",
"uv-static", "uv-static",
"uv-warnings",
] ]
[[package]] [[package]]

View file

@ -87,7 +87,7 @@ mod resolver {
use uv_client::RegistryClient; use uv_client::RegistryClient;
use uv_configuration::{ use uv_configuration::{
BuildOptions, Concurrency, ConfigSettings, Constraints, IndexStrategy, BuildOptions, Concurrency, ConfigSettings, Constraints, IndexStrategy,
PackageConfigSettings, PreviewMode, SourceStrategy, PackageConfigSettings, Preview, SourceStrategy,
}; };
use uv_dispatch::{BuildDispatch, SharedState}; use uv_dispatch::{BuildDispatch, SharedState};
use uv_distribution::DistributionDatabase; use uv_distribution::DistributionDatabase;
@ -194,7 +194,7 @@ mod resolver {
sources, sources,
workspace_cache, workspace_cache,
concurrency, concurrency,
PreviewMode::Enabled, Preview::default(),
); );
let markers = if universal { let markers = if universal {

View file

@ -28,7 +28,7 @@ use tokio::sync::{Mutex, Semaphore};
use tracing::{Instrument, debug, info_span, instrument, warn}; use tracing::{Instrument, debug, info_span, instrument, warn};
use uv_cache_key::cache_digest; use uv_cache_key::cache_digest;
use uv_configuration::PreviewMode; use uv_configuration::Preview;
use uv_configuration::{BuildKind, BuildOutput, ConfigSettings, SourceStrategy}; use uv_configuration::{BuildKind, BuildOutput, ConfigSettings, SourceStrategy};
use uv_distribution::BuildRequires; use uv_distribution::BuildRequires;
use uv_distribution_types::{IndexLocations, Requirement, Resolution}; use uv_distribution_types::{IndexLocations, Requirement, Resolution};
@ -286,7 +286,7 @@ impl SourceBuild {
mut environment_variables: FxHashMap<OsString, OsString>, mut environment_variables: FxHashMap<OsString, OsString>,
level: BuildOutput, level: BuildOutput,
concurrent_builds: usize, concurrent_builds: usize,
preview: PreviewMode, preview: Preview,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let temp_dir = build_context.cache().venv_dir()?; let temp_dir = build_context.cache().venv_dir()?;

View file

@ -11,8 +11,8 @@ use clap::{Args, Parser, Subcommand};
use uv_cache::CacheArgs; use uv_cache::CacheArgs;
use uv_configuration::{ use uv_configuration::{
ConfigSettingEntry, ConfigSettingPackageEntry, ExportFormat, IndexStrategy, ConfigSettingEntry, ConfigSettingPackageEntry, ExportFormat, IndexStrategy,
KeyringProviderType, PackageNameSpecifier, ProjectBuildBackend, TargetTriple, TrustedHost, KeyringProviderType, PackageNameSpecifier, PreviewFeatures, ProjectBuildBackend, TargetTriple,
TrustedPublishing, VersionControlSystem, TrustedHost, TrustedPublishing, VersionControlSystem,
}; };
use uv_distribution_types::{Index, IndexUrl, Origin, PipExtraIndex, PipFindLinks, PipIndex}; use uv_distribution_types::{Index, IndexUrl, Origin, PipExtraIndex, PipFindLinks, PipIndex};
use uv_normalize::{ExtraName, GroupName, PackageName, PipGroupName}; use uv_normalize::{ExtraName, GroupName, PackageName, PipGroupName};
@ -273,7 +273,7 @@ pub struct GlobalArgs {
)] )]
pub allow_insecure_host: Option<Vec<Maybe<TrustedHost>>>, pub allow_insecure_host: Option<Vec<Maybe<TrustedHost>>>,
/// Whether to enable experimental, preview features. /// Whether to enable all experimental preview features.
/// ///
/// Preview features may change without warning. /// Preview features may change without warning.
#[arg(global = true, long, hide = true, env = EnvVars::UV_PREVIEW, value_parser = clap::builder::BoolishValueParser::new(), overrides_with("no_preview"))] #[arg(global = true, long, hide = true, env = EnvVars::UV_PREVIEW, value_parser = clap::builder::BoolishValueParser::new(), overrides_with("no_preview"))]
@ -282,6 +282,25 @@ pub struct GlobalArgs {
#[arg(global = true, long, overrides_with("preview"), hide = true)] #[arg(global = true, long, overrides_with("preview"), hide = true)]
pub no_preview: bool, pub no_preview: bool,
/// Enable experimental preview features.
///
/// Preview features may change without warning.
///
/// Use comma-separated values or pass multiple times to enable multiple features.
///
/// The following features are available: `python-install-default`, `python-upgrade`,
/// `json-output`, `pylock`, `add-bounds`.
#[arg(
global = true,
long = "preview-features",
env = EnvVars::UV_PREVIEW_FEATURES,
value_delimiter = ',',
hide = true,
alias = "preview-feature",
value_enum,
)]
pub preview_features: Vec<PreviewFeatures>,
/// Avoid discovering a `pyproject.toml` or `uv.toml` file. /// Avoid discovering a `pyproject.toml` or `uv.toml` file.
/// ///
/// Normally, configuration files are discovered in the current directory, /// Normally, configuration files are discovered in the current directory,

View file

@ -27,7 +27,9 @@ uv-pep440 = { workspace = true }
uv-pep508 = { workspace = true, features = ["schemars"] } uv-pep508 = { workspace = true, features = ["schemars"] }
uv-platform-tags = { workspace = true } uv-platform-tags = { workspace = true }
uv-static = { workspace = true } uv-static = { workspace = true }
uv-warnings = { workspace = true }
bitflags = { workspace = true }
clap = { workspace = true, features = ["derive"], optional = true } clap = { workspace = true, features = ["derive"], optional = true }
either = { workspace = true } either = { workspace = true }
fs-err = { workspace = true } fs-err = { workspace = true }

View file

@ -1,37 +1,243 @@
use std::fmt::{Display, Formatter}; use std::{
fmt::{Display, Formatter},
str::FromStr,
};
use thiserror::Error;
use uv_warnings::warn_user_once;
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct PreviewFeatures: u32 {
const PYTHON_INSTALL_DEFAULT = 1 << 0;
const PYTHON_UPGRADE = 1 << 1;
const JSON_OUTPUT = 1 << 2;
const PYLOCK = 1 << 3;
const ADD_BOUNDS = 1 << 4;
}
}
impl PreviewFeatures {
/// Returns the string representation of a single preview feature flag.
///
/// Panics if given a combination of flags.
fn flag_as_str(self) -> &'static str {
match self {
Self::PYTHON_INSTALL_DEFAULT => "python-install-default",
Self::PYTHON_UPGRADE => "python-upgrade",
Self::JSON_OUTPUT => "json-output",
Self::PYLOCK => "pylock",
Self::ADD_BOUNDS => "add-bounds",
_ => panic!("`flag_as_str` can only be used for exactly one feature flag"),
}
}
}
impl Display for PreviewFeatures {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if self.is_empty() {
write!(f, "none")
} else {
let features: Vec<&str> = self.iter().map(PreviewFeatures::flag_as_str).collect();
write!(f, "{}", features.join(","))
}
}
}
#[derive(Debug, Error, Clone)]
pub enum PreviewFeaturesParseError {
#[error("Empty string in preview features: {0}")]
Empty(String),
}
impl FromStr for PreviewFeatures {
type Err = PreviewFeaturesParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut flags = PreviewFeatures::empty();
for part in s.split(',') {
let part = part.trim();
if part.is_empty() {
return Err(PreviewFeaturesParseError::Empty(
"Empty string in preview features".to_string(),
));
}
let flag = match part {
"python-install-default" => Self::PYTHON_INSTALL_DEFAULT,
"python-upgrade" => Self::PYTHON_UPGRADE,
"json-output" => Self::JSON_OUTPUT,
"pylock" => Self::PYLOCK,
"add-bounds" => Self::ADD_BOUNDS,
_ => {
warn_user_once!("Unknown preview feature: `{part}`");
continue;
}
};
flags |= flag;
}
Ok(flags)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum PreviewMode { pub struct Preview {
#[default] flags: PreviewFeatures,
Disabled,
Enabled,
} }
impl PreviewMode { impl Preview {
pub fn is_enabled(&self) -> bool { pub fn new(flags: PreviewFeatures) -> Self {
matches!(self, Self::Enabled) Self { flags }
} }
pub fn is_disabled(&self) -> bool { pub fn all() -> Self {
matches!(self, Self::Disabled) Self::new(PreviewFeatures::all())
} }
}
impl From<bool> for PreviewMode { pub fn from_args(
fn from(version: bool) -> Self { preview: bool,
if version { no_preview: bool,
PreviewMode::Enabled preview_features: &[PreviewFeatures],
} else { ) -> Self {
PreviewMode::Disabled if no_preview {
return Self::default();
} }
if preview {
return Self::all();
}
let mut flags = PreviewFeatures::empty();
for features in preview_features {
flags |= *features;
}
Self { flags }
}
pub fn is_enabled(&self, flag: PreviewFeatures) -> bool {
self.flags.contains(flag)
} }
} }
impl Display for PreviewMode { impl Display for Preview {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self { if self.flags.is_empty() {
Self::Disabled => write!(f, "disabled"), write!(f, "disabled")
Self::Enabled => write!(f, "enabled"), } else if self.flags == PreviewFeatures::all() {
write!(f, "enabled")
} else {
write!(f, "{}", self.flags)
} }
} }
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_preview_features_from_str() {
// Test single feature
let features = PreviewFeatures::from_str("python-install-default").unwrap();
assert_eq!(features, PreviewFeatures::PYTHON_INSTALL_DEFAULT);
// Test multiple features
let features = PreviewFeatures::from_str("python-upgrade,json-output").unwrap();
assert!(features.contains(PreviewFeatures::PYTHON_UPGRADE));
assert!(features.contains(PreviewFeatures::JSON_OUTPUT));
assert!(!features.contains(PreviewFeatures::PYLOCK));
// Test with whitespace
let features = PreviewFeatures::from_str("pylock , add-bounds").unwrap();
assert!(features.contains(PreviewFeatures::PYLOCK));
assert!(features.contains(PreviewFeatures::ADD_BOUNDS));
// Test empty string error
assert!(PreviewFeatures::from_str("").is_err());
assert!(PreviewFeatures::from_str("pylock,").is_err());
assert!(PreviewFeatures::from_str(",pylock").is_err());
// Test unknown feature (should be ignored with warning)
let features = PreviewFeatures::from_str("unknown-feature,pylock").unwrap();
assert!(features.contains(PreviewFeatures::PYLOCK));
assert_eq!(features.bits().count_ones(), 1);
}
#[test]
fn test_preview_features_display() {
// Test empty
let features = PreviewFeatures::empty();
assert_eq!(features.to_string(), "none");
// Test single feature
let features = PreviewFeatures::PYTHON_INSTALL_DEFAULT;
assert_eq!(features.to_string(), "python-install-default");
// Test multiple features
let features = PreviewFeatures::PYTHON_UPGRADE | PreviewFeatures::JSON_OUTPUT;
assert_eq!(features.to_string(), "python-upgrade,json-output");
}
#[test]
fn test_preview_display() {
// Test disabled
let preview = Preview::default();
assert_eq!(preview.to_string(), "disabled");
// Test enabled (all features)
let preview = Preview::all();
assert_eq!(preview.to_string(), "enabled");
// Test specific features
let preview = Preview::new(PreviewFeatures::PYTHON_UPGRADE | PreviewFeatures::PYLOCK);
assert_eq!(preview.to_string(), "python-upgrade,pylock");
}
#[test]
fn test_preview_from_args() {
// Test no_preview
let preview = Preview::from_args(true, true, &[]);
assert_eq!(preview.to_string(), "disabled");
// Test preview (all features)
let preview = Preview::from_args(true, false, &[]);
assert_eq!(preview.to_string(), "enabled");
// Test specific features
let features = vec![
PreviewFeatures::PYTHON_UPGRADE,
PreviewFeatures::JSON_OUTPUT,
];
let preview = Preview::from_args(false, false, &features);
assert!(preview.is_enabled(PreviewFeatures::PYTHON_UPGRADE));
assert!(preview.is_enabled(PreviewFeatures::JSON_OUTPUT));
assert!(!preview.is_enabled(PreviewFeatures::PYLOCK));
}
#[test]
fn test_as_str_single_flags() {
assert_eq!(
PreviewFeatures::PYTHON_INSTALL_DEFAULT.flag_as_str(),
"python-install-default"
);
assert_eq!(
PreviewFeatures::PYTHON_UPGRADE.flag_as_str(),
"python-upgrade"
);
assert_eq!(PreviewFeatures::JSON_OUTPUT.flag_as_str(), "json-output");
assert_eq!(PreviewFeatures::PYLOCK.flag_as_str(), "pylock");
assert_eq!(PreviewFeatures::ADD_BOUNDS.flag_as_str(), "add-bounds");
}
#[test]
#[should_panic(expected = "`flag_as_str` can only be used for exactly one feature flag")]
fn test_as_str_multiple_flags_panics() {
let features = PreviewFeatures::PYTHON_UPGRADE | PreviewFeatures::JSON_OUTPUT;
let _ = features.flag_as_str();
}
}

View file

@ -4,7 +4,7 @@ use clap::Parser;
use tracing::info; use tracing::info;
use uv_cache::{Cache, CacheArgs}; use uv_cache::{Cache, CacheArgs};
use uv_configuration::{Concurrency, PreviewMode}; use uv_configuration::{Concurrency, Preview};
use uv_python::{EnvironmentPreference, PythonEnvironment, PythonRequest}; use uv_python::{EnvironmentPreference, PythonEnvironment, PythonRequest};
#[derive(Parser)] #[derive(Parser)]
@ -26,7 +26,7 @@ pub(crate) async fn compile(args: CompileArgs) -> anyhow::Result<()> {
&PythonRequest::default(), &PythonRequest::default(),
EnvironmentPreference::OnlyVirtual, EnvironmentPreference::OnlyVirtual,
&cache, &cache,
PreviewMode::Disabled, Preview::default(),
)? )?
.into_interpreter(); .into_interpreter();
interpreter.sys_executable().to_path_buf() interpreter.sys_executable().to_path_buf()

View file

@ -18,7 +18,7 @@ use uv_cache::Cache;
use uv_client::RegistryClient; use uv_client::RegistryClient;
use uv_configuration::{ use uv_configuration::{
BuildKind, BuildOptions, ConfigSettings, Constraints, IndexStrategy, PackageConfigSettings, BuildKind, BuildOptions, ConfigSettings, Constraints, IndexStrategy, PackageConfigSettings,
PreviewMode, Reinstall, SourceStrategy, Preview, Reinstall, SourceStrategy,
}; };
use uv_configuration::{BuildOutput, Concurrency}; use uv_configuration::{BuildOutput, Concurrency};
use uv_distribution::DistributionDatabase; use uv_distribution::DistributionDatabase;
@ -99,7 +99,7 @@ pub struct BuildDispatch<'a> {
sources: SourceStrategy, sources: SourceStrategy,
workspace_cache: WorkspaceCache, workspace_cache: WorkspaceCache,
concurrency: Concurrency, concurrency: Concurrency,
preview: PreviewMode, preview: Preview,
} }
impl<'a> BuildDispatch<'a> { impl<'a> BuildDispatch<'a> {
@ -123,7 +123,7 @@ impl<'a> BuildDispatch<'a> {
sources: SourceStrategy, sources: SourceStrategy,
workspace_cache: WorkspaceCache, workspace_cache: WorkspaceCache,
concurrency: Concurrency, concurrency: Concurrency,
preview: PreviewMode, preview: Preview,
) -> Self { ) -> Self {
Self { Self {
client, client,

View file

@ -8,7 +8,7 @@ use std::{env, io, iter};
use std::{path::Path, path::PathBuf, str::FromStr}; use std::{path::Path, path::PathBuf, str::FromStr};
use thiserror::Error; use thiserror::Error;
use tracing::{debug, instrument, trace}; use tracing::{debug, instrument, trace};
use uv_configuration::PreviewMode; use uv_configuration::Preview;
use which::{which, which_all}; use which::{which, which_all};
use uv_cache::Cache; use uv_cache::Cache;
@ -335,7 +335,7 @@ fn python_executables_from_installed<'a>(
implementation: Option<&'a ImplementationName>, implementation: Option<&'a ImplementationName>,
platform: PlatformRequest, platform: PlatformRequest,
preference: PythonPreference, preference: PythonPreference,
preview: PreviewMode, preview: Preview,
) -> Box<dyn Iterator<Item = Result<(PythonSource, PathBuf), Error>> + 'a> { ) -> Box<dyn Iterator<Item = Result<(PythonSource, PathBuf), Error>> + 'a> {
let from_managed_installations = iter::once_with(move || { let from_managed_installations = iter::once_with(move || {
ManagedPythonInstallations::from_settings(None) ManagedPythonInstallations::from_settings(None)
@ -485,7 +485,7 @@ fn python_executables<'a>(
platform: PlatformRequest, platform: PlatformRequest,
environments: EnvironmentPreference, environments: EnvironmentPreference,
preference: PythonPreference, preference: PythonPreference,
preview: PreviewMode, preview: Preview,
) -> Box<dyn Iterator<Item = Result<(PythonSource, PathBuf), Error>> + 'a> { ) -> Box<dyn Iterator<Item = Result<(PythonSource, PathBuf), Error>> + 'a> {
// Always read from `UV_INTERNAL__PARENT_INTERPRETER` — it could be a system interpreter // Always read from `UV_INTERNAL__PARENT_INTERPRETER` — it could be a system interpreter
let from_parent_interpreter = iter::once_with(|| { let from_parent_interpreter = iter::once_with(|| {
@ -705,7 +705,7 @@ fn python_interpreters<'a>(
environments: EnvironmentPreference, environments: EnvironmentPreference,
preference: PythonPreference, preference: PythonPreference,
cache: &'a Cache, cache: &'a Cache,
preview: PreviewMode, preview: Preview,
) -> impl Iterator<Item = Result<(PythonSource, Interpreter), Error>> + 'a { ) -> impl Iterator<Item = Result<(PythonSource, Interpreter), Error>> + 'a {
python_interpreters_from_executables( python_interpreters_from_executables(
// Perform filtering on the discovered executables based on their source. This avoids // Perform filtering on the discovered executables based on their source. This avoids
@ -1053,7 +1053,7 @@ pub fn find_python_installations<'a>(
environments: EnvironmentPreference, environments: EnvironmentPreference,
preference: PythonPreference, preference: PythonPreference,
cache: &'a Cache, cache: &'a Cache,
preview: PreviewMode, preview: Preview,
) -> Box<dyn Iterator<Item = Result<FindPythonResult, Error>> + 'a> { ) -> Box<dyn Iterator<Item = Result<FindPythonResult, Error>> + 'a> {
let sources = DiscoveryPreferences { let sources = DiscoveryPreferences {
python_preference: preference, python_preference: preference,
@ -1254,7 +1254,7 @@ pub(crate) fn find_python_installation(
environments: EnvironmentPreference, environments: EnvironmentPreference,
preference: PythonPreference, preference: PythonPreference,
cache: &Cache, cache: &Cache,
preview: PreviewMode, preview: Preview,
) -> Result<FindPythonResult, Error> { ) -> Result<FindPythonResult, Error> {
let installations = let installations =
find_python_installations(request, environments, preference, cache, preview); find_python_installations(request, environments, preference, cache, preview);
@ -1353,7 +1353,7 @@ pub(crate) fn find_best_python_installation(
environments: EnvironmentPreference, environments: EnvironmentPreference,
preference: PythonPreference, preference: PythonPreference,
cache: &Cache, cache: &Cache,
preview: PreviewMode, preview: Preview,
) -> Result<FindPythonResult, Error> { ) -> Result<FindPythonResult, Error> {
debug!("Starting Python discovery for {}", request); debug!("Starting Python discovery for {}", request);

View file

@ -7,7 +7,7 @@ use owo_colors::OwoColorize;
use tracing::debug; use tracing::debug;
use uv_cache::Cache; use uv_cache::Cache;
use uv_configuration::PreviewMode; use uv_configuration::Preview;
use uv_fs::{LockedFile, Simplified}; use uv_fs::{LockedFile, Simplified};
use uv_pep440::Version; use uv_pep440::Version;
@ -153,7 +153,7 @@ impl PythonEnvironment {
request: &PythonRequest, request: &PythonRequest,
preference: EnvironmentPreference, preference: EnvironmentPreference,
cache: &Cache, cache: &Cache,
preview: PreviewMode, preview: Preview,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let installation = match find_python_installation( let installation = match find_python_installation(
request, request,

View file

@ -8,7 +8,7 @@ use tracing::{debug, info};
use uv_cache::Cache; use uv_cache::Cache;
use uv_client::BaseClientBuilder; use uv_client::BaseClientBuilder;
use uv_configuration::PreviewMode; use uv_configuration::Preview;
use uv_pep440::{Prerelease, Version}; use uv_pep440::{Prerelease, Version};
use crate::discovery::{ use crate::discovery::{
@ -58,7 +58,7 @@ impl PythonInstallation {
environments: EnvironmentPreference, environments: EnvironmentPreference,
preference: PythonPreference, preference: PythonPreference,
cache: &Cache, cache: &Cache,
preview: PreviewMode, preview: Preview,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let installation = let installation =
find_python_installation(request, environments, preference, cache, preview)??; find_python_installation(request, environments, preference, cache, preview)??;
@ -72,7 +72,7 @@ impl PythonInstallation {
environments: EnvironmentPreference, environments: EnvironmentPreference,
preference: PythonPreference, preference: PythonPreference,
cache: &Cache, cache: &Cache,
preview: PreviewMode, preview: Preview,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
Ok(find_best_python_installation( Ok(find_best_python_installation(
request, request,
@ -97,7 +97,7 @@ impl PythonInstallation {
python_install_mirror: Option<&str>, python_install_mirror: Option<&str>,
pypy_install_mirror: Option<&str>, pypy_install_mirror: Option<&str>,
python_downloads_json_url: Option<&str>, python_downloads_json_url: Option<&str>,
preview: PreviewMode, preview: Preview,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let request = request.unwrap_or(&PythonRequest::Default); let request = request.unwrap_or(&PythonRequest::Default);
@ -220,7 +220,7 @@ impl PythonInstallation {
reporter: Option<&dyn Reporter>, reporter: Option<&dyn Reporter>,
python_install_mirror: Option<&str>, python_install_mirror: Option<&str>,
pypy_install_mirror: Option<&str>, pypy_install_mirror: Option<&str>,
preview: PreviewMode, preview: Preview,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let installations = ManagedPythonInstallations::from_settings(None)?.init()?; let installations = ManagedPythonInstallations::from_settings(None)?.init()?;
let installations_dir = installations.root(); let installations_dir = installations.root();

View file

@ -135,7 +135,7 @@ mod tests {
use indoc::{formatdoc, indoc}; use indoc::{formatdoc, indoc};
use temp_env::with_vars; use temp_env::with_vars;
use test_log::test; use test_log::test;
use uv_configuration::PreviewMode; use uv_configuration::Preview;
use uv_static::EnvVars; use uv_static::EnvVars;
use uv_cache::Cache; use uv_cache::Cache;
@ -468,7 +468,7 @@ mod tests {
EnvironmentPreference::OnlySystem, EnvironmentPreference::OnlySystem,
PythonPreference::default(), PythonPreference::default(),
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}); });
assert!( assert!(
@ -483,7 +483,7 @@ mod tests {
EnvironmentPreference::OnlySystem, EnvironmentPreference::OnlySystem,
PythonPreference::default(), PythonPreference::default(),
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}); });
assert!( assert!(
@ -508,7 +508,7 @@ mod tests {
EnvironmentPreference::OnlySystem, EnvironmentPreference::OnlySystem,
PythonPreference::default(), PythonPreference::default(),
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}); });
assert!( assert!(
@ -530,7 +530,7 @@ mod tests {
EnvironmentPreference::OnlySystem, EnvironmentPreference::OnlySystem,
PythonPreference::default(), PythonPreference::default(),
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert!( assert!(
@ -592,7 +592,7 @@ mod tests {
EnvironmentPreference::OnlySystem, EnvironmentPreference::OnlySystem,
PythonPreference::default(), PythonPreference::default(),
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert!( assert!(
@ -624,7 +624,7 @@ mod tests {
EnvironmentPreference::OnlySystem, EnvironmentPreference::OnlySystem,
PythonPreference::default(), PythonPreference::default(),
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}); });
assert!( assert!(
@ -661,7 +661,7 @@ mod tests {
EnvironmentPreference::OnlySystem, EnvironmentPreference::OnlySystem,
PythonPreference::default(), PythonPreference::default(),
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert!( assert!(
@ -693,7 +693,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -715,7 +715,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -741,7 +741,7 @@ mod tests {
EnvironmentPreference::OnlySystem, EnvironmentPreference::OnlySystem,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -767,7 +767,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -790,7 +790,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
@ -824,7 +824,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
@ -858,7 +858,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})?; })?;
assert!( assert!(
@ -880,7 +880,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})?; })?;
assert!( assert!(
@ -902,7 +902,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
@ -936,7 +936,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
@ -973,7 +973,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert!( assert!(
@ -1004,7 +1004,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert!( assert!(
@ -1039,7 +1039,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -1065,7 +1065,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -1092,7 +1092,7 @@ mod tests {
EnvironmentPreference::OnlyVirtual, EnvironmentPreference::OnlyVirtual,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}, },
)??; )??;
@ -1117,7 +1117,7 @@ mod tests {
EnvironmentPreference::OnlyVirtual, EnvironmentPreference::OnlyVirtual,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}, },
)?; )?;
@ -1139,7 +1139,7 @@ mod tests {
EnvironmentPreference::OnlySystem, EnvironmentPreference::OnlySystem,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}, },
)??; )??;
@ -1162,7 +1162,7 @@ mod tests {
EnvironmentPreference::OnlyVirtual, EnvironmentPreference::OnlyVirtual,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}, },
)??; )??;
@ -1195,7 +1195,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}, },
)??; )??;
@ -1216,7 +1216,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}, },
)??; )??;
@ -1243,7 +1243,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
@ -1261,7 +1261,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
@ -1290,7 +1290,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -1328,7 +1328,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}, },
)??; )??;
@ -1356,7 +1356,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}, },
)??; )??;
@ -1381,7 +1381,7 @@ mod tests {
EnvironmentPreference::ExplicitSystem, EnvironmentPreference::ExplicitSystem,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}, },
)??; )??;
@ -1406,7 +1406,7 @@ mod tests {
EnvironmentPreference::OnlySystem, EnvironmentPreference::OnlySystem,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}, },
)??; )??;
@ -1431,7 +1431,7 @@ mod tests {
EnvironmentPreference::OnlyVirtual, EnvironmentPreference::OnlyVirtual,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}, },
)??; )??;
@ -1469,7 +1469,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}, },
)??; )??;
@ -1497,7 +1497,7 @@ mod tests {
EnvironmentPreference::OnlySystem, EnvironmentPreference::OnlySystem,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -1514,7 +1514,7 @@ mod tests {
EnvironmentPreference::OnlySystem, EnvironmentPreference::OnlySystem,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -1531,7 +1531,7 @@ mod tests {
EnvironmentPreference::OnlySystem, EnvironmentPreference::OnlySystem,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})?; })?;
assert!( assert!(
@ -1553,7 +1553,7 @@ mod tests {
EnvironmentPreference::OnlyVirtual, EnvironmentPreference::OnlyVirtual,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})?; })?;
assert!( assert!(
@ -1570,7 +1570,7 @@ mod tests {
EnvironmentPreference::OnlySystem, EnvironmentPreference::OnlySystem,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}, },
)?; )?;
@ -1592,7 +1592,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -1607,7 +1607,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})?; })?;
assert!( assert!(
@ -1621,7 +1621,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})?; })?;
assert!( assert!(
@ -1650,7 +1650,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -1666,7 +1666,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -1696,7 +1696,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -1712,7 +1712,7 @@ mod tests {
EnvironmentPreference::ExplicitSystem, EnvironmentPreference::ExplicitSystem,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -1728,7 +1728,7 @@ mod tests {
EnvironmentPreference::OnlyVirtual, EnvironmentPreference::OnlyVirtual,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -1744,7 +1744,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -1768,7 +1768,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -1783,7 +1783,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -1807,7 +1807,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -1827,7 +1827,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}, },
)??; )??;
@ -1856,7 +1856,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -1878,7 +1878,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})?; })?;
assert!( assert!(
@ -1908,7 +1908,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -1924,7 +1924,7 @@ mod tests {
EnvironmentPreference::ExplicitSystem, EnvironmentPreference::ExplicitSystem,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})?; })?;
assert!( assert!(
@ -1951,7 +1951,7 @@ mod tests {
EnvironmentPreference::ExplicitSystem, EnvironmentPreference::ExplicitSystem,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}) })
.unwrap() .unwrap()
@ -1976,7 +1976,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})?; })?;
assert!( assert!(
@ -1993,7 +1993,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -2008,7 +2008,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -2034,7 +2034,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -2049,7 +2049,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -2075,7 +2075,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -2102,7 +2102,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -2129,7 +2129,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -2156,7 +2156,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -2183,7 +2183,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -2211,7 +2211,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})?; })?;
assert!( assert!(
@ -2233,7 +2233,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -2248,7 +2248,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -2274,7 +2274,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -2289,7 +2289,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
assert_eq!( assert_eq!(
@ -2327,7 +2327,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}) })
.unwrap() .unwrap()
@ -2345,7 +2345,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}) })
.unwrap() .unwrap()
@ -2387,7 +2387,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}) })
.unwrap() .unwrap()
@ -2405,7 +2405,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}) })
.unwrap() .unwrap()
@ -2442,7 +2442,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}) })
.unwrap() .unwrap()
@ -2465,7 +2465,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}) })
.unwrap() .unwrap()
@ -2488,7 +2488,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
}) })
.unwrap() .unwrap()
@ -2527,7 +2527,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;
@ -2580,7 +2580,7 @@ mod tests {
EnvironmentPreference::Any, EnvironmentPreference::Any,
PythonPreference::OnlySystem, PythonPreference::OnlySystem,
&context.cache, &context.cache,
PreviewMode::Disabled, Preview::default(),
) )
})??; })??;

View file

@ -12,7 +12,7 @@ use itertools::Itertools;
use same_file::is_same_file; use same_file::is_same_file;
use thiserror::Error; use thiserror::Error;
use tracing::{debug, warn}; use tracing::{debug, warn};
use uv_configuration::PreviewMode; use uv_configuration::{Preview, PreviewFeatures};
#[cfg(windows)] #[cfg(windows)]
use windows_sys::Win32::Storage::FileSystem::FILE_ATTRIBUTE_REPARSE_POINT; use windows_sys::Win32::Storage::FileSystem::FILE_ATTRIBUTE_REPARSE_POINT;
@ -519,7 +519,7 @@ impl ManagedPythonInstallation {
/// Ensure the environment contains the symlink directory (or junction on Windows) /// Ensure the environment contains the symlink directory (or junction on Windows)
/// pointing to the patch directory for this minor version. /// pointing to the patch directory for this minor version.
pub fn ensure_minor_version_link(&self, preview: PreviewMode) -> Result<(), Error> { pub fn ensure_minor_version_link(&self, preview: Preview) -> Result<(), Error> {
if let Some(minor_version_link) = PythonMinorVersionLink::from_installation(self, preview) { if let Some(minor_version_link) = PythonMinorVersionLink::from_installation(self, preview) {
minor_version_link.create_directory()?; minor_version_link.create_directory()?;
} }
@ -531,7 +531,7 @@ impl ManagedPythonInstallation {
/// ///
/// Unlike [`ensure_minor_version_link`], will not create a new symlink directory /// Unlike [`ensure_minor_version_link`], will not create a new symlink directory
/// if one doesn't already exist, /// if one doesn't already exist,
pub fn update_minor_version_link(&self, preview: PreviewMode) -> Result<(), Error> { pub fn update_minor_version_link(&self, preview: Preview) -> Result<(), Error> {
if let Some(minor_version_link) = PythonMinorVersionLink::from_installation(self, preview) { if let Some(minor_version_link) = PythonMinorVersionLink::from_installation(self, preview) {
if !minor_version_link.exists() { if !minor_version_link.exists() {
return Ok(()); return Ok(());
@ -702,7 +702,7 @@ impl PythonMinorVersionLink {
pub fn from_executable( pub fn from_executable(
executable: &Path, executable: &Path,
key: &PythonInstallationKey, key: &PythonInstallationKey,
preview: PreviewMode, preview: Preview,
) -> Option<Self> { ) -> Option<Self> {
let implementation = key.implementation(); let implementation = key.implementation();
if !matches!( if !matches!(
@ -755,7 +755,7 @@ impl PythonMinorVersionLink {
// If preview mode is disabled, still return a `MinorVersionSymlink` for // If preview mode is disabled, still return a `MinorVersionSymlink` for
// existing symlinks, allowing continued operations without the `--preview` // existing symlinks, allowing continued operations without the `--preview`
// flag after initial symlink directory installation. // flag after initial symlink directory installation.
if preview.is_disabled() && !minor_version_link.exists() { if !preview.is_enabled(PreviewFeatures::PYTHON_UPGRADE) && !minor_version_link.exists() {
return None; return None;
} }
Some(minor_version_link) Some(minor_version_link)
@ -763,7 +763,7 @@ impl PythonMinorVersionLink {
pub fn from_installation( pub fn from_installation(
installation: &ManagedPythonInstallation, installation: &ManagedPythonInstallation,
preview: PreviewMode, preview: Preview,
) -> Option<Self> { ) -> Option<Self> {
PythonMinorVersionLink::from_executable( PythonMinorVersionLink::from_executable(
installation.executable(false).as_path(), installation.executable(false).as_path(),

View file

@ -225,6 +225,9 @@ impl EnvVars {
/// Equivalent to the `--preview` argument. Enables preview mode. /// Equivalent to the `--preview` argument. Enables preview mode.
pub const UV_PREVIEW: &'static str = "UV_PREVIEW"; pub const UV_PREVIEW: &'static str = "UV_PREVIEW";
/// Equivalent to the `--preview-features` argument. Enables specific preview features.
pub const UV_PREVIEW_FEATURES: &'static str = "UV_PREVIEW_FEATURES";
/// Equivalent to the `--token` argument for self update. A GitHub token for authentication. /// Equivalent to the `--token` argument for self update. A GitHub token for authentication.
pub const UV_GITHUB_TOKEN: &'static str = "UV_GITHUB_TOKEN"; pub const UV_GITHUB_TOKEN: &'static str = "UV_GITHUB_TOKEN";

View file

@ -1,7 +1,7 @@
use core::fmt; use core::fmt;
use fs_err as fs; use fs_err as fs;
use uv_configuration::PreviewMode; use uv_configuration::Preview;
use uv_dirs::user_executable_directory; use uv_dirs::user_executable_directory;
use uv_pep440::Version; use uv_pep440::Version;
use uv_pep508::{InvalidNameError, PackageName}; use uv_pep508::{InvalidNameError, PackageName};
@ -258,7 +258,7 @@ impl InstalledTools {
&self, &self,
name: &PackageName, name: &PackageName,
interpreter: Interpreter, interpreter: Interpreter,
preview: PreviewMode, preview: Preview,
) -> Result<PythonEnvironment, Error> { ) -> Result<PythonEnvironment, Error> {
let environment_path = self.tool_dir(name); let environment_path = self.tool_dir(name);

View file

@ -3,7 +3,7 @@ use std::path::Path;
use thiserror::Error; use thiserror::Error;
use uv_configuration::PreviewMode; use uv_configuration::Preview;
use uv_python::{Interpreter, PythonEnvironment}; use uv_python::{Interpreter, PythonEnvironment};
pub use virtualenv::{OnExisting, remove_virtualenv}; pub use virtualenv::{OnExisting, remove_virtualenv};
@ -56,7 +56,7 @@ pub fn create_venv(
relocatable: bool, relocatable: bool,
seed: bool, seed: bool,
upgradeable: bool, upgradeable: bool,
preview: PreviewMode, preview: Preview,
) -> Result<PythonEnvironment, Error> { ) -> Result<PythonEnvironment, Error> {
// Create the virtualenv at the given location. // Create the virtualenv at the given location.
let virtualenv = virtualenv::create( let virtualenv = virtualenv::create(

View file

@ -12,7 +12,7 @@ use itertools::Itertools;
use owo_colors::OwoColorize; use owo_colors::OwoColorize;
use tracing::{debug, trace}; use tracing::{debug, trace};
use uv_configuration::PreviewMode; use uv_configuration::Preview;
use uv_fs::{CWD, Simplified, cachedir}; use uv_fs::{CWD, Simplified, cachedir};
use uv_pypi_types::Scheme; use uv_pypi_types::Scheme;
use uv_python::managed::{PythonMinorVersionLink, create_link_to_executable}; use uv_python::managed::{PythonMinorVersionLink, create_link_to_executable};
@ -59,7 +59,7 @@ pub(crate) fn create(
relocatable: bool, relocatable: bool,
seed: bool, seed: bool,
upgradeable: bool, upgradeable: bool,
preview: PreviewMode, preview: Preview,
) -> Result<VirtualEnvironment, Error> { ) -> Result<VirtualEnvironment, Error> {
// Determine the base Python executable; that is, the Python executable that should be // Determine the base Python executable; that is, the Python executable that should be
// considered the "base" for the virtual environment. // considered the "base" for the virtual environment.

View file

@ -16,7 +16,7 @@ use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{ use uv_configuration::{
BuildKind, BuildOptions, BuildOutput, Concurrency, ConfigSettings, Constraints, BuildKind, BuildOptions, BuildOutput, Concurrency, ConfigSettings, Constraints,
DependencyGroupsWithDefaults, HashCheckingMode, IndexStrategy, KeyringProviderType, DependencyGroupsWithDefaults, HashCheckingMode, IndexStrategy, KeyringProviderType,
PackageConfigSettings, PreviewMode, SourceStrategy, PackageConfigSettings, Preview, SourceStrategy,
}; };
use uv_dispatch::{BuildDispatch, SharedState}; use uv_dispatch::{BuildDispatch, SharedState};
use uv_distribution_filename::{ use uv_distribution_filename::{
@ -117,7 +117,7 @@ pub(crate) async fn build_frontend(
concurrency: Concurrency, concurrency: Concurrency,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
let build_result = build_impl( let build_result = build_impl(
project_dir, project_dir,
@ -185,7 +185,7 @@ async fn build_impl(
concurrency: Concurrency, concurrency: Concurrency,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<BuildResult> { ) -> Result<BuildResult> {
// Extract the resolver settings. // Extract the resolver settings.
let ResolverSettings { let ResolverSettings {
@ -437,7 +437,7 @@ async fn build_package(
link_mode: LinkMode, link_mode: LinkMode,
config_setting: &ConfigSettings, config_setting: &ConfigSettings,
config_settings_package: &PackageConfigSettings, config_settings_package: &PackageConfigSettings,
preview: PreviewMode, preview: Preview,
) -> Result<Vec<BuildMessage>, Error> { ) -> Result<Vec<BuildMessage>, Error> {
let output_dir = if let Some(output_dir) = output_dir { let output_dir = if let Some(output_dir) = output_dir {
Cow::Owned(std::path::absolute(output_dir)?) Cow::Owned(std::path::absolute(output_dir)?)

View file

@ -5,7 +5,7 @@ use anyhow::Result;
use owo_colors::OwoColorize; use owo_colors::OwoColorize;
use uv_cache::Cache; use uv_cache::Cache;
use uv_configuration::PreviewMode; use uv_configuration::Preview;
use uv_distribution_types::{Diagnostic, InstalledDist}; use uv_distribution_types::{Diagnostic, InstalledDist};
use uv_installer::{SitePackages, SitePackagesDiagnostic}; use uv_installer::{SitePackages, SitePackagesDiagnostic};
use uv_python::{EnvironmentPreference, PythonEnvironment, PythonRequest}; use uv_python::{EnvironmentPreference, PythonEnvironment, PythonRequest};
@ -20,7 +20,7 @@ pub(crate) fn pip_check(
system: bool, system: bool,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
let start = Instant::now(); let start = Instant::now();

View file

@ -14,8 +14,8 @@ use uv_cache::Cache;
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder}; use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{ use uv_configuration::{
BuildOptions, Concurrency, ConfigSettings, Constraints, ExportFormat, ExtrasSpecification, BuildOptions, Concurrency, ConfigSettings, Constraints, ExportFormat, ExtrasSpecification,
IndexStrategy, NoBinary, NoBuild, PackageConfigSettings, PreviewMode, Reinstall, IndexStrategy, NoBinary, NoBuild, PackageConfigSettings, Preview, Reinstall, SourceStrategy,
SourceStrategy, Upgrade, Upgrade,
}; };
use uv_configuration::{KeyringProviderType, TargetTriple}; use uv_configuration::{KeyringProviderType, TargetTriple};
use uv_dispatch::{BuildDispatch, SharedState}; use uv_dispatch::{BuildDispatch, SharedState};
@ -110,7 +110,7 @@ pub(crate) async fn pip_compile(
quiet: bool, quiet: bool,
cache: Cache, cache: Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
// If the user provides a `pyproject.toml` or other TOML file as the output file, raise an // If the user provides a `pyproject.toml` or other TOML file as the output file, raise an
// error. // error.

View file

@ -6,7 +6,7 @@ use itertools::Itertools;
use owo_colors::OwoColorize; use owo_colors::OwoColorize;
use uv_cache::Cache; use uv_cache::Cache;
use uv_configuration::PreviewMode; use uv_configuration::Preview;
use uv_distribution_types::{Diagnostic, InstalledDist, Name}; use uv_distribution_types::{Diagnostic, InstalledDist, Name};
use uv_installer::SitePackages; use uv_installer::SitePackages;
use uv_python::{EnvironmentPreference, PythonEnvironment, PythonRequest}; use uv_python::{EnvironmentPreference, PythonEnvironment, PythonRequest};
@ -24,7 +24,7 @@ pub(crate) fn pip_freeze(
paths: Option<Vec<PathBuf>>, paths: Option<Vec<PathBuf>>,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
// Detect the current Python interpreter. // Detect the current Python interpreter.
let environment = PythonEnvironment::find( let environment = PythonEnvironment::find(

View file

@ -10,8 +10,8 @@ use uv_cache::Cache;
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder}; use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{ use uv_configuration::{
BuildOptions, Concurrency, ConfigSettings, Constraints, DryRun, ExtrasSpecification, BuildOptions, Concurrency, ConfigSettings, Constraints, DryRun, ExtrasSpecification,
HashCheckingMode, IndexStrategy, PackageConfigSettings, PreviewMode, Reinstall, SourceStrategy, HashCheckingMode, IndexStrategy, PackageConfigSettings, Preview, PreviewFeatures, Reinstall,
Upgrade, SourceStrategy, Upgrade,
}; };
use uv_configuration::{KeyringProviderType, TargetTriple}; use uv_configuration::{KeyringProviderType, TargetTriple};
use uv_dispatch::{BuildDispatch, SharedState}; use uv_dispatch::{BuildDispatch, SharedState};
@ -95,7 +95,7 @@ pub(crate) async fn pip_install(
cache: Cache, cache: Cache,
dry_run: DryRun, dry_run: DryRun,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> anyhow::Result<ExitStatus> { ) -> anyhow::Result<ExitStatus> {
let start = std::time::Instant::now(); let start = std::time::Instant::now();
@ -133,9 +133,10 @@ pub(crate) async fn pip_install(
.await?; .await?;
if pylock.is_some() { if pylock.is_some() {
if preview.is_disabled() { if !preview.is_enabled(PreviewFeatures::PYLOCK) {
warn_user!( warn_user!(
"The `--pylock` setting is experimental and may change without warning. Pass `--preview` to disable this warning." "The `--pylock` setting is experimental and may change without warning. Pass `--preview-features {}` to disable this warning.",
PreviewFeatures::PYLOCK
); );
} }
} }

View file

@ -15,7 +15,7 @@ use uv_cache::{Cache, Refresh};
use uv_cache_info::Timestamp; use uv_cache_info::Timestamp;
use uv_cli::ListFormat; use uv_cli::ListFormat;
use uv_client::{BaseClientBuilder, RegistryClientBuilder}; use uv_client::{BaseClientBuilder, RegistryClientBuilder};
use uv_configuration::{Concurrency, IndexStrategy, KeyringProviderType, PreviewMode}; use uv_configuration::{Concurrency, IndexStrategy, KeyringProviderType, Preview};
use uv_distribution_filename::DistFilename; use uv_distribution_filename::DistFilename;
use uv_distribution_types::{ use uv_distribution_types::{
Diagnostic, IndexCapabilities, IndexLocations, InstalledDist, Name, RequiresPython, Diagnostic, IndexCapabilities, IndexLocations, InstalledDist, Name, RequiresPython,
@ -54,7 +54,7 @@ pub(crate) async fn pip_list(
system: bool, system: bool,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
// Disallow `--outdated` with `--format freeze`. // Disallow `--outdated` with `--format freeze`.
if outdated && matches!(format, ListFormat::Freeze) { if outdated && matches!(format, ListFormat::Freeze) {

View file

@ -7,7 +7,7 @@ use owo_colors::OwoColorize;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use uv_cache::Cache; use uv_cache::Cache;
use uv_configuration::PreviewMode; use uv_configuration::Preview;
use uv_distribution_types::{Diagnostic, Name}; use uv_distribution_types::{Diagnostic, Name};
use uv_fs::Simplified; use uv_fs::Simplified;
use uv_install_wheel::read_record_file; use uv_install_wheel::read_record_file;
@ -28,7 +28,7 @@ pub(crate) fn pip_show(
files: bool, files: bool,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
if packages.is_empty() { if packages.is_empty() {
#[allow(clippy::print_stderr)] #[allow(clippy::print_stderr)]

View file

@ -9,8 +9,8 @@ use uv_cache::Cache;
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder}; use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{ use uv_configuration::{
BuildOptions, Concurrency, ConfigSettings, Constraints, DryRun, ExtrasSpecification, BuildOptions, Concurrency, ConfigSettings, Constraints, DryRun, ExtrasSpecification,
HashCheckingMode, IndexStrategy, PackageConfigSettings, PreviewMode, Reinstall, SourceStrategy, HashCheckingMode, IndexStrategy, PackageConfigSettings, Preview, PreviewFeatures, Reinstall,
Upgrade, SourceStrategy, Upgrade,
}; };
use uv_configuration::{KeyringProviderType, TargetTriple}; use uv_configuration::{KeyringProviderType, TargetTriple};
use uv_dispatch::{BuildDispatch, SharedState}; use uv_dispatch::{BuildDispatch, SharedState};
@ -83,7 +83,7 @@ pub(crate) async fn pip_sync(
cache: Cache, cache: Cache,
dry_run: DryRun, dry_run: DryRun,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()? .retries_from_env()?
@ -126,9 +126,10 @@ pub(crate) async fn pip_sync(
.await?; .await?;
if pylock.is_some() { if pylock.is_some() {
if preview.is_disabled() { if !preview.is_enabled(PreviewFeatures::PYLOCK) {
warn_user!( warn_user!(
"The `--pylock` setting is experimental and may change without warning. Pass `--preview` to disable this warning." "The `--pylock` setting is experimental and may change without warning. Pass `--preview-features {}` to disable this warning.",
PreviewFeatures::PYLOCK
); );
} }
} }

View file

@ -13,7 +13,7 @@ use tokio::sync::Semaphore;
use uv_cache::{Cache, Refresh}; use uv_cache::{Cache, Refresh};
use uv_cache_info::Timestamp; use uv_cache_info::Timestamp;
use uv_client::{BaseClientBuilder, RegistryClientBuilder}; use uv_client::{BaseClientBuilder, RegistryClientBuilder};
use uv_configuration::{Concurrency, IndexStrategy, KeyringProviderType, PreviewMode}; use uv_configuration::{Concurrency, IndexStrategy, KeyringProviderType, Preview};
use uv_distribution_types::{Diagnostic, IndexCapabilities, IndexLocations, Name, RequiresPython}; use uv_distribution_types::{Diagnostic, IndexCapabilities, IndexLocations, Name, RequiresPython};
use uv_installer::SitePackages; use uv_installer::SitePackages;
use uv_normalize::PackageName; use uv_normalize::PackageName;
@ -52,7 +52,7 @@ pub(crate) async fn pip_tree(
system: bool, system: bool,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
// Detect the current Python interpreter. // Detect the current Python interpreter.
let environment = PythonEnvironment::find( let environment = PythonEnvironment::find(

View file

@ -7,7 +7,7 @@ use tracing::{debug, warn};
use uv_cache::Cache; use uv_cache::Cache;
use uv_client::BaseClientBuilder; use uv_client::BaseClientBuilder;
use uv_configuration::{DryRun, KeyringProviderType, PreviewMode}; use uv_configuration::{DryRun, KeyringProviderType, Preview};
use uv_distribution_types::Requirement; use uv_distribution_types::Requirement;
use uv_distribution_types::{InstalledMetadata, Name, UnresolvedRequirement}; use uv_distribution_types::{InstalledMetadata, Name, UnresolvedRequirement};
use uv_fs::Simplified; use uv_fs::Simplified;
@ -37,7 +37,7 @@ pub(crate) async fn pip_uninstall(
network_settings: &NetworkSettings, network_settings: &NetworkSettings,
dry_run: DryRun, dry_run: DryRun,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
let start = std::time::Instant::now(); let start = std::time::Instant::now();

View file

@ -18,8 +18,8 @@ use uv_cache_key::RepositoryUrl;
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder}; use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{ use uv_configuration::{
Concurrency, Constraints, DependencyGroups, DependencyGroupsWithDefaults, DevMode, DryRun, Concurrency, Constraints, DependencyGroups, DependencyGroupsWithDefaults, DevMode, DryRun,
EditableMode, ExtrasSpecification, ExtrasSpecificationWithDefaults, InstallOptions, EditableMode, ExtrasSpecification, ExtrasSpecificationWithDefaults, InstallOptions, Preview,
PreviewMode, SourceStrategy, PreviewFeatures, SourceStrategy,
}; };
use uv_dispatch::BuildDispatch; use uv_dispatch::BuildDispatch;
use uv_distribution::DistributionDatabase; use uv_distribution::DistributionDatabase;
@ -95,10 +95,13 @@ pub(crate) async fn add(
no_config: bool, no_config: bool,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
if bounds.is_some() && preview.is_disabled() { if bounds.is_some() && !preview.is_enabled(PreviewFeatures::ADD_BOUNDS) {
warn_user_once!("The bounds option is in preview and may change in any future release."); warn_user_once!(
"The `bounds` option is in preview and may change in any future release. Pass `--preview-features {}` to disable this warning.",
PreviewFeatures::ADD_BOUNDS
);
} }
for source in &requirements { for source in &requirements {
@ -944,7 +947,7 @@ async fn lock_and_sync(
concurrency: Concurrency, concurrency: Concurrency,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<(), ProjectError> { ) -> Result<(), ProjectError> {
let mut lock = project::lock::LockOperation::new( let mut lock = project::lock::LockOperation::new(
if locked { if locked {

View file

@ -12,7 +12,7 @@ use crate::settings::{NetworkSettings, ResolverInstallerSettings};
use uv_cache::{Cache, CacheBucket}; use uv_cache::{Cache, CacheBucket};
use uv_cache_key::{cache_digest, hash_digest}; use uv_cache_key::{cache_digest, hash_digest};
use uv_configuration::{Concurrency, Constraints, PreviewMode}; use uv_configuration::{Concurrency, Constraints, Preview};
use uv_distribution_types::{Name, Resolution}; use uv_distribution_types::{Name, Resolution};
use uv_fs::PythonExt; use uv_fs::PythonExt;
use uv_python::{Interpreter, PythonEnvironment, canonicalize_executable}; use uv_python::{Interpreter, PythonEnvironment, canonicalize_executable};
@ -119,7 +119,7 @@ impl CachedEnvironment {
concurrency: Concurrency, concurrency: Concurrency,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<Self, ProjectError> { ) -> Result<Self, ProjectError> {
let interpreter = Self::base_interpreter(interpreter, cache)?; let interpreter = Self::base_interpreter(interpreter, cache)?;

View file

@ -9,7 +9,7 @@ use owo_colors::OwoColorize;
use uv_cache::Cache; use uv_cache::Cache;
use uv_configuration::{ use uv_configuration::{
Concurrency, DependencyGroups, EditableMode, ExportFormat, ExtrasSpecification, InstallOptions, Concurrency, DependencyGroups, EditableMode, ExportFormat, ExtrasSpecification, InstallOptions,
PreviewMode, Preview,
}; };
use uv_normalize::{DefaultExtras, DefaultGroups, PackageName}; use uv_normalize::{DefaultExtras, DefaultGroups, PackageName};
use uv_python::{PythonDownloads, PythonPreference, PythonRequest}; use uv_python::{PythonDownloads, PythonPreference, PythonRequest};
@ -79,7 +79,7 @@ pub(crate) async fn export(
quiet: bool, quiet: bool,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
// Identify the target. // Identify the target.
let workspace_cache = WorkspaceCache::default(); let workspace_cache = WorkspaceCache::default();

View file

@ -12,7 +12,7 @@ use uv_cache::Cache;
use uv_cli::AuthorFrom; use uv_cli::AuthorFrom;
use uv_client::BaseClientBuilder; use uv_client::BaseClientBuilder;
use uv_configuration::{ use uv_configuration::{
DependencyGroupsWithDefaults, PreviewMode, ProjectBuildBackend, VersionControlError, DependencyGroupsWithDefaults, Preview, ProjectBuildBackend, VersionControlError,
VersionControlSystem, VersionControlSystem,
}; };
use uv_fs::{CWD, Simplified}; use uv_fs::{CWD, Simplified};
@ -62,7 +62,7 @@ pub(crate) async fn init(
no_config: bool, no_config: bool,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
match init_kind { match init_kind {
InitKind::Script => { InitKind::Script => {
@ -201,7 +201,7 @@ async fn init_script(
pin_python: bool, pin_python: bool,
package: bool, package: bool,
no_config: bool, no_config: bool,
preview: PreviewMode, preview: Preview,
) -> Result<()> { ) -> Result<()> {
if no_workspace { if no_workspace {
warn_user_once!("`--no-workspace` is a no-op for Python scripts, which are standalone"); warn_user_once!("`--no-workspace` is a no-op for Python scripts, which are standalone");
@ -296,7 +296,7 @@ async fn init_project(
no_config: bool, no_config: bool,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<()> { ) -> Result<()> {
// Discover the current workspace, if it exists. // Discover the current workspace, if it exists.
let workspace_cache = WorkspaceCache::default(); let workspace_cache = WorkspaceCache::default();

View file

@ -12,8 +12,8 @@ use tracing::debug;
use uv_cache::Cache; use uv_cache::Cache;
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder}; use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{ use uv_configuration::{
Concurrency, Constraints, DependencyGroupsWithDefaults, DryRun, ExtrasSpecification, Concurrency, Constraints, DependencyGroupsWithDefaults, DryRun, ExtrasSpecification, Preview,
PreviewMode, Reinstall, Upgrade, Reinstall, Upgrade,
}; };
use uv_dispatch::BuildDispatch; use uv_dispatch::BuildDispatch;
use uv_distribution::DistributionDatabase; use uv_distribution::DistributionDatabase;
@ -93,7 +93,7 @@ pub(crate) async fn lock(
no_config: bool, no_config: bool,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> anyhow::Result<ExitStatus> { ) -> anyhow::Result<ExitStatus> {
// If necessary, initialize the PEP 723 script. // If necessary, initialize the PEP 723 script.
let script = match script { let script = match script {
@ -271,7 +271,7 @@ pub(super) struct LockOperation<'env> {
cache: &'env Cache, cache: &'env Cache,
workspace_cache: &'env WorkspaceCache, workspace_cache: &'env WorkspaceCache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
} }
impl<'env> LockOperation<'env> { impl<'env> LockOperation<'env> {
@ -286,7 +286,7 @@ impl<'env> LockOperation<'env> {
cache: &'env Cache, cache: &'env Cache,
workspace_cache: &'env WorkspaceCache, workspace_cache: &'env WorkspaceCache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Self { ) -> Self {
Self { Self {
mode, mode,
@ -418,7 +418,7 @@ async fn do_lock(
cache: &Cache, cache: &Cache,
workspace_cache: &WorkspaceCache, workspace_cache: &WorkspaceCache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<LockResult, ProjectError> { ) -> Result<LockResult, ProjectError> {
let start = std::time::Instant::now(); let start = std::time::Instant::now();

View file

@ -12,8 +12,8 @@ use uv_cache::{Cache, CacheBucket};
use uv_cache_key::cache_digest; use uv_cache_key::cache_digest;
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder}; use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{ use uv_configuration::{
Concurrency, Constraints, DependencyGroupsWithDefaults, DryRun, ExtrasSpecification, Concurrency, Constraints, DependencyGroupsWithDefaults, DryRun, ExtrasSpecification, Preview,
PreviewMode, Reinstall, SourceStrategy, Upgrade, PreviewFeatures, Reinstall, SourceStrategy, Upgrade,
}; };
use uv_dispatch::{BuildDispatch, SharedState}; use uv_dispatch::{BuildDispatch, SharedState};
use uv_distribution::{DistributionDatabase, LoweredRequirement}; use uv_distribution::{DistributionDatabase, LoweredRequirement};
@ -647,7 +647,7 @@ impl ScriptInterpreter {
active: Option<bool>, active: Option<bool>,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<Self, ProjectError> { ) -> Result<Self, ProjectError> {
// For now, we assume that scripts are never evaluated in the context of a workspace. // For now, we assume that scripts are never evaluated in the context of a workspace.
let workspace = None; let workspace = None;
@ -887,7 +887,7 @@ impl ProjectInterpreter {
active: Option<bool>, active: Option<bool>,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<Self, ProjectError> { ) -> Result<Self, ProjectError> {
// Resolve the Python request and requirement for the workspace. // Resolve the Python request and requirement for the workspace.
let WorkspacePython { let WorkspacePython {
@ -1269,7 +1269,7 @@ impl ProjectEnvironment {
cache: &Cache, cache: &Cache,
dry_run: DryRun, dry_run: DryRun,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<Self, ProjectError> { ) -> Result<Self, ProjectError> {
// Lock the project environment to avoid synchronization issues. // Lock the project environment to avoid synchronization issues.
let _lock = ProjectInterpreter::lock(workspace) let _lock = ProjectInterpreter::lock(workspace)
@ -1279,7 +1279,7 @@ impl ProjectEnvironment {
}) })
.ok(); .ok();
let upgradeable = preview.is_enabled() let upgradeable = preview.is_enabled(PreviewFeatures::PYTHON_UPGRADE)
&& python && python
.as_ref() .as_ref()
.is_none_or(|request| !request.includes_patch()); .is_none_or(|request| !request.includes_patch());
@ -1501,7 +1501,7 @@ impl ScriptEnvironment {
cache: &Cache, cache: &Cache,
dry_run: DryRun, dry_run: DryRun,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<Self, ProjectError> { ) -> Result<Self, ProjectError> {
// Lock the script environment to avoid synchronization issues. // Lock the script environment to avoid synchronization issues.
let _lock = ScriptInterpreter::lock(script) let _lock = ScriptInterpreter::lock(script)
@ -1658,7 +1658,7 @@ pub(crate) async fn resolve_names(
cache: &Cache, cache: &Cache,
workspace_cache: &WorkspaceCache, workspace_cache: &WorkspaceCache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<Vec<Requirement>, uv_requirements::Error> { ) -> Result<Vec<Requirement>, uv_requirements::Error> {
// Partition the requirements into named and unnamed requirements. // Partition the requirements into named and unnamed requirements.
let (mut requirements, unnamed): (Vec<_>, Vec<_>) = let (mut requirements, unnamed): (Vec<_>, Vec<_>) =
@ -1829,7 +1829,7 @@ pub(crate) async fn resolve_environment(
concurrency: Concurrency, concurrency: Concurrency,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ResolverOutput, ProjectError> { ) -> Result<ResolverOutput, ProjectError> {
warn_on_requirements_txt_setting(&spec.requirements, settings); warn_on_requirements_txt_setting(&spec.requirements, settings);
@ -2017,7 +2017,7 @@ pub(crate) async fn sync_environment(
concurrency: Concurrency, concurrency: Concurrency,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<PythonEnvironment, ProjectError> { ) -> Result<PythonEnvironment, ProjectError> {
let InstallerSettingsRef { let InstallerSettingsRef {
index_locations, index_locations,
@ -2175,7 +2175,7 @@ pub(crate) async fn update_environment(
workspace_cache: WorkspaceCache, workspace_cache: WorkspaceCache,
dry_run: DryRun, dry_run: DryRun,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<EnvironmentUpdate, ProjectError> { ) -> Result<EnvironmentUpdate, ProjectError> {
warn_on_requirements_txt_setting(&spec, &settings.resolver); warn_on_requirements_txt_setting(&spec, &settings.resolver);
@ -2416,7 +2416,7 @@ pub(crate) async fn init_script_python_requirement(
client_builder: &BaseClientBuilder<'_>, client_builder: &BaseClientBuilder<'_>,
cache: &Cache, cache: &Cache,
reporter: &PythonDownloadReporter, reporter: &PythonDownloadReporter,
preview: PreviewMode, preview: Preview,
) -> anyhow::Result<RequiresPython> { ) -> anyhow::Result<RequiresPython> {
let python_request = if let Some(request) = python { let python_request = if let Some(request) = python {
// (1) Explicit request from user // (1) Explicit request from user

View file

@ -10,7 +10,7 @@ use tracing::{debug, warn};
use uv_cache::Cache; use uv_cache::Cache;
use uv_configuration::{ use uv_configuration::{
Concurrency, DependencyGroups, DryRun, EditableMode, ExtrasSpecification, InstallOptions, Concurrency, DependencyGroups, DryRun, EditableMode, ExtrasSpecification, InstallOptions,
PreviewMode, Preview,
}; };
use uv_fs::Simplified; use uv_fs::Simplified;
use uv_normalize::{DEV_DEPENDENCIES, DefaultExtras, DefaultGroups}; use uv_normalize::{DEV_DEPENDENCIES, DefaultExtras, DefaultGroups};
@ -60,7 +60,7 @@ pub(crate) async fn remove(
no_config: bool, no_config: bool,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
let target = if let Some(script) = script { let target = if let Some(script) = script {
// If we found a PEP 723 script and the user provided a project-only setting, warn. // If we found a PEP 723 script and the user provided a project-only setting, warn.

View file

@ -19,7 +19,7 @@ use uv_cli::ExternalCommand;
use uv_client::BaseClientBuilder; use uv_client::BaseClientBuilder;
use uv_configuration::{ use uv_configuration::{
Concurrency, Constraints, DependencyGroups, DryRun, EditableMode, ExtrasSpecification, Concurrency, Constraints, DependencyGroups, DryRun, EditableMode, ExtrasSpecification,
InstallOptions, PreviewMode, InstallOptions, Preview,
}; };
use uv_distribution_types::Requirement; use uv_distribution_types::Requirement;
use uv_fs::which::is_executable; use uv_fs::which::is_executable;
@ -94,7 +94,7 @@ pub(crate) async fn run(
printer: Printer, printer: Printer,
env_file: Vec<PathBuf>, env_file: Vec<PathBuf>,
no_env_file: bool, no_env_file: bool,
preview: PreviewMode, preview: Preview,
max_recursion_depth: u32, max_recursion_depth: u32,
) -> anyhow::Result<ExitStatus> { ) -> anyhow::Result<ExitStatus> {
// Check if max recursion depth was exceeded. This most commonly happens // Check if max recursion depth was exceeded. This most commonly happens

View file

@ -14,7 +14,7 @@ use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{ use uv_configuration::{
Concurrency, Constraints, DependencyGroups, DependencyGroupsWithDefaults, DryRun, EditableMode, Concurrency, Constraints, DependencyGroups, DependencyGroupsWithDefaults, DryRun, EditableMode,
ExtrasSpecification, ExtrasSpecificationWithDefaults, HashCheckingMode, InstallOptions, ExtrasSpecification, ExtrasSpecificationWithDefaults, HashCheckingMode, InstallOptions,
PreviewMode, TargetTriple, Preview, PreviewFeatures, TargetTriple,
}; };
use uv_dispatch::BuildDispatch; use uv_dispatch::BuildDispatch;
use uv_distribution_types::{ use uv_distribution_types::{
@ -77,12 +77,14 @@ pub(crate) async fn sync(
no_config: bool, no_config: bool,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
output_format: SyncFormat, output_format: SyncFormat,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
if preview.is_enabled() && matches!(output_format, SyncFormat::Json) { if preview.is_enabled(PreviewFeatures::JSON_OUTPUT) && matches!(output_format, SyncFormat::Json)
{
warn_user!( warn_user!(
"The `--output-format json` option is experimental and the schema may change without warning. Pass `--preview` to disable this warning." "The `--output-format json` option is experimental and the schema may change without warning. Pass `--preview-features {}` to disable this warning.",
PreviewFeatures::JSON_OUTPUT
); );
} }
@ -564,7 +566,7 @@ pub(super) async fn do_sync(
workspace_cache: WorkspaceCache, workspace_cache: WorkspaceCache,
dry_run: DryRun, dry_run: DryRun,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<(), ProjectError> { ) -> Result<(), ProjectError> {
// Extract the project settings. // Extract the project settings.
let InstallerSettingsRef { let InstallerSettingsRef {

View file

@ -7,7 +7,7 @@ use tokio::sync::Semaphore;
use uv_cache::{Cache, Refresh}; use uv_cache::{Cache, Refresh};
use uv_cache_info::Timestamp; use uv_cache_info::Timestamp;
use uv_client::RegistryClientBuilder; use uv_client::RegistryClientBuilder;
use uv_configuration::{Concurrency, DependencyGroups, PreviewMode, TargetTriple}; use uv_configuration::{Concurrency, DependencyGroups, Preview, TargetTriple};
use uv_distribution_types::IndexCapabilities; use uv_distribution_types::IndexCapabilities;
use uv_normalize::DefaultGroups; use uv_normalize::DefaultGroups;
use uv_pep508::PackageName; use uv_pep508::PackageName;
@ -57,7 +57,7 @@ pub(crate) async fn tree(
no_config: bool, no_config: bool,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
// Find the project requirements. // Find the project requirements.
let workspace_cache = WorkspaceCache::default(); let workspace_cache = WorkspaceCache::default();

View file

@ -11,7 +11,7 @@ use uv_cli::version::VersionInfo;
use uv_cli::{VersionBump, VersionFormat}; use uv_cli::{VersionBump, VersionFormat};
use uv_configuration::{ use uv_configuration::{
Concurrency, DependencyGroups, DependencyGroupsWithDefaults, DryRun, EditableMode, Concurrency, DependencyGroups, DependencyGroupsWithDefaults, DryRun, EditableMode,
ExtrasSpecification, InstallOptions, PreviewMode, ExtrasSpecification, InstallOptions, Preview,
}; };
use uv_fs::Simplified; use uv_fs::Simplified;
use uv_normalize::DefaultExtras; use uv_normalize::DefaultExtras;
@ -76,7 +76,7 @@ pub(crate) async fn project_version(
no_config: bool, no_config: bool,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
// Read the metadata // Read the metadata
let project = find_target(project_dir, package.as_ref(), explicit_project).await?; let project = find_target(project_dir, package.as_ref(), explicit_project).await?;
@ -414,7 +414,7 @@ async fn print_frozen_version(
short: bool, short: bool,
output_format: VersionFormat, output_format: VersionFormat,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
// Discover the interpreter (this is the same interpreter --no-sync uses). // Discover the interpreter (this is the same interpreter --no-sync uses).
let interpreter = ProjectInterpreter::discover( let interpreter = ProjectInterpreter::discover(
@ -509,7 +509,7 @@ async fn lock_and_sync(
no_config: bool, no_config: bool,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
// If frozen, don't touch the lock or sync at all // If frozen, don't touch the lock or sync at all
if frozen { if frozen {

View file

@ -3,7 +3,7 @@ use std::fmt::Write;
use std::path::Path; use std::path::Path;
use uv_cache::Cache; use uv_cache::Cache;
use uv_configuration::{DependencyGroupsWithDefaults, PreviewMode}; use uv_configuration::{DependencyGroupsWithDefaults, Preview};
use uv_fs::Simplified; use uv_fs::Simplified;
use uv_python::{ use uv_python::{
EnvironmentPreference, PythonDownloads, PythonInstallation, PythonPreference, PythonRequest, EnvironmentPreference, PythonDownloads, PythonInstallation, PythonPreference, PythonRequest,
@ -32,7 +32,7 @@ pub(crate) async fn find(
python_preference: PythonPreference, python_preference: PythonPreference,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
let environment_preference = if system { let environment_preference = if system {
EnvironmentPreference::OnlySystem EnvironmentPreference::OnlySystem
@ -123,7 +123,7 @@ pub(crate) async fn find_script(
no_config: bool, no_config: bool,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
let interpreter = match ScriptInterpreter::discover( let interpreter = match ScriptInterpreter::discover(
script, script,

View file

@ -14,7 +14,7 @@ use owo_colors::OwoColorize;
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use tracing::{debug, trace}; use tracing::{debug, trace};
use uv_configuration::PreviewMode; use uv_configuration::{Preview, PreviewFeatures};
use uv_fs::Simplified; use uv_fs::Simplified;
use uv_python::downloads::{ use uv_python::downloads::{
self, ArchRequest, DownloadResult, ManagedPythonDownload, PythonDownloadRequest, self, ArchRequest, DownloadResult, ManagedPythonDownload, PythonDownloadRequest,
@ -161,7 +161,7 @@ pub(crate) async fn install(
default: bool, default: bool,
python_downloads: PythonDownloads, python_downloads: PythonDownloads,
no_config: bool, no_config: bool,
preview: PreviewMode, preview: Preview,
printer: Printer, printer: Printer,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
let start = std::time::Instant::now(); let start = std::time::Instant::now();
@ -170,15 +170,17 @@ pub(crate) async fn install(
// `--default` is used. It's not clear how this overlaps with a global Python pin, but I'd be // `--default` is used. It's not clear how this overlaps with a global Python pin, but I'd be
// surprised if `uv python find` returned the "newest" Python version rather than the one I just // surprised if `uv python find` returned the "newest" Python version rather than the one I just
// installed with the `--default` flag. // installed with the `--default` flag.
if default && !preview.is_enabled() { if default && !preview.is_enabled(PreviewFeatures::PYTHON_INSTALL_DEFAULT) {
warn_user!( warn_user!(
"The `--default` option is experimental and may change without warning. Pass `--preview` to disable this warning" "The `--default` option is experimental and may change without warning. Pass `--preview-features {}` to disable this warning",
PreviewFeatures::PYTHON_INSTALL_DEFAULT
); );
} }
if upgrade && preview.is_disabled() { if upgrade && !preview.is_enabled(PreviewFeatures::PYTHON_UPGRADE) {
warn_user!( warn_user!(
"`uv python upgrade` is experimental and may change without warning. Pass `--preview` to disable this warning" "`uv python upgrade` is experimental and may change without warning. Pass `--preview-features {}` to disable this warning",
PreviewFeatures::PYTHON_UPGRADE
); );
} }
@ -737,12 +739,13 @@ fn create_bin_links(
installations: &[&ManagedPythonInstallation], installations: &[&ManagedPythonInstallation],
changelog: &mut Changelog, changelog: &mut Changelog,
errors: &mut Vec<(InstallErrorKind, PythonInstallationKey, Error)>, errors: &mut Vec<(InstallErrorKind, PythonInstallationKey, Error)>,
preview: PreviewMode, preview: Preview,
) { ) {
// TODO(zanieb): We want more feedback on the `is_default_install` behavior before stabilizing // TODO(zanieb): We want more feedback on the `is_default_install` behavior before stabilizing
// it. In particular, it may be confusing because it does not apply when versions are loaded // it. In particular, it may be confusing because it does not apply when versions are loaded
// from a `.python-version` file. // from a `.python-version` file.
let targets = if (default || (is_default_install && preview.is_enabled())) let targets = if (default
|| (is_default_install && preview.is_enabled(PreviewFeatures::PYTHON_INSTALL_DEFAULT)))
&& first_request.matches_installation(installation) && first_request.matches_installation(installation)
{ {
vec![ vec![

View file

@ -2,7 +2,7 @@ use serde::Serialize;
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::fmt::Write; use std::fmt::Write;
use uv_cli::PythonListFormat; use uv_cli::PythonListFormat;
use uv_configuration::PreviewMode; use uv_configuration::Preview;
use uv_pep440::Version; use uv_pep440::Version;
use anyhow::Result; use anyhow::Result;
@ -65,7 +65,7 @@ pub(crate) async fn list(
python_downloads: PythonDownloads, python_downloads: PythonDownloads,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
let request = request.as_deref().map(PythonRequest::parse); let request = request.as_deref().map(PythonRequest::parse);
let base_download_request = if python_preference == PythonPreference::OnlySystem { let base_download_request = if python_preference == PythonPreference::OnlySystem {

View file

@ -8,7 +8,7 @@ use tracing::debug;
use uv_cache::Cache; use uv_cache::Cache;
use uv_client::BaseClientBuilder; use uv_client::BaseClientBuilder;
use uv_configuration::{DependencyGroupsWithDefaults, PreviewMode}; use uv_configuration::{DependencyGroupsWithDefaults, Preview};
use uv_fs::Simplified; use uv_fs::Simplified;
use uv_python::{ use uv_python::{
EnvironmentPreference, PYTHON_VERSION_FILENAME, PythonDownloads, PythonInstallation, EnvironmentPreference, PYTHON_VERSION_FILENAME, PythonDownloads, PythonInstallation,
@ -39,7 +39,7 @@ pub(crate) async fn pin(
network_settings: NetworkSettings, network_settings: NetworkSettings,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
let workspace_cache = WorkspaceCache::default(); let workspace_cache = WorkspaceCache::default();
let virtual_project = if no_project { let virtual_project = if no_project {
@ -270,7 +270,7 @@ fn warn_if_existing_pin_incompatible_with_project(
virtual_project: &VirtualProject, virtual_project: &VirtualProject,
python_preference: PythonPreference, python_preference: PythonPreference,
cache: &Cache, cache: &Cache,
preview: PreviewMode, preview: Preview,
) { ) {
// Check if the pinned version is compatible with the project. // Check if the pinned version is compatible with the project.
if let Some(pin_version) = pep440_version_from_request(pin) { if let Some(pin_version) = pep440_version_from_request(pin) {

View file

@ -11,7 +11,7 @@ use owo_colors::OwoColorize;
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use tracing::{debug, warn}; use tracing::{debug, warn};
use uv_configuration::PreviewMode; use uv_configuration::Preview;
use uv_fs::Simplified; use uv_fs::Simplified;
use uv_python::downloads::PythonDownloadRequest; use uv_python::downloads::PythonDownloadRequest;
use uv_python::managed::{ use uv_python::managed::{
@ -30,7 +30,7 @@ pub(crate) async fn uninstall(
targets: Vec<String>, targets: Vec<String>,
all: bool, all: bool,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
let installations = ManagedPythonInstallations::from_settings(install_dir)?.init()?; let installations = ManagedPythonInstallations::from_settings(install_dir)?.init()?;
@ -66,7 +66,7 @@ async fn do_uninstall(
targets: Vec<String>, targets: Vec<String>,
all: bool, all: bool,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
let start = std::time::Instant::now(); let start = std::time::Instant::now();

View file

@ -7,7 +7,7 @@ use std::{collections::BTreeSet, ffi::OsString};
use tracing::{debug, warn}; use tracing::{debug, warn};
use uv_cache::Cache; use uv_cache::Cache;
use uv_client::BaseClientBuilder; use uv_client::BaseClientBuilder;
use uv_configuration::PreviewMode; use uv_configuration::Preview;
use uv_distribution_types::Requirement; use uv_distribution_types::Requirement;
use uv_distribution_types::{InstalledDist, Name}; use uv_distribution_types::{InstalledDist, Name};
use uv_fs::Simplified; use uv_fs::Simplified;
@ -81,7 +81,7 @@ pub(crate) async fn refine_interpreter(
python_preference: PythonPreference, python_preference: PythonPreference,
python_downloads: PythonDownloads, python_downloads: PythonDownloads,
cache: &Cache, cache: &Cache,
preview: PreviewMode, preview: Preview,
) -> anyhow::Result<Option<Interpreter>, ProjectError> { ) -> anyhow::Result<Option<Interpreter>, ProjectError> {
let pip::operations::Error::Resolve(uv_resolver::ResolveError::NoSolution(no_solution_err)) = let pip::operations::Error::Resolve(uv_resolver::ResolveError::NoSolution(no_solution_err)) =
err err

View file

@ -2,12 +2,12 @@ use anstream::println;
use anyhow::Context; use anyhow::Context;
use owo_colors::OwoColorize; use owo_colors::OwoColorize;
use uv_configuration::PreviewMode; use uv_configuration::Preview;
use uv_fs::Simplified; use uv_fs::Simplified;
use uv_tool::{InstalledTools, tool_executable_dir}; use uv_tool::{InstalledTools, tool_executable_dir};
/// Show the tool directory. /// Show the tool directory.
pub(crate) fn dir(bin: bool, _preview: PreviewMode) -> anyhow::Result<()> { pub(crate) fn dir(bin: bool, _preview: Preview) -> anyhow::Result<()> {
if bin { if bin {
let executable_directory = tool_executable_dir()?; let executable_directory = tool_executable_dir()?;
println!("{}", executable_directory.simplified_display().cyan()); println!("{}", executable_directory.simplified_display().cyan());

View file

@ -8,7 +8,7 @@ use tracing::{debug, trace};
use uv_cache::{Cache, Refresh}; use uv_cache::{Cache, Refresh};
use uv_cache_info::Timestamp; use uv_cache_info::Timestamp;
use uv_client::BaseClientBuilder; use uv_client::BaseClientBuilder;
use uv_configuration::{Concurrency, Constraints, DryRun, PreviewMode, Reinstall, Upgrade}; use uv_configuration::{Concurrency, Constraints, DryRun, Preview, Reinstall, Upgrade};
use uv_distribution_types::{ use uv_distribution_types::{
NameRequirementSpecification, Requirement, RequirementSource, NameRequirementSpecification, Requirement, RequirementSource,
UnresolvedRequirementSpecification, UnresolvedRequirementSpecification,
@ -62,7 +62,7 @@ pub(crate) async fn install(
concurrency: Concurrency, concurrency: Concurrency,
cache: Cache, cache: Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()? .retries_from_env()?

View file

@ -17,7 +17,7 @@ use uv_cache_info::Timestamp;
use uv_cli::ExternalCommand; use uv_cli::ExternalCommand;
use uv_client::BaseClientBuilder; use uv_client::BaseClientBuilder;
use uv_configuration::Constraints; use uv_configuration::Constraints;
use uv_configuration::{Concurrency, PreviewMode}; use uv_configuration::{Concurrency, Preview};
use uv_distribution_types::InstalledDist; use uv_distribution_types::InstalledDist;
use uv_distribution_types::{ use uv_distribution_types::{
IndexUrl, Name, NameRequirementSpecification, Requirement, RequirementSource, IndexUrl, Name, NameRequirementSpecification, Requirement, RequirementSource,
@ -101,7 +101,7 @@ pub(crate) async fn run(
printer: Printer, printer: Printer,
env_file: Vec<PathBuf>, env_file: Vec<PathBuf>,
no_env_file: bool, no_env_file: bool,
preview: PreviewMode, preview: Preview,
) -> anyhow::Result<ExitStatus> { ) -> anyhow::Result<ExitStatus> {
/// Whether or not a path looks like a Python script based on the file extension. /// Whether or not a path looks like a Python script based on the file extension.
fn has_python_script_ext(path: &Path) -> bool { fn has_python_script_ext(path: &Path) -> bool {
@ -686,7 +686,7 @@ async fn get_or_create_environment(
concurrency: Concurrency, concurrency: Concurrency,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<(ToolRequirement, PythonEnvironment), ProjectError> { ) -> Result<(ToolRequirement, PythonEnvironment), ProjectError> {
let client_builder = BaseClientBuilder::new() let client_builder = BaseClientBuilder::new()
.retries_from_env()? .retries_from_env()?

View file

@ -7,7 +7,7 @@ use tracing::debug;
use uv_cache::Cache; use uv_cache::Cache;
use uv_client::BaseClientBuilder; use uv_client::BaseClientBuilder;
use uv_configuration::{Concurrency, Constraints, DryRun, PreviewMode}; use uv_configuration::{Concurrency, Constraints, DryRun, Preview};
use uv_distribution_types::Requirement; use uv_distribution_types::Requirement;
use uv_fs::CWD; use uv_fs::CWD;
use uv_normalize::PackageName; use uv_normalize::PackageName;
@ -47,7 +47,7 @@ pub(crate) async fn upgrade(
concurrency: Concurrency, concurrency: Concurrency,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
let installed_tools = InstalledTools::from_settings()?.init()?; let installed_tools = InstalledTools::from_settings()?.init()?;
let _lock = installed_tools.lock().await?; let _lock = installed_tools.lock().await?;
@ -221,7 +221,7 @@ async fn upgrade_tool(
filesystem: &ResolverInstallerOptions, filesystem: &ResolverInstallerOptions,
installer_metadata: bool, installer_metadata: bool,
concurrency: Concurrency, concurrency: Concurrency,
preview: PreviewMode, preview: Preview,
) -> Result<UpgradeOutcome> { ) -> Result<UpgradeOutcome> {
// Ensure the tool is installed. // Ensure the tool is installed.
let existing_tool_receipt = match installed_tools.get_tool_receipt(name) { let existing_tool_receipt = match installed_tools.get_tool_receipt(name) {

View file

@ -11,7 +11,8 @@ use uv_cache::Cache;
use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder}; use uv_client::{BaseClientBuilder, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{ use uv_configuration::{
BuildOptions, Concurrency, ConfigSettings, Constraints, DependencyGroups, IndexStrategy, BuildOptions, Concurrency, ConfigSettings, Constraints, DependencyGroups, IndexStrategy,
KeyringProviderType, NoBinary, NoBuild, PackageConfigSettings, PreviewMode, SourceStrategy, KeyringProviderType, NoBinary, NoBuild, PackageConfigSettings, Preview, PreviewFeatures,
SourceStrategy,
}; };
use uv_dispatch::{BuildDispatch, SharedState}; use uv_dispatch::{BuildDispatch, SharedState};
use uv_distribution_types::Requirement; use uv_distribution_types::Requirement;
@ -81,7 +82,7 @@ pub(crate) async fn venv(
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
relocatable: bool, relocatable: bool,
preview: PreviewMode, preview: Preview,
) -> Result<ExitStatus> { ) -> Result<ExitStatus> {
let workspace_cache = WorkspaceCache::default(); let workspace_cache = WorkspaceCache::default();
let project = if no_project { let project = if no_project {
@ -198,7 +199,7 @@ pub(crate) async fn venv(
path.user_display().cyan() path.user_display().cyan()
)?; )?;
let upgradeable = preview.is_enabled() let upgradeable = preview.is_enabled(PreviewFeatures::PYTHON_UPGRADE)
&& python_request && python_request
.as_ref() .as_ref()
.is_none_or(|request| !request.includes_patch()); .is_none_or(|request| !request.includes_patch());

View file

@ -23,9 +23,9 @@ use uv_client::Connectivity;
use uv_configuration::{ use uv_configuration::{
BuildOptions, Concurrency, ConfigSettings, DependencyGroups, DryRun, EditableMode, BuildOptions, Concurrency, ConfigSettings, DependencyGroups, DryRun, EditableMode,
ExportFormat, ExtrasSpecification, HashCheckingMode, IndexStrategy, InstallOptions, ExportFormat, ExtrasSpecification, HashCheckingMode, IndexStrategy, InstallOptions,
KeyringProviderType, NoBinary, NoBuild, PackageConfigSettings, PreviewMode, KeyringProviderType, NoBinary, NoBuild, PackageConfigSettings, Preview, ProjectBuildBackend,
ProjectBuildBackend, Reinstall, RequiredVersion, SourceStrategy, TargetTriple, TrustedHost, Reinstall, RequiredVersion, SourceStrategy, TargetTriple, TrustedHost, TrustedPublishing,
TrustedPublishing, Upgrade, VersionControlSystem, Upgrade, VersionControlSystem,
}; };
use uv_distribution_types::{DependencyMetadata, Index, IndexLocations, IndexUrl, Requirement}; use uv_distribution_types::{DependencyMetadata, Index, IndexLocations, IndexUrl, Requirement};
use uv_install_wheel::LinkMode; use uv_install_wheel::LinkMode;
@ -63,7 +63,7 @@ pub(crate) struct GlobalSettings {
pub(crate) network_settings: NetworkSettings, pub(crate) network_settings: NetworkSettings,
pub(crate) concurrency: Concurrency, pub(crate) concurrency: Concurrency,
pub(crate) show_settings: bool, pub(crate) show_settings: bool,
pub(crate) preview: PreviewMode, pub(crate) preview: Preview,
pub(crate) python_preference: PythonPreference, pub(crate) python_preference: PythonPreference,
pub(crate) python_downloads: PythonDownloads, pub(crate) python_downloads: PythonDownloads,
pub(crate) no_progress: bool, pub(crate) no_progress: bool,
@ -117,10 +117,12 @@ impl GlobalSettings {
.unwrap_or_else(Concurrency::threads), .unwrap_or_else(Concurrency::threads),
}, },
show_settings: args.show_settings, show_settings: args.show_settings,
preview: PreviewMode::from( preview: Preview::from_args(
flag(args.preview, args.no_preview, "preview") flag(args.preview, args.no_preview, "preview")
.combine(workspace.and_then(|workspace| workspace.globals.preview)) .combine(workspace.and_then(|workspace| workspace.globals.preview))
.unwrap_or(false), .unwrap_or(false),
args.no_preview,
&args.preview_features,
), ),
python_preference, python_preference,
python_downloads: flag( python_downloads: flag(

View file

@ -21,7 +21,7 @@ use regex::Regex;
use tokio::io::AsyncWriteExt; use tokio::io::AsyncWriteExt;
use uv_cache::Cache; use uv_cache::Cache;
use uv_configuration::PreviewMode; use uv_configuration::Preview;
use uv_fs::Simplified; use uv_fs::Simplified;
use uv_python::managed::ManagedPythonInstallations; use uv_python::managed::ManagedPythonInstallations;
use uv_python::{ use uv_python::{
@ -1505,7 +1505,7 @@ pub fn python_installations_for_versions(
EnvironmentPreference::OnlySystem, EnvironmentPreference::OnlySystem,
PythonPreference::Managed, PythonPreference::Managed,
&cache, &cache,
PreviewMode::Disabled, Preview::default(),
) { ) {
python.into_interpreter().sys_executable().to_owned() python.into_interpreter().sys_executable().to_owned()
} else { } else {

View file

@ -13021,7 +13021,7 @@ fn add_bounds() -> Result<()> {
----- stdout ----- ----- stdout -----
----- stderr ----- ----- stderr -----
warning: The bounds option is in preview and may change in any future release. warning: The `bounds` option is in preview and may change in any future release. Pass `--preview-features add-bounds` to disable this warning.
Resolved 2 packages in [TIME] Resolved 2 packages in [TIME]
Prepared 1 package in [TIME] Prepared 1 package in [TIME]
Installed 1 package in [TIME] Installed 1 package in [TIME]
@ -13061,7 +13061,7 @@ fn add_bounds() -> Result<()> {
----- stdout ----- ----- stdout -----
----- stderr ----- ----- stderr -----
warning: The bounds option is in preview and may change in any future release. warning: The `bounds` option is in preview and may change in any future release. Pass `--preview-features add-bounds` to disable this warning.
Resolved 4 packages in [TIME] Resolved 4 packages in [TIME]
Prepared 2 packages in [TIME] Prepared 2 packages in [TIME]
Installed 2 packages in [TIME] Installed 2 packages in [TIME]

View file

@ -630,14 +630,14 @@ fn python_install_preview() {
"###); "###);
// Should be a no-op when already installed // Should be a no-op when already installed
uv_snapshot!(context.filters(), context.python_install().arg("--preview"), @r###" uv_snapshot!(context.filters(), context.python_install().arg("--preview"), @r"
success: true success: true
exit_code: 0 exit_code: 0
----- stdout ----- ----- stdout -----
----- stderr ----- ----- stderr -----
Python is already installed. Use `uv python install <request>` to install another version. Python is already installed. Use `uv python install <request>` to install another version.
"###); ");
// You can opt-in to a reinstall // You can opt-in to a reinstall
uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("--reinstall"), @r" uv_snapshot!(context.filters(), context.python_install().arg("--preview").arg("--reinstall"), @r"
@ -1260,7 +1260,7 @@ fn python_install_default() {
----- stdout ----- ----- stdout -----
----- stderr ----- ----- stderr -----
warning: The `--default` option is experimental and may change without warning. Pass `--preview` to disable this warning warning: The `--default` option is experimental and may change without warning. Pass `--preview-features python-install-default` to disable this warning
Installed Python 3.13.5 in [TIME] Installed Python 3.13.5 in [TIME]
+ cpython-3.13.5-[PLATFORM] (python, python3) + cpython-3.13.5-[PLATFORM] (python, python3)
"); ");
@ -1294,7 +1294,7 @@ fn python_install_default() {
----- stdout ----- ----- stdout -----
----- stderr ----- ----- stderr -----
warning: The `--default` option is experimental and may change without warning. Pass `--preview` to disable this warning warning: The `--default` option is experimental and may change without warning. Pass `--preview-features python-install-default` to disable this warning
Installed Python 3.13.5 in [TIME] Installed Python 3.13.5 in [TIME]
+ cpython-3.13.5-[PLATFORM] (python, python3, python3.13) + cpython-3.13.5-[PLATFORM] (python, python3, python3.13)
"); ");
@ -1379,7 +1379,7 @@ fn python_install_default() {
----- stdout ----- ----- stdout -----
----- stderr ----- ----- stderr -----
warning: The `--default` option is experimental and may change without warning. Pass `--preview` to disable this warning warning: The `--default` option is experimental and may change without warning. Pass `--preview-features python-install-default` to disable this warning
error: The `--default` flag cannot be used with multiple targets error: The `--default` flag cannot be used with multiple targets
"); ");
@ -1390,7 +1390,7 @@ fn python_install_default() {
----- stdout ----- ----- stdout -----
----- stderr ----- ----- stderr -----
warning: The `--default` option is experimental and may change without warning. Pass `--preview` to disable this warning warning: The `--default` option is experimental and may change without warning. Pass `--preview-features python-install-default` to disable this warning
Installed Python 3.12.11 in [TIME] Installed Python 3.12.11 in [TIME]
+ cpython-3.12.11-[PLATFORM] (python, python3, python3.12) + cpython-3.12.11-[PLATFORM] (python, python3, python3.12)
"); ");

File diff suppressed because it is too large Load diff

View file

@ -306,6 +306,10 @@ Equivalent to the `--prerelease` command-line argument. For example, if set to
Equivalent to the `--preview` argument. Enables preview mode. Equivalent to the `--preview` argument. Enables preview mode.
### `UV_PREVIEW_FEATURES`
Equivalent to the `--preview-features` argument. Enables specific preview features.
### `UV_PROJECT` ### `UV_PROJECT`
Equivalent to the `--project` command-line argument. Equivalent to the `--project` command-line argument.