Use VenvCreationPolicy instead of clear and allow-existing bools

This commit is contained in:
John Mumm 2025-07-01 12:30:29 +02:00
parent dc2473af28
commit 6561537b50
No known key found for this signature in database
GPG key ID: 73D2271AFDC26EA8
9 changed files with 53 additions and 41 deletions

View file

@ -40,6 +40,7 @@ use uv_pypi_types::VerbatimParsedUrl;
use uv_python::{Interpreter, PythonEnvironment}; use uv_python::{Interpreter, PythonEnvironment};
use uv_static::EnvVars; use uv_static::EnvVars;
use uv_types::{AnyErrorBuild, BuildContext, BuildIsolation, BuildStack, SourceBuildTrait}; use uv_types::{AnyErrorBuild, BuildContext, BuildIsolation, BuildStack, SourceBuildTrait};
use uv_virtualenv::VenvCreationPolicy;
use uv_warnings::warn_user_once; use uv_warnings::warn_user_once;
use uv_workspace::WorkspaceCache; use uv_workspace::WorkspaceCache;
@ -333,8 +334,7 @@ impl SourceBuild {
interpreter.clone(), interpreter.clone(),
uv_virtualenv::Prompt::None, uv_virtualenv::Prompt::None,
false, false,
false, VenvCreationPolicy::RemoveDirectory,
true,
false, false,
false, false,
false, false,

View file

@ -5,6 +5,7 @@ use uv_configuration::PreviewMode;
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};
use uv_virtualenv::VenvCreationPolicy;
use std::io::{self, Write}; use std::io::{self, Write};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -285,8 +286,7 @@ impl InstalledTools {
interpreter, interpreter,
uv_virtualenv::Prompt::None, uv_virtualenv::Prompt::None,
false, false,
false, VenvCreationPolicy::RemoveDirectory,
true,
false, false,
false, false,
false, false,

View file

@ -6,6 +6,8 @@ use thiserror::Error;
use uv_configuration::PreviewMode; use uv_configuration::PreviewMode;
use uv_python::{Interpreter, PythonEnvironment}; use uv_python::{Interpreter, PythonEnvironment};
pub use virtualenv::VenvCreationPolicy;
mod virtualenv; mod virtualenv;
#[derive(Debug, Error)] #[derive(Debug, Error)]
@ -50,8 +52,7 @@ pub fn create_venv(
interpreter: Interpreter, interpreter: Interpreter,
prompt: Prompt, prompt: Prompt,
system_site_packages: bool, system_site_packages: bool,
allow_existing: bool, venv_creation_policy: VenvCreationPolicy,
clear: bool,
relocatable: bool, relocatable: bool,
seed: bool, seed: bool,
upgradeable: bool, upgradeable: bool,
@ -63,8 +64,7 @@ pub fn create_venv(
&interpreter, &interpreter,
prompt, prompt,
system_site_packages, system_site_packages,
allow_existing, venv_creation_policy,
clear,
relocatable, relocatable,
seed, seed,
upgradeable, upgradeable,

View file

@ -54,8 +54,7 @@ pub(crate) fn create(
interpreter: &Interpreter, interpreter: &Interpreter,
prompt: Prompt, prompt: Prompt,
system_site_packages: bool, system_site_packages: bool,
allow_existing: bool, venv_creation_policy: VenvCreationPolicy,
clear: bool,
relocatable: bool, relocatable: bool,
seed: bool, seed: bool,
upgradeable: bool, upgradeable: bool,
@ -86,13 +85,15 @@ pub(crate) fn create(
format!("File exists at `{}`", location.user_display()), format!("File exists at `{}`", location.user_display()),
))); )));
} else if metadata.is_dir() { } else if metadata.is_dir() {
let confirmation_required = !clear && !allow_existing; let confirmed_clear = venv_creation_policy == VenvCreationPolicy::FailIfNotEmpty
let confirmed_clear = confirmation_required && confirm_clear(location)?; && confirm_clear(location)?;
if allow_existing { if venv_creation_policy == VenvCreationPolicy::OverwriteFiles {
debug!("Allowing existing directory due to `--allow-existing`"); debug!("Allowing existing directory due to `--allow-existing`");
} else if clear || confirmed_clear { } else if venv_creation_policy == VenvCreationPolicy::RemoveDirectory
if clear { || confirmed_clear
{
if venv_creation_policy == VenvCreationPolicy::RemoveDirectory {
debug!("Removing existing directory due to `--clear`"); debug!("Removing existing directory due to `--clear`");
} else { } else {
debug!("Removing existing directory"); debug!("Removing existing directory");
@ -491,6 +492,17 @@ fn confirm_clear(location: &Path) -> Result<bool, io::Error> {
} }
} }
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
pub enum VenvCreationPolicy {
/// Do not create a virtual environment if a non-empty directory exists.
#[default]
FailIfNotEmpty,
/// Overwrite existing virtual environment files.
OverwriteFiles,
/// Remove existing directory.
RemoveDirectory,
}
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
enum WindowsExecutable { enum WindowsExecutable {
/// The `python.exe` executable (or `venvlauncher.exe` launcher shim). /// The `python.exe` executable (or `venvlauncher.exe` launcher shim).

View file

@ -8,6 +8,7 @@ use uv_configuration::{Concurrency, Constraints, PreviewMode};
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};
use uv_virtualenv::VenvCreationPolicy;
use crate::commands::pip::loggers::{InstallLogger, ResolveLogger}; use crate::commands::pip::loggers::{InstallLogger, ResolveLogger};
use crate::commands::pip::operations::Modifications; use crate::commands::pip::operations::Modifications;
@ -96,8 +97,7 @@ impl CachedEnvironment {
interpreter, interpreter,
uv_virtualenv::Prompt::None, uv_virtualenv::Prompt::None,
false, false,
false, VenvCreationPolicy::RemoveDirectory,
true,
true, true,
false, false,
false, false,

View file

@ -43,6 +43,7 @@ use uv_scripts::Pep723ItemRef;
use uv_settings::PythonInstallMirrors; use uv_settings::PythonInstallMirrors;
use uv_static::EnvVars; use uv_static::EnvVars;
use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy}; use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy};
use uv_virtualenv::VenvCreationPolicy;
use uv_warnings::{warn_user, warn_user_once}; use uv_warnings::{warn_user, warn_user_once};
use uv_workspace::dependency_groups::DependencyGroupError; use uv_workspace::dependency_groups::DependencyGroupError;
use uv_workspace::pyproject::PyProjectToml; use uv_workspace::pyproject::PyProjectToml;
@ -1308,8 +1309,7 @@ impl ProjectEnvironment {
interpreter, interpreter,
prompt, prompt,
false, false,
false, VenvCreationPolicy::RemoveDirectory,
true,
false, false,
false, false,
upgradeable, upgradeable,
@ -1348,8 +1348,7 @@ impl ProjectEnvironment {
interpreter, interpreter,
prompt, prompt,
false, false,
false, VenvCreationPolicy::RemoveDirectory,
true,
false, false,
false, false,
upgradeable, upgradeable,
@ -1487,8 +1486,7 @@ impl ScriptEnvironment {
interpreter, interpreter,
prompt, prompt,
false, false,
false, VenvCreationPolicy::RemoveDirectory,
true,
false, false,
false, false,
upgradeable, upgradeable,
@ -1524,8 +1522,7 @@ impl ScriptEnvironment {
interpreter, interpreter,
prompt, prompt,
false, false,
false, VenvCreationPolicy::RemoveDirectory,
true,
false, false,
false, false,
upgradeable, upgradeable,

View file

@ -37,6 +37,7 @@ use uv_scripts::Pep723Item;
use uv_settings::PythonInstallMirrors; use uv_settings::PythonInstallMirrors;
use uv_shell::runnable::WindowsRunnable; use uv_shell::runnable::WindowsRunnable;
use uv_static::EnvVars; use uv_static::EnvVars;
use uv_virtualenv::VenvCreationPolicy;
use uv_warnings::warn_user; use uv_warnings::warn_user;
use uv_workspace::{DiscoveryOptions, VirtualProject, Workspace, WorkspaceCache, WorkspaceError}; use uv_workspace::{DiscoveryOptions, VirtualProject, Workspace, WorkspaceCache, WorkspaceError};
@ -452,8 +453,7 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl
interpreter, interpreter,
uv_virtualenv::Prompt::None, uv_virtualenv::Prompt::None,
false, false,
false, VenvCreationPolicy::RemoveDirectory,
true,
false, false,
false, false,
false, false,
@ -657,8 +657,7 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl
interpreter, interpreter,
uv_virtualenv::Prompt::None, uv_virtualenv::Prompt::None,
false, false,
false, VenvCreationPolicy::RemoveDirectory,
true,
false, false,
false, false,
false, false,
@ -887,8 +886,7 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl
interpreter, interpreter,
uv_virtualenv::Prompt::None, uv_virtualenv::Prompt::None,
false, false,
false, VenvCreationPolicy::RemoveDirectory,
true,
false, false,
false, false,
false, false,

View file

@ -29,6 +29,7 @@ use uv_resolver::{ExcludeNewer, FlatIndex};
use uv_settings::PythonInstallMirrors; use uv_settings::PythonInstallMirrors;
use uv_shell::{Shell, shlex_posix, shlex_windows}; use uv_shell::{Shell, shlex_posix, shlex_windows};
use uv_types::{AnyErrorBuild, BuildContext, BuildIsolation, BuildStack, HashStrategy}; use uv_types::{AnyErrorBuild, BuildContext, BuildIsolation, BuildStack, HashStrategy};
use uv_virtualenv::VenvCreationPolicy;
use uv_warnings::warn_user; use uv_warnings::warn_user;
use uv_workspace::{DiscoveryOptions, VirtualProject, WorkspaceCache, WorkspaceError}; use uv_workspace::{DiscoveryOptions, VirtualProject, WorkspaceCache, WorkspaceError};
@ -60,8 +61,7 @@ pub(crate) async fn venv(
prompt: uv_virtualenv::Prompt, prompt: uv_virtualenv::Prompt,
system_site_packages: bool, system_site_packages: bool,
seed: bool, seed: bool,
allow_existing: bool, venv_creation_policy: VenvCreationPolicy,
clear: bool,
exclude_newer: Option<ExcludeNewer>, exclude_newer: Option<ExcludeNewer>,
concurrency: Concurrency, concurrency: Concurrency,
no_config: bool, no_config: bool,
@ -87,8 +87,7 @@ pub(crate) async fn venv(
seed, seed,
python_preference, python_preference,
python_downloads, python_downloads,
allow_existing, venv_creation_policy,
clear,
exclude_newer, exclude_newer,
concurrency, concurrency,
no_config, no_config,
@ -145,8 +144,7 @@ async fn venv_impl(
seed: bool, seed: bool,
python_preference: PythonPreference, python_preference: PythonPreference,
python_downloads: PythonDownloads, python_downloads: PythonDownloads,
allow_existing: bool, venv_creation_policy: VenvCreationPolicy,
clear: bool,
exclude_newer: Option<ExcludeNewer>, exclude_newer: Option<ExcludeNewer>,
concurrency: Concurrency, concurrency: Concurrency,
no_config: bool, no_config: bool,
@ -291,8 +289,7 @@ async fn venv_impl(
interpreter, interpreter,
prompt, prompt,
system_site_packages, system_site_packages,
allow_existing, venv_creation_policy,
clear,
relocatable, relocatable,
seed, seed,
upgradeable, upgradeable,

View file

@ -41,6 +41,7 @@ use uv_requirements_txt::RequirementsTxtRequirement;
use uv_scripts::{Pep723Error, Pep723Item, Pep723ItemRef, Pep723Metadata, Pep723Script}; use uv_scripts::{Pep723Error, Pep723Item, Pep723ItemRef, Pep723Metadata, Pep723Script};
use uv_settings::{Combine, FilesystemOptions, Options}; use uv_settings::{Combine, FilesystemOptions, Options};
use uv_static::EnvVars; use uv_static::EnvVars;
use uv_virtualenv::VenvCreationPolicy;
use uv_warnings::{warn_user, warn_user_once}; use uv_warnings::{warn_user, warn_user_once};
use uv_workspace::{DiscoveryOptions, Workspace, WorkspaceCache}; use uv_workspace::{DiscoveryOptions, Workspace, WorkspaceCache};
@ -1026,6 +1027,14 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
let python_request: Option<PythonRequest> = let python_request: Option<PythonRequest> =
args.settings.python.as_deref().map(PythonRequest::parse); args.settings.python.as_deref().map(PythonRequest::parse);
let venv_creation_policy = if args.allow_existing {
VenvCreationPolicy::OverwriteFiles
} else if args.clear {
VenvCreationPolicy::RemoveDirectory
} else {
VenvCreationPolicy::default()
};
commands::venv( commands::venv(
&project_dir, &project_dir,
args.path, args.path,
@ -1042,8 +1051,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
uv_virtualenv::Prompt::from_args(prompt), uv_virtualenv::Prompt::from_args(prompt),
args.system_site_packages, args.system_site_packages,
args.seed, args.seed,
args.allow_existing, venv_creation_policy,
args.clear,
args.settings.exclude_newer, args.settings.exclude_newer,
globals.concurrency, globals.concurrency,
cli.top_level.no_config, cli.top_level.no_config,