From b5605658dedc9d47f37326646381c6dffaebf482 Mon Sep 17 00:00:00 2001 From: Yiqiuuu Date: Sun, 26 Oct 2025 22:43:08 -0400 Subject: [PATCH 01/10] allow toml pass preview features in list --- crates/uv-settings/src/lib.rs | 4 + crates/uv-settings/src/settings.rs | 14 + crates/uv/src/settings.rs | 49 +- crates/uv/tests/it/show_settings.rs | 802 ++++++++++++++++++++++++++++ docs/concepts/preview.md | 24 + docs/reference/settings.md | 32 ++ uv.schema.json | 10 + 7 files changed, 928 insertions(+), 7 deletions(-) diff --git a/crates/uv-settings/src/lib.rs b/crates/uv-settings/src/lib.rs index c9fcc16b714b9..68dff0fbc7e8d 100644 --- a/crates/uv-settings/src/lib.rs +++ b/crates/uv-settings/src/lib.rs @@ -296,6 +296,7 @@ fn warn_uv_toml_masked_fields(options: &Options) { no_cache, cache_dir, preview, + preview_features, python_preference, python_downloads, concurrent_downloads, @@ -387,6 +388,9 @@ fn warn_uv_toml_masked_fields(options: &Options) { if preview.is_some() { masked_fields.push("preview"); } + if preview_features.is_some() { + masked_fields.push("preview-features"); + } if python_preference.is_some() { masked_fields.push("python-preference"); } diff --git a/crates/uv-settings/src/settings.rs b/crates/uv-settings/src/settings.rs index 6042af68da881..69e38f0bb953f 100644 --- a/crates/uv-settings/src/settings.rs +++ b/crates/uv-settings/src/settings.rs @@ -254,6 +254,17 @@ pub struct GlobalOptions { "# )] pub preview: Option, + /// Enable experimental preview features. + /// Preview features may change without warning. + /// Use comma-separated values or pass multiple times to enable multiple features. + #[option( + default = "[]", + value_type = "list[str]", + example = r#" + preview-features = ["json-output", "format"] + "# + )] + pub preview_features: Option>, /// Whether to prefer using Python installations that are already present on the system, or /// those that are downloaded and installed by uv. #[option( @@ -2047,6 +2058,7 @@ pub struct OptionsWire { no_cache: Option, cache_dir: Option, preview: Option, + preview_features: Option>, python_preference: Option, python_downloads: Option, concurrent_downloads: Option, @@ -2140,6 +2152,7 @@ impl From for Options { no_cache, cache_dir, preview, + preview_features, python_preference, python_downloads, python_install_mirror, @@ -2210,6 +2223,7 @@ impl From for Options { no_cache, cache_dir, preview, + preview_features, python_preference, python_downloads, concurrent_downloads, diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs index 25d11cab7be9f..f776b87c6b065 100644 --- a/crates/uv/src/settings.rs +++ b/crates/uv/src/settings.rs @@ -137,13 +137,48 @@ impl GlobalSettings { .unwrap_or_else(Concurrency::threads), }, show_settings: args.show_settings, - preview: Preview::from_args( - flag(args.preview, args.no_preview, "preview") - .combine(workspace.and_then(|workspace| workspace.globals.preview)) - .unwrap_or(false), - args.no_preview, - &args.preview_features, - ), + preview: { + // Start with command line features (highest precedence) + let mut all_preview_features = args.preview_features.clone(); + + // Add environment variable features if no command line features were specified + if all_preview_features.is_empty() { + if let Ok(env_value) = std::env::var(EnvVars::UV_PREVIEW_FEATURES) { + let env_features = env_value + .split(',') + .map(|feature| feature.trim().to_string()) + .filter(|feature| !feature.is_empty()) + .collect::>(); + + for feature in env_features { + if let Ok(parsed) = feature.parse::() { + all_preview_features.push(parsed); + } + } + } + } + + // Add configuration features if no command line or environment features were specified + if all_preview_features.is_empty() { + if let Some(config_features) = workspace + .and_then(|workspace| workspace.globals.preview_features.as_ref()) + { + for feature in config_features { + if let Ok(parsed) = feature.parse::() { + all_preview_features.push(parsed); + } + } + } + } + + Preview::from_args( + flag(args.preview, args.no_preview, "preview") + .combine(workspace.and_then(|workspace| workspace.globals.preview)) + .unwrap_or(false), + args.no_preview, + &all_preview_features, + ) + }, python_preference, python_downloads: flag( args.allow_python_downloads, diff --git a/crates/uv/tests/it/show_settings.rs b/crates/uv/tests/it/show_settings.rs index 9ee19e5c41847..01eddc6e53ad9 100644 --- a/crates/uv/tests/it/show_settings.rs +++ b/crates/uv/tests/it/show_settings.rs @@ -2,6 +2,7 @@ use std::path::Path; use std::process::Command; use assert_fs::prelude::*; +use indoc::indoc; use uv_static::EnvVars; use crate::common::{TestContext, uv_snapshot}; @@ -8423,6 +8424,807 @@ fn preview_features() { ); } +/// Test preview features configuration from pyproject.toml +#[test] +#[cfg_attr( + windows, + ignore = "Configuration tests are not yet supported on Windows" +)] +fn preview_features_from_pyproject_toml() { + let context = TestContext::new("3.12"); + + let pyproject_toml = context.temp_dir.child("pyproject.toml"); + pyproject_toml.write_str(indoc! {r#" + [tool.uv] + preview-features = ["json-output", "format"] + "#}).unwrap(); + + uv_snapshot!(context.filters(), context.version().arg("--show-settings"), @r#" + success: true + exit_code: 0 + ----- stdout ----- + GlobalSettings { + required_version: None, + quiet: 0, + verbose: 0, + color: Never, + network_settings: NetworkSettings { + connectivity: Online, + native_tls: false, + allow_insecure_host: [], + timeout: [TIME], + retries: 3, + }, + concurrency: Concurrency { + downloads: 50, + builds: 12, + installs: 12, + }, + show_settings: true, + preview: Preview { + flags: PreviewFeatures( + JSON_OUTPUT | FORMAT, + ), + }, + python_preference: Managed, + python_downloads: Never, + no_progress: false, + installer_metadata: true, + } + CacheSettings { + no_cache: false, + cache_dir: Some( + "[CACHE_DIR]/", + ), + } + VersionSettings { + value: None, + bump: [], + short: false, + output_format: Text, + dry_run: false, + lock_check: Disabled, + frozen: false, + active: None, + no_sync: false, + package: None, + python: None, + install_mirrors: PythonInstallMirrors { + python_install_mirror: None, + pypy_install_mirror: None, + python_downloads_json_url: None, + }, + refresh: None( + Timestamp( + SystemTime { + tv_sec: [TIME], + tv_nsec: [TIME], + }, + ), + ), + settings: ResolverInstallerSettings { + resolver: ResolverSettings { + build_options: BuildOptions { + no_binary: None, + no_build: None, + }, + config_setting: ConfigSettings( + {}, + ), + config_settings_package: PackageConfigSettings( + {}, + ), + dependency_metadata: DependencyMetadata( + {}, + ), + exclude_newer: ExcludeNewer { + global: Some( + ExcludeNewerTimestamp( + 2024-03-25T00:00:00Z, + ), + ), + package: ExcludeNewerPackage( + {}, + ), + }, + fork_strategy: RequiresPython, + index_locations: IndexLocations { + indexes: [], + flat_index: [], + no_index: false, + }, + index_strategy: FirstIndex, + keyring_provider: Disabled, + link_mode: Clone, + build_isolation: Isolate, + extra_build_dependencies: ExtraBuildDependencies( + {}, + ), + extra_build_variables: ExtraBuildVariables( + {}, + ), + prerelease: IfNecessaryOrExplicit, + resolution: Highest, + sources: Enabled, + upgrade: None, + }, + compile_bytecode: false, + reinstall: None, + }, + } + + ----- stderr ----- + "# + ); +} + +/// Test preview features configuration from uv.toml +#[test] +#[cfg_attr( + windows, + ignore = "Configuration tests are not yet supported on Windows" +)] +fn preview_features_from_uv_toml() { + let context = TestContext::new("3.12"); + + let uv_toml = context.temp_dir.child("uv.toml"); + uv_toml.write_str(indoc! {r#" + preview-features = ["pylock", "add-bounds"] + "#}).unwrap(); + + uv_snapshot!(context.filters(), context.version().arg("--show-settings"), @r#" + success: true + exit_code: 0 + ----- stdout ----- + GlobalSettings { + required_version: None, + quiet: 0, + verbose: 0, + color: Never, + network_settings: NetworkSettings { + connectivity: Online, + native_tls: false, + allow_insecure_host: [], + timeout: [TIME], + retries: 3, + }, + concurrency: Concurrency { + downloads: 50, + builds: 12, + installs: 12, + }, + show_settings: true, + preview: Preview { + flags: PreviewFeatures( + PYLOCK | ADD_BOUNDS, + ), + }, + python_preference: Managed, + python_downloads: Never, + no_progress: false, + installer_metadata: true, + } + CacheSettings { + no_cache: false, + cache_dir: Some( + "[CACHE_DIR]/", + ), + } + VersionSettings { + value: None, + bump: [], + short: false, + output_format: Text, + dry_run: false, + lock_check: Disabled, + frozen: false, + active: None, + no_sync: false, + package: None, + python: None, + install_mirrors: PythonInstallMirrors { + python_install_mirror: None, + pypy_install_mirror: None, + python_downloads_json_url: None, + }, + refresh: None( + Timestamp( + SystemTime { + tv_sec: [TIME], + tv_nsec: [TIME], + }, + ), + ), + settings: ResolverInstallerSettings { + resolver: ResolverSettings { + build_options: BuildOptions { + no_binary: None, + no_build: None, + }, + config_setting: ConfigSettings( + {}, + ), + config_settings_package: PackageConfigSettings( + {}, + ), + dependency_metadata: DependencyMetadata( + {}, + ), + exclude_newer: ExcludeNewer { + global: Some( + ExcludeNewerTimestamp( + 2024-03-25T00:00:00Z, + ), + ), + package: ExcludeNewerPackage( + {}, + ), + }, + fork_strategy: RequiresPython, + index_locations: IndexLocations { + indexes: [], + flat_index: [], + no_index: false, + }, + index_strategy: FirstIndex, + keyring_provider: Disabled, + link_mode: Clone, + build_isolation: Isolate, + extra_build_dependencies: ExtraBuildDependencies( + {}, + ), + extra_build_variables: ExtraBuildVariables( + {}, + ), + prerelease: IfNecessaryOrExplicit, + resolution: Highest, + sources: Enabled, + upgrade: None, + }, + compile_bytecode: false, + reinstall: None, + }, + } + + ----- stderr ----- + "# + ); +} + +/// Test precedence: command line overrides configuration +#[test] +#[cfg_attr( + windows, + ignore = "Configuration tests are not yet supported on Windows" +)] +fn preview_features_precedence_command_line_over_config() { + let context = TestContext::new("3.12"); + + let pyproject_toml = context.temp_dir.child("pyproject.toml"); + pyproject_toml.write_str(indoc! {r#" + [tool.uv] + preview-features = ["json-output", "format"] + "#}).unwrap(); + + // Command line should override configuration + uv_snapshot!(context.filters(), context.version().arg("--show-settings").arg("--preview-features").arg("pylock"), @r#" + success: true + exit_code: 0 + ----- stdout ----- + GlobalSettings { + required_version: None, + quiet: 0, + verbose: 0, + color: Never, + network_settings: NetworkSettings { + connectivity: Online, + native_tls: false, + allow_insecure_host: [], + timeout: [TIME], + retries: 3, + }, + concurrency: Concurrency { + downloads: 50, + builds: 12, + installs: 12, + }, + show_settings: true, + preview: Preview { + flags: PreviewFeatures( + PYLOCK, + ), + }, + python_preference: Managed, + python_downloads: Never, + no_progress: false, + installer_metadata: true, + } + CacheSettings { + no_cache: false, + cache_dir: Some( + "[CACHE_DIR]/", + ), + } + VersionSettings { + value: None, + bump: [], + short: false, + output_format: Text, + dry_run: false, + lock_check: Disabled, + frozen: false, + active: None, + no_sync: false, + package: None, + python: None, + install_mirrors: PythonInstallMirrors { + python_install_mirror: None, + pypy_install_mirror: None, + python_downloads_json_url: None, + }, + refresh: None( + Timestamp( + SystemTime { + tv_sec: [TIME], + tv_nsec: [TIME], + }, + ), + ), + settings: ResolverInstallerSettings { + resolver: ResolverSettings { + build_options: BuildOptions { + no_binary: None, + no_build: None, + }, + config_setting: ConfigSettings( + {}, + ), + config_settings_package: PackageConfigSettings( + {}, + ), + dependency_metadata: DependencyMetadata( + {}, + ), + exclude_newer: ExcludeNewer { + global: Some( + ExcludeNewerTimestamp( + 2024-03-25T00:00:00Z, + ), + ), + package: ExcludeNewerPackage( + {}, + ), + }, + fork_strategy: RequiresPython, + index_locations: IndexLocations { + indexes: [], + flat_index: [], + no_index: false, + }, + index_strategy: FirstIndex, + keyring_provider: Disabled, + link_mode: Clone, + build_isolation: Isolate, + extra_build_dependencies: ExtraBuildDependencies( + {}, + ), + extra_build_variables: ExtraBuildVariables( + {}, + ), + prerelease: IfNecessaryOrExplicit, + resolution: Highest, + sources: Enabled, + upgrade: None, + }, + compile_bytecode: false, + reinstall: None, + }, + } + + ----- stderr ----- + "# + ); +} + +/// Test precedence: command line overrides environment variable +#[test] +#[cfg_attr( + windows, + ignore = "Configuration tests are not yet supported on Windows" +)] +fn preview_features_precedence_command_line_over_env() { + let context = TestContext::new("3.12"); + + // Command line should override environment variable + uv_snapshot!(context.filters(), context.version().arg("--show-settings").arg("--preview-features").arg("add-bounds").env(EnvVars::UV_PREVIEW_FEATURES, "json-output,format"), @r#" + success: true + exit_code: 0 + ----- stdout ----- + GlobalSettings { + required_version: None, + quiet: 0, + verbose: 0, + color: Never, + network_settings: NetworkSettings { + connectivity: Online, + native_tls: false, + allow_insecure_host: [], + timeout: [TIME], + retries: 3, + }, + concurrency: Concurrency { + downloads: 50, + builds: 12, + installs: 12, + }, + show_settings: true, + preview: Preview { + flags: PreviewFeatures( + ADD_BOUNDS, + ), + }, + python_preference: Managed, + python_downloads: Never, + no_progress: false, + installer_metadata: true, + } + CacheSettings { + no_cache: false, + cache_dir: Some( + "[CACHE_DIR]/", + ), + } + VersionSettings { + value: None, + bump: [], + short: false, + output_format: Text, + dry_run: false, + lock_check: Disabled, + frozen: false, + active: None, + no_sync: false, + package: None, + python: None, + install_mirrors: PythonInstallMirrors { + python_install_mirror: None, + pypy_install_mirror: None, + python_downloads_json_url: None, + }, + refresh: None( + Timestamp( + SystemTime { + tv_sec: [TIME], + tv_nsec: [TIME], + }, + ), + ), + settings: ResolverInstallerSettings { + resolver: ResolverSettings { + build_options: BuildOptions { + no_binary: None, + no_build: None, + }, + config_setting: ConfigSettings( + {}, + ), + config_settings_package: PackageConfigSettings( + {}, + ), + dependency_metadata: DependencyMetadata( + {}, + ), + exclude_newer: ExcludeNewer { + global: Some( + ExcludeNewerTimestamp( + 2024-03-25T00:00:00Z, + ), + ), + package: ExcludeNewerPackage( + {}, + ), + }, + fork_strategy: RequiresPython, + index_locations: IndexLocations { + indexes: [], + flat_index: [], + no_index: false, + }, + index_strategy: FirstIndex, + keyring_provider: Disabled, + link_mode: Clone, + build_isolation: Isolate, + extra_build_dependencies: ExtraBuildDependencies( + {}, + ), + extra_build_variables: ExtraBuildVariables( + {}, + ), + prerelease: IfNecessaryOrExplicit, + resolution: Highest, + sources: Enabled, + upgrade: None, + }, + compile_bytecode: false, + reinstall: None, + }, + } + + ----- stderr ----- + "# + ); +} + +/// Test that preview = true still works and enables all features +#[test] +#[cfg_attr( + windows, + ignore = "Configuration tests are not yet supported on Windows" +)] +fn preview_boolean_still_works() { + let context = TestContext::new("3.12"); + + let pyproject_toml = context.temp_dir.child("pyproject.toml"); + pyproject_toml.write_str(indoc! {r#" + [tool.uv] + preview = true + "#}).unwrap(); + + uv_snapshot!(context.filters(), context.version().arg("--show-settings"), @r#" + success: true + exit_code: 0 + ----- stdout ----- + GlobalSettings { + required_version: None, + quiet: 0, + verbose: 0, + color: Never, + network_settings: NetworkSettings { + connectivity: Online, + native_tls: false, + allow_insecure_host: [], + timeout: [TIME], + retries: 3, + }, + concurrency: Concurrency { + downloads: 50, + builds: 12, + installs: 12, + }, + show_settings: true, + preview: Preview { + flags: PreviewFeatures( + PYTHON_INSTALL_DEFAULT | PYTHON_UPGRADE | JSON_OUTPUT | PYLOCK | ADD_BOUNDS | PACKAGE_CONFLICTS | EXTRA_BUILD_DEPENDENCIES | DETECT_MODULE_CONFLICTS | FORMAT | NATIVE_AUTH | S3_ENDPOINT, + ), + }, + python_preference: Managed, + python_downloads: Never, + no_progress: false, + installer_metadata: true, + } + CacheSettings { + no_cache: false, + cache_dir: Some( + "[CACHE_DIR]/", + ), + } + VersionSettings { + value: None, + bump: [], + short: false, + output_format: Text, + dry_run: false, + lock_check: Disabled, + frozen: false, + active: None, + no_sync: false, + package: None, + python: None, + install_mirrors: PythonInstallMirrors { + python_install_mirror: None, + pypy_install_mirror: None, + python_downloads_json_url: None, + }, + refresh: None( + Timestamp( + SystemTime { + tv_sec: [TIME], + tv_nsec: [TIME], + }, + ), + ), + settings: ResolverInstallerSettings { + resolver: ResolverSettings { + build_options: BuildOptions { + no_binary: None, + no_build: None, + }, + config_setting: ConfigSettings( + {}, + ), + config_settings_package: PackageConfigSettings( + {}, + ), + dependency_metadata: DependencyMetadata( + {}, + ), + exclude_newer: ExcludeNewer { + global: Some( + ExcludeNewerTimestamp( + 2024-03-25T00:00:00Z, + ), + ), + package: ExcludeNewerPackage( + {}, + ), + }, + fork_strategy: RequiresPython, + index_locations: IndexLocations { + indexes: [], + flat_index: [], + no_index: false, + }, + index_strategy: FirstIndex, + keyring_provider: Disabled, + link_mode: Clone, + build_isolation: Isolate, + extra_build_dependencies: ExtraBuildDependencies( + {}, + ), + extra_build_variables: ExtraBuildVariables( + {}, + ), + prerelease: IfNecessaryOrExplicit, + resolution: Highest, + sources: Enabled, + upgrade: None, + }, + compile_bytecode: false, + reinstall: None, + }, + } + + ----- stderr ----- + "# + ); +} + +/// Test that no-preview overrides everything +#[test] +#[cfg_attr( + windows, + ignore = "Configuration tests are not yet supported on Windows" +)] +fn no_preview_overrides_everything() { + let context = TestContext::new("3.12"); + + let pyproject_toml = context.temp_dir.child("pyproject.toml"); + pyproject_toml.write_str(indoc! {r#" + [tool.uv] + preview = true + preview-features = ["json-output", "format"] + "#}).unwrap(); + + // --no-preview should disable everything regardless of config + uv_snapshot!(context.filters(), context.version().arg("--show-settings").arg("--no-preview"), @r#" + success: true + exit_code: 0 + ----- stdout ----- + GlobalSettings { + required_version: None, + quiet: 0, + verbose: 0, + color: Never, + network_settings: NetworkSettings { + connectivity: Online, + native_tls: false, + allow_insecure_host: [], + timeout: [TIME], + retries: 3, + }, + concurrency: Concurrency { + downloads: 50, + builds: 12, + installs: 12, + }, + show_settings: true, + preview: Preview { + flags: PreviewFeatures( + 0x0, + ), + }, + python_preference: Managed, + python_downloads: Never, + no_progress: false, + installer_metadata: true, + } + CacheSettings { + no_cache: false, + cache_dir: Some( + "[CACHE_DIR]/", + ), + } + VersionSettings { + value: None, + bump: [], + short: false, + output_format: Text, + dry_run: false, + lock_check: Disabled, + frozen: false, + active: None, + no_sync: false, + package: None, + python: None, + install_mirrors: PythonInstallMirrors { + python_install_mirror: None, + pypy_install_mirror: None, + python_downloads_json_url: None, + }, + refresh: None( + Timestamp( + SystemTime { + tv_sec: [TIME], + tv_nsec: [TIME], + }, + ), + ), + settings: ResolverInstallerSettings { + resolver: ResolverSettings { + build_options: BuildOptions { + no_binary: None, + no_build: None, + }, + config_setting: ConfigSettings( + {}, + ), + config_settings_package: PackageConfigSettings( + {}, + ), + dependency_metadata: DependencyMetadata( + {}, + ), + exclude_newer: ExcludeNewer { + global: Some( + ExcludeNewerTimestamp( + 2024-03-25T00:00:00Z, + ), + ), + package: ExcludeNewerPackage( + {}, + ), + }, + fork_strategy: RequiresPython, + index_locations: IndexLocations { + indexes: [], + flat_index: [], + no_index: false, + }, + index_strategy: FirstIndex, + keyring_provider: Disabled, + link_mode: Clone, + build_isolation: Isolate, + extra_build_dependencies: ExtraBuildDependencies( + {}, + ), + extra_build_variables: ExtraBuildVariables( + {}, + ), + prerelease: IfNecessaryOrExplicit, + resolution: Highest, + sources: Enabled, + upgrade: None, + }, + compile_bytecode: false, + reinstall: None, + }, + } + + ----- stderr ----- + "# + ); +} + /// Track the interactions between `upgrade` and `upgrade-package` across the `uv pip` CLI and a /// configuration file. #[test] diff --git a/docs/concepts/preview.md b/docs/concepts/preview.md index effb389a89e36..a6bacb7843f73 100644 --- a/docs/concepts/preview.md +++ b/docs/concepts/preview.md @@ -41,8 +41,32 @@ The `UV_PREVIEW_FEATURES` environment variable can be used similarly, e.g.: $ UV_PREVIEW_FEATURES=foo,bar uv run ... ``` +Alternatively, preview features can be configured in `pyproject.toml` or `uv.toml`: + +```toml +[tool.uv] +preview-features = ["json-output", "format"] +``` + +Or, all preview features can be enabled with: + +```toml +[tool.uv] +preview = true +``` + For backwards compatibility, enabling preview features that do not exist will warn, but not error. +## Configuration precedence + +When multiple preview configuration methods are used, the following precedence applies (highest to lowest): + +1. Command line flags (`--no-preview`, `--preview`, `--preview-features`) +2. Environment variables (`UV_PREVIEW`, `UV_PREVIEW_FEATURES`) +3. Configuration files (`pyproject.toml`, `uv.toml`) + +For example, if you set `preview = true` in configuration but use `--no-preview` on the command line, preview features will be disabled. + ## Using preview features Often, preview features can be used without changing any preview settings if the behavior change is diff --git a/docs/reference/settings.md b/docs/reference/settings.md index 9249d47b5e85a..09ce8ce67fe1a 100644 --- a/docs/reference/settings.md +++ b/docs/reference/settings.md @@ -1814,6 +1814,38 @@ Whether to enable experimental, preview features. --- +### [`preview-features`](#preview-features) {: #preview-features } + +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`, `package-conflicts`, `extra-build-dependencies`, +`detect-module-conflicts`, `format`, `native-auth`, `s3-endpoint`. + +**Default value**: `[]` + +**Type**: `list[str]` + +**Example usage**: + +=== "pyproject.toml" + + ```toml + [tool.uv] + preview-features = ["json-output", "format"] + ``` +=== "uv.toml" + + ```toml + preview-features = ["json-output", "format"] + ``` + +--- + ### [`publish-url`](#publish-url) {: #publish-url } The URL for publishing packages to the Python package index (by default: diff --git a/uv.schema.json b/uv.schema.json index a37f6081985d6..c6c1d9235c4d7 100644 --- a/uv.schema.json +++ b/uv.schema.json @@ -471,6 +471,16 @@ "null" ] }, + "preview-features": { + "description": "Enable experimental preview features.\n\nPreview features may change without warning.\n\nUse comma-separated values or pass multiple times to enable multiple features.\n\nThe following features are available: `python-install-default`, `python-upgrade`,\n`json-output`, `pylock`, `add-bounds`, `package-conflicts`, `extra-build-dependencies`,\n`detect-module-conflicts`, `format`, `native-auth`, `s3-endpoint`.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, "publish-url": { "description": "The URL for publishing packages to the Python package index (by default:\n).", "anyOf": [ From 0a67b7481c42a60af5465a9830d9a98c4d1035ba Mon Sep 17 00:00:00 2001 From: Yiqiuuu Date: Sun, 26 Oct 2025 23:39:17 -0400 Subject: [PATCH 02/10] lint --- crates/uv/tests/it/show_settings.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/uv/tests/it/show_settings.rs b/crates/uv/tests/it/show_settings.rs index 01eddc6e53ad9..7f4886f73f780 100644 --- a/crates/uv/tests/it/show_settings.rs +++ b/crates/uv/tests/it/show_settings.rs @@ -8965,10 +8965,10 @@ fn preview_boolean_still_works() { let context = TestContext::new("3.12"); let pyproject_toml = context.temp_dir.child("pyproject.toml"); - pyproject_toml.write_str(indoc! {r#" + pyproject_toml.write_str(indoc! {r" [tool.uv] preview = true - "#}).unwrap(); + "}).unwrap(); uv_snapshot!(context.filters(), context.version().arg("--show-settings"), @r#" success: true From 3ba09e6db7ce0e4496c6d7f4ce6dc9fbfde00bc9 Mon Sep 17 00:00:00 2001 From: Yiqiuuu Date: Mon, 27 Oct 2025 19:24:16 -0400 Subject: [PATCH 03/10] lint --- crates/uv/src/settings.rs | 4 ++-- crates/uv/tests/it/show_settings.rs | 30 +++++++++++++++++++---------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs index f776b87c6b065..6902c4fcf29f2 100644 --- a/crates/uv/src/settings.rs +++ b/crates/uv/src/settings.rs @@ -160,8 +160,8 @@ impl GlobalSettings { // Add configuration features if no command line or environment features were specified if all_preview_features.is_empty() { - if let Some(config_features) = workspace - .and_then(|workspace| workspace.globals.preview_features.as_ref()) + if let Some(config_features) = + workspace.and_then(|workspace| workspace.globals.preview_features.as_ref()) { for feature in config_features { if let Ok(parsed) = feature.parse::() { diff --git a/crates/uv/tests/it/show_settings.rs b/crates/uv/tests/it/show_settings.rs index 7f4886f73f780..05e387d5f60f3 100644 --- a/crates/uv/tests/it/show_settings.rs +++ b/crates/uv/tests/it/show_settings.rs @@ -8434,10 +8434,12 @@ fn preview_features_from_pyproject_toml() { let context = TestContext::new("3.12"); let pyproject_toml = context.temp_dir.child("pyproject.toml"); - pyproject_toml.write_str(indoc! {r#" + pyproject_toml + .write_str(indoc! {r#" [tool.uv] preview-features = ["json-output", "format"] - "#}).unwrap(); + "#}) + .unwrap(); uv_snapshot!(context.filters(), context.version().arg("--show-settings"), @r#" success: true @@ -8568,9 +8570,11 @@ fn preview_features_from_uv_toml() { let context = TestContext::new("3.12"); let uv_toml = context.temp_dir.child("uv.toml"); - uv_toml.write_str(indoc! {r#" + uv_toml + .write_str(indoc! {r#" preview-features = ["pylock", "add-bounds"] - "#}).unwrap(); + "#}) + .unwrap(); uv_snapshot!(context.filters(), context.version().arg("--show-settings"), @r#" success: true @@ -8701,10 +8705,12 @@ fn preview_features_precedence_command_line_over_config() { let context = TestContext::new("3.12"); let pyproject_toml = context.temp_dir.child("pyproject.toml"); - pyproject_toml.write_str(indoc! {r#" + pyproject_toml + .write_str(indoc! {r#" [tool.uv] preview-features = ["json-output", "format"] - "#}).unwrap(); + "#}) + .unwrap(); // Command line should override configuration uv_snapshot!(context.filters(), context.version().arg("--show-settings").arg("--preview-features").arg("pylock"), @r#" @@ -8965,10 +8971,12 @@ fn preview_boolean_still_works() { let context = TestContext::new("3.12"); let pyproject_toml = context.temp_dir.child("pyproject.toml"); - pyproject_toml.write_str(indoc! {r" + pyproject_toml + .write_str(indoc! {r" [tool.uv] preview = true - "}).unwrap(); + "}) + .unwrap(); uv_snapshot!(context.filters(), context.version().arg("--show-settings"), @r#" success: true @@ -9099,11 +9107,13 @@ fn no_preview_overrides_everything() { let context = TestContext::new("3.12"); let pyproject_toml = context.temp_dir.child("pyproject.toml"); - pyproject_toml.write_str(indoc! {r#" + pyproject_toml + .write_str(indoc! {r#" [tool.uv] preview = true preview-features = ["json-output", "format"] - "#}).unwrap(); + "#}) + .unwrap(); // --no-preview should disable everything regardless of config uv_snapshot!(context.filters(), context.version().arg("--show-settings").arg("--no-preview"), @r#" From c3258f198e6bf77a6bafc52ed075d57907ede526 Mon Sep 17 00:00:00 2001 From: Yiqiuuu Date: Mon, 27 Oct 2025 21:23:47 -0400 Subject: [PATCH 04/10] run cargo dev generate-json-schema --- uv.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uv.schema.json b/uv.schema.json index c6c1d9235c4d7..0169cbd477994 100644 --- a/uv.schema.json +++ b/uv.schema.json @@ -472,7 +472,7 @@ ] }, "preview-features": { - "description": "Enable experimental preview features.\n\nPreview features may change without warning.\n\nUse comma-separated values or pass multiple times to enable multiple features.\n\nThe following features are available: `python-install-default`, `python-upgrade`,\n`json-output`, `pylock`, `add-bounds`, `package-conflicts`, `extra-build-dependencies`,\n`detect-module-conflicts`, `format`, `native-auth`, `s3-endpoint`.", + "description": "Enable experimental preview features.\nPreview features may change without warning.\nUse comma-separated values or pass multiple times to enable multiple features.", "type": [ "array", "null" From 796f6ff0b581feee23280a6162beb3b32e7a97f4 Mon Sep 17 00:00:00 2001 From: Yiqiuuu Date: Sun, 2 Nov 2025 00:17:48 -0400 Subject: [PATCH 05/10] update --- crates/uv/tests/it/show_settings.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/uv/tests/it/show_settings.rs b/crates/uv/tests/it/show_settings.rs index 05e387d5f60f3..eeda09d46015e 100644 --- a/crates/uv/tests/it/show_settings.rs +++ b/crates/uv/tests/it/show_settings.rs @@ -4643,7 +4643,7 @@ fn resolve_config_file() -> anyhow::Result<()> { | 1 | [project] | ^^^^^^^ - unknown field `project`, expected one of `required-version`, `native-tls`, `offline`, `no-cache`, `cache-dir`, `preview`, `python-preference`, `python-downloads`, `concurrent-downloads`, `concurrent-builds`, `concurrent-installs`, `index`, `index-url`, `extra-index-url`, `no-index`, `find-links`, `index-strategy`, `keyring-provider`, `allow-insecure-host`, `resolution`, `prerelease`, `fork-strategy`, `dependency-metadata`, `config-settings`, `config-settings-package`, `no-build-isolation`, `no-build-isolation-package`, `extra-build-dependencies`, `extra-build-variables`, `exclude-newer`, `exclude-newer-package`, `link-mode`, `compile-bytecode`, `no-sources`, `upgrade`, `upgrade-package`, `reinstall`, `reinstall-package`, `no-build`, `no-build-package`, `no-binary`, `no-binary-package`, `python-install-mirror`, `pypy-install-mirror`, `python-downloads-json-url`, `publish-url`, `trusted-publishing`, `check-url`, `add-bounds`, `pip`, `cache-keys`, `override-dependencies`, `constraint-dependencies`, `build-constraint-dependencies`, `environments`, `required-environments`, `conflicts`, `workspace`, `sources`, `managed`, `package`, `default-groups`, `dependency-groups`, `dev-dependencies`, `build-backend` + unknown field `project`, expected one of `required-version`, `native-tls`, `offline`, `no-cache`, `cache-dir`, `preview`, `preview-features`, `python-preference`, `python-downloads`, `concurrent-downloads`, `concurrent-builds`, `concurrent-installs`, `index`, `index-url`, `extra-index-url`, `no-index`, `find-links`, `index-strategy`, `keyring-provider`, `allow-insecure-host`, `resolution`, `prerelease`, `fork-strategy`, `dependency-metadata`, `config-settings`, `config-settings-package`, `no-build-isolation`, `no-build-isolation-package`, `extra-build-dependencies`, `extra-build-variables`, `exclude-newer`, `exclude-newer-package`, `link-mode`, `compile-bytecode`, `no-sources`, `upgrade`, `upgrade-package`, `reinstall`, `reinstall-package`, `no-build`, `no-build-package`, `no-binary`, `no-binary-package`, `python-install-mirror`, `pypy-install-mirror`, `python-downloads-json-url`, `publish-url`, `trusted-publishing`, `check-url`, `add-bounds`, `pip`, `cache-keys`, `override-dependencies`, `constraint-dependencies`, `build-constraint-dependencies`, `environments`, `required-environments`, `conflicts`, `workspace`, `sources`, `managed`, `package`, `default-groups`, `dependency-groups`, `dev-dependencies`, `build-backend` " ); @@ -8449,7 +8449,7 @@ fn preview_features_from_pyproject_toml() { required_version: None, quiet: 0, verbose: 0, - color: Never, + color: Auto, network_settings: NetworkSettings { connectivity: Online, native_tls: false, @@ -8584,7 +8584,7 @@ fn preview_features_from_uv_toml() { required_version: None, quiet: 0, verbose: 0, - color: Never, + color: Auto, network_settings: NetworkSettings { connectivity: Online, native_tls: false, @@ -8721,7 +8721,7 @@ fn preview_features_precedence_command_line_over_config() { required_version: None, quiet: 0, verbose: 0, - color: Never, + color: Auto, network_settings: NetworkSettings { connectivity: Online, native_tls: false, @@ -8850,7 +8850,7 @@ fn preview_features_precedence_command_line_over_env() { required_version: None, quiet: 0, verbose: 0, - color: Never, + color: Auto, network_settings: NetworkSettings { connectivity: Online, native_tls: false, @@ -8986,7 +8986,7 @@ fn preview_boolean_still_works() { required_version: None, quiet: 0, verbose: 0, - color: Never, + color: Auto, network_settings: NetworkSettings { connectivity: Online, native_tls: false, @@ -9124,7 +9124,7 @@ fn no_preview_overrides_everything() { required_version: None, quiet: 0, verbose: 0, - color: Never, + color: Auto, network_settings: NetworkSettings { connectivity: Online, native_tls: false, From dbc1090f7b980a92447348394bfe26cc7b3a6a10 Mon Sep 17 00:00:00 2001 From: Yiqiuuu Date: Sun, 2 Nov 2025 00:42:19 -0400 Subject: [PATCH 06/10] update --- crates/uv/tests/it/common/mod.rs | 57 +++++++++++++++++++++++++++++ crates/uv/tests/it/show_settings.rs | 52 ++++++++++++++++++++------ 2 files changed, 98 insertions(+), 11 deletions(-) diff --git a/crates/uv/tests/it/common/mod.rs b/crates/uv/tests/it/common/mod.rs index 74decf8ea94ad..25578abb5e6ac 100644 --- a/crates/uv/tests/it/common/mod.rs +++ b/crates/uv/tests/it/common/mod.rs @@ -144,6 +144,63 @@ impl TestContext { self } + /// Set the "concurrent builds" for all commands in this context. + pub fn with_concurrent_builds(mut self, concurrent_builds: &str) -> Self { + self.extra_env.push(( + EnvVars::UV_CONCURRENT_BUILDS.into(), + concurrent_builds.into(), + )); + self + } + + /// Set the "concurrent downloads" for all commands in this context. + pub fn with_concurrent_downloads(mut self, concurrent_downloads: &str) -> Self { + self.extra_env.push(( + EnvVars::UV_CONCURRENT_DOWNLOADS.into(), + concurrent_downloads.into(), + )); + self + } + + /// Set the "link mode" for all commands in this context. + pub fn with_link_mode(mut self, link_mode: &str) -> Self { + self.extra_env + .push((EnvVars::UV_LINK_MODE.into(), link_mode.into())); + self + } + + /// Set the "http retries" for all commands in this context. + pub fn with_http_retries(mut self, http_retries: &str) -> Self { + self.extra_env + .push((EnvVars::UV_HTTP_RETRIES.into(), http_retries.into())); + self + } + + /// Set the "color" preference for all commands in this context. + pub fn with_color(mut self, color: &str) -> Self { + // Color is controlled by NO_COLOR, FORCE_COLOR, and CLICOLOR_FORCE environment variables + // See: crates/uv/src/settings.rs GlobalSettings::resolve + match color.to_lowercase().as_str() { + "never" => { + self.extra_env.push((EnvVars::NO_COLOR.into(), "1".into())); + } + "always" => { + self.extra_env.push((EnvVars::FORCE_COLOR.into(), "1".into())); + } + "auto" => { + // Auto is the default behavior, but we explicitly remove color-related env vars + // to ensure consistent behavior across environments + self.extra_env.push((EnvVars::NO_COLOR.into(), "".into())); + self.extra_env.push((EnvVars::FORCE_COLOR.into(), "".into())); + self.extra_env.push((EnvVars::CLICOLOR_FORCE.into(), "".into())); + } + _ => { + panic!("Invalid color value: {color}. Use 'never', 'always', or 'auto'"); + } + } + self + } + /// Add extra standard filtering for messages like "Resolved 10 packages" which /// can differ between platforms. /// diff --git a/crates/uv/tests/it/show_settings.rs b/crates/uv/tests/it/show_settings.rs index 3cd8edda44ae8..f91e31ea0051d 100644 --- a/crates/uv/tests/it/show_settings.rs +++ b/crates/uv/tests/it/show_settings.rs @@ -8502,7 +8502,12 @@ fn preview_features() { ignore = "Configuration tests are not yet supported on Windows" )] fn preview_features_from_pyproject_toml() { - let context = TestContext::new("3.12"); + let context = TestContext::new("3.12") + .with_concurrent_builds("12") + .with_concurrent_installs("12") + .with_link_mode("clone") + .with_http_retries("3") + .with_color("never"); let pyproject_toml = context.temp_dir.child("pyproject.toml"); pyproject_toml @@ -8520,7 +8525,7 @@ fn preview_features_from_pyproject_toml() { required_version: None, quiet: 0, verbose: 0, - color: Auto, + color: Never, network_settings: NetworkSettings { connectivity: Online, native_tls: false, @@ -8638,7 +8643,12 @@ fn preview_features_from_pyproject_toml() { ignore = "Configuration tests are not yet supported on Windows" )] fn preview_features_from_uv_toml() { - let context = TestContext::new("3.12"); + let context = TestContext::new("3.12") + .with_concurrent_builds("12") + .with_concurrent_installs("12") + .with_link_mode("clone") + .with_http_retries("3") + .with_color("never"); let uv_toml = context.temp_dir.child("uv.toml"); uv_toml @@ -8655,7 +8665,7 @@ fn preview_features_from_uv_toml() { required_version: None, quiet: 0, verbose: 0, - color: Auto, + color: Never, network_settings: NetworkSettings { connectivity: Online, native_tls: false, @@ -8773,7 +8783,12 @@ fn preview_features_from_uv_toml() { ignore = "Configuration tests are not yet supported on Windows" )] fn preview_features_precedence_command_line_over_config() { - let context = TestContext::new("3.12"); + let context = TestContext::new("3.12") + .with_concurrent_builds("12") + .with_concurrent_installs("12") + .with_link_mode("clone") + .with_http_retries("3") + .with_color("never"); let pyproject_toml = context.temp_dir.child("pyproject.toml"); pyproject_toml @@ -8792,7 +8807,7 @@ fn preview_features_precedence_command_line_over_config() { required_version: None, quiet: 0, verbose: 0, - color: Auto, + color: Never, network_settings: NetworkSettings { connectivity: Online, native_tls: false, @@ -8910,7 +8925,12 @@ fn preview_features_precedence_command_line_over_config() { ignore = "Configuration tests are not yet supported on Windows" )] fn preview_features_precedence_command_line_over_env() { - let context = TestContext::new("3.12"); + let context = TestContext::new("3.12") + .with_concurrent_builds("12") + .with_concurrent_installs("12") + .with_link_mode("clone") + .with_http_retries("3") + .with_color("auto"); // Command line should override environment variable uv_snapshot!(context.filters(), context.version().arg("--show-settings").arg("--preview-features").arg("add-bounds").env(EnvVars::UV_PREVIEW_FEATURES, "json-output,format"), @r#" @@ -9039,7 +9059,12 @@ fn preview_features_precedence_command_line_over_env() { ignore = "Configuration tests are not yet supported on Windows" )] fn preview_boolean_still_works() { - let context = TestContext::new("3.12"); + let context = TestContext::new("3.12") + .with_concurrent_builds("12") + .with_concurrent_installs("12") + .with_link_mode("clone") + .with_http_retries("3") + .with_color("never"); let pyproject_toml = context.temp_dir.child("pyproject.toml"); pyproject_toml @@ -9057,7 +9082,7 @@ fn preview_boolean_still_works() { required_version: None, quiet: 0, verbose: 0, - color: Auto, + color: Never, network_settings: NetworkSettings { connectivity: Online, native_tls: false, @@ -9175,7 +9200,12 @@ fn preview_boolean_still_works() { ignore = "Configuration tests are not yet supported on Windows" )] fn no_preview_overrides_everything() { - let context = TestContext::new("3.12"); + let context = TestContext::new("3.12") + .with_concurrent_builds("12") + .with_concurrent_installs("12") + .with_link_mode("clone") + .with_http_retries("3") + .with_color("never"); let pyproject_toml = context.temp_dir.child("pyproject.toml"); pyproject_toml @@ -9195,7 +9225,7 @@ fn no_preview_overrides_everything() { required_version: None, quiet: 0, verbose: 0, - color: Auto, + color: Never, network_settings: NetworkSettings { connectivity: Online, native_tls: false, From 20739836daafbe0866211142fdbdbe18e1e331e8 Mon Sep 17 00:00:00 2001 From: Yiqiuuu Date: Sun, 2 Nov 2025 12:32:57 -0500 Subject: [PATCH 07/10] insta update --- crates/uv/tests/it/show_settings.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/uv/tests/it/show_settings.rs b/crates/uv/tests/it/show_settings.rs index f91e31ea0051d..e6cf2c0de512a 100644 --- a/crates/uv/tests/it/show_settings.rs +++ b/crates/uv/tests/it/show_settings.rs @@ -4684,7 +4684,7 @@ fn resolve_config_file() -> anyhow::Result<()> { | 1 | [project] | ^^^^^^^ - unknown field `project`, expected one of `required-version`, `native-tls`, `offline`, `no-cache`, `cache-dir`, `preview`, `python-preference`, `python-downloads`, `concurrent-downloads`, `concurrent-builds`, `concurrent-installs`, `index`, `index-url`, `extra-index-url`, `no-index`, `find-links`, `index-strategy`, `keyring-provider`, `allow-insecure-host`, `resolution`, `prerelease`, `fork-strategy`, `dependency-metadata`, `config-settings`, `config-settings-package`, `no-build-isolation`, `no-build-isolation-package`, `extra-build-dependencies`, `extra-build-variables`, `exclude-newer`, `exclude-newer-package`, `link-mode`, `compile-bytecode`, `no-sources`, `upgrade`, `upgrade-package`, `reinstall`, `reinstall-package`, `no-build`, `no-build-package`, `no-binary`, `no-binary-package`, `python-install-mirror`, `pypy-install-mirror`, `python-downloads-json-url`, `publish-url`, `trusted-publishing`, `check-url`, `add-bounds`, `pip`, `cache-keys`, `override-dependencies`, `exclude-dependencies`, `constraint-dependencies`, `build-constraint-dependencies`, `environments`, `required-environments`, `conflicts`, `workspace`, `sources`, `managed`, `package`, `default-groups`, `dependency-groups`, `dev-dependencies`, `build-backend` + unknown field `project`, expected one of `required-version`, `native-tls`, `offline`, `no-cache`, `cache-dir`, `preview`, `preview-features`, `python-preference`, `python-downloads`, `concurrent-downloads`, `concurrent-builds`, `concurrent-installs`, `index`, `index-url`, `extra-index-url`, `no-index`, `find-links`, `index-strategy`, `keyring-provider`, `allow-insecure-host`, `resolution`, `prerelease`, `fork-strategy`, `dependency-metadata`, `config-settings`, `config-settings-package`, `no-build-isolation`, `no-build-isolation-package`, `extra-build-dependencies`, `extra-build-variables`, `exclude-newer`, `exclude-newer-package`, `link-mode`, `compile-bytecode`, `no-sources`, `upgrade`, `upgrade-package`, `reinstall`, `reinstall-package`, `no-build`, `no-build-package`, `no-binary`, `no-binary-package`, `python-install-mirror`, `pypy-install-mirror`, `python-downloads-json-url`, `publish-url`, `trusted-publishing`, `check-url`, `add-bounds`, `pip`, `cache-keys`, `override-dependencies`, `exclude-dependencies`, `constraint-dependencies`, `build-constraint-dependencies`, `environments`, `required-environments`, `conflicts`, `workspace`, `sources`, `managed`, `package`, `default-groups`, `dependency-groups`, `dev-dependencies`, `build-backend` " ); From b23c7b6646ec9e5d5be6e4e67443a1b9244727a5 Mon Sep 17 00:00:00 2001 From: Yiqiuuu Date: Sun, 2 Nov 2025 21:00:57 -0500 Subject: [PATCH 08/10] lint and generate --- crates/uv/tests/it/common/mod.rs | 9 ++++++--- docs/reference/settings.md | 6 ------ 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/crates/uv/tests/it/common/mod.rs b/crates/uv/tests/it/common/mod.rs index 25578abb5e6ac..92daae22d9be5 100644 --- a/crates/uv/tests/it/common/mod.rs +++ b/crates/uv/tests/it/common/mod.rs @@ -185,14 +185,17 @@ impl TestContext { self.extra_env.push((EnvVars::NO_COLOR.into(), "1".into())); } "always" => { - self.extra_env.push((EnvVars::FORCE_COLOR.into(), "1".into())); + self.extra_env + .push((EnvVars::FORCE_COLOR.into(), "1".into())); } "auto" => { // Auto is the default behavior, but we explicitly remove color-related env vars // to ensure consistent behavior across environments self.extra_env.push((EnvVars::NO_COLOR.into(), "".into())); - self.extra_env.push((EnvVars::FORCE_COLOR.into(), "".into())); - self.extra_env.push((EnvVars::CLICOLOR_FORCE.into(), "".into())); + self.extra_env + .push((EnvVars::FORCE_COLOR.into(), "".into())); + self.extra_env + .push((EnvVars::CLICOLOR_FORCE.into(), "".into())); } _ => { panic!("Invalid color value: {color}. Use 'never', 'always', or 'auto'"); diff --git a/docs/reference/settings.md b/docs/reference/settings.md index eacc111d33569..aa3d0e80e9184 100644 --- a/docs/reference/settings.md +++ b/docs/reference/settings.md @@ -1848,15 +1848,9 @@ Whether to enable experimental, preview features. ### [`preview-features`](#preview-features) {: #preview-features } 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`, `package-conflicts`, `extra-build-dependencies`, -`detect-module-conflicts`, `format`, `native-auth`, `s3-endpoint`. - **Default value**: `[]` **Type**: `list[str]` From 989974ec3cbcfaa340344b52ac662f3ddecf511e Mon Sep 17 00:00:00 2001 From: Yiqiuuu Date: Sun, 2 Nov 2025 21:27:44 -0500 Subject: [PATCH 09/10] lint markdown --- docs/concepts/preview.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/concepts/preview.md b/docs/concepts/preview.md index a6bacb7843f73..e9533069b3b84 100644 --- a/docs/concepts/preview.md +++ b/docs/concepts/preview.md @@ -59,13 +59,15 @@ For backwards compatibility, enabling preview features that do not exist will wa ## Configuration precedence -When multiple preview configuration methods are used, the following precedence applies (highest to lowest): +When multiple preview configuration methods are used, the following precedence applies (highest to +lowest): 1. Command line flags (`--no-preview`, `--preview`, `--preview-features`) 2. Environment variables (`UV_PREVIEW`, `UV_PREVIEW_FEATURES`) 3. Configuration files (`pyproject.toml`, `uv.toml`) -For example, if you set `preview = true` in configuration but use `--no-preview` on the command line, preview features will be disabled. +For example, if you set `preview = true` in configuration but use `--no-preview` on the command +line, preview features will be disabled. ## Using preview features From 81e8f6a5bccd5ede71e92baa8b5e65e4d7e9777c Mon Sep 17 00:00:00 2001 From: Yiqiuuu Date: Mon, 3 Nov 2025 21:40:33 -0500 Subject: [PATCH 10/10] update snapshot --- crates/uv/tests/it/show_settings.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/uv/tests/it/show_settings.rs b/crates/uv/tests/it/show_settings.rs index e21fcf9668bd0..c55fa689588ef 100644 --- a/crates/uv/tests/it/show_settings.rs +++ b/crates/uv/tests/it/show_settings.rs @@ -9098,7 +9098,7 @@ fn preview_boolean_still_works() { show_settings: true, preview: Preview { flags: PreviewFeatures( - PYTHON_INSTALL_DEFAULT | PYTHON_UPGRADE | JSON_OUTPUT | PYLOCK | ADD_BOUNDS | PACKAGE_CONFLICTS | EXTRA_BUILD_DEPENDENCIES | DETECT_MODULE_CONFLICTS | FORMAT | NATIVE_AUTH | S3_ENDPOINT, + PYTHON_INSTALL_DEFAULT | PYTHON_UPGRADE | JSON_OUTPUT | PYLOCK | ADD_BOUNDS | PACKAGE_CONFLICTS | EXTRA_BUILD_DEPENDENCIES | DETECT_MODULE_CONFLICTS | FORMAT | NATIVE_AUTH | S3_ENDPOINT | CACHE_SIZE, ), }, python_preference: Managed,