mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 13:25:00 +00:00
Require uv venv --clear
before clearing an existing directory
This commit is contained in:
parent
3774a656d7
commit
dc2473af28
24 changed files with 146 additions and 71 deletions
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
|
@ -981,7 +981,7 @@ jobs:
|
|||
|
||||
- name: "Create a virtual environment (uv)"
|
||||
run: |
|
||||
./uv venv -p 3.13t --managed-python
|
||||
./uv venv -c -p 3.13t --managed-python
|
||||
|
||||
- name: "Check version (uv)"
|
||||
run: |
|
||||
|
@ -1697,14 +1697,14 @@ jobs:
|
|||
./uv run --no-project python -c "from built_by_uv import greet; print(greet())"
|
||||
|
||||
# Test both `build_wheel` and `build_sdist` through uv
|
||||
./uv venv -v
|
||||
./uv venv -c -v
|
||||
./uv build -v --force-pep517 scripts/packages/built-by-uv --find-links crates/uv-build/dist --offline
|
||||
./uv pip install -v scripts/packages/built-by-uv/dist/*.tar.gz --find-links crates/uv-build/dist --offline --no-deps
|
||||
./uv run --no-project python -c "from built_by_uv import greet; print(greet())"
|
||||
|
||||
# Test both `build_wheel` and `build_sdist` through the official `build`
|
||||
rm -rf scripts/packages/built-by-uv/dist/
|
||||
./uv venv -v
|
||||
./uv venv -c -v
|
||||
./uv pip install build
|
||||
# Add the uv binary to PATH for `build` to find
|
||||
PATH="$(pwd):$PATH" UV_OFFLINE=1 UV_FIND_LINKS=crates/uv-build/dist ./uv run --no-project python -m build -v --installer uv scripts/packages/built-by-uv
|
||||
|
|
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -6075,13 +6075,16 @@ version = "0.7.17"
|
|||
name = "uv-virtualenv"
|
||||
version = "0.0.4"
|
||||
dependencies = [
|
||||
"console",
|
||||
"fs-err 3.1.1",
|
||||
"itertools 0.14.0",
|
||||
"owo-colors",
|
||||
"pathdiff",
|
||||
"self-replace",
|
||||
"thiserror 2.0.12",
|
||||
"tracing",
|
||||
"uv-configuration",
|
||||
"uv-console",
|
||||
"uv-fs",
|
||||
"uv-pypi-types",
|
||||
"uv-python",
|
||||
|
|
|
@ -334,6 +334,7 @@ impl SourceBuild {
|
|||
uv_virtualenv::Prompt::None,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
|
|
|
@ -266,9 +266,6 @@ enum Resolver {
|
|||
/// These represent a subset of the `virtualenv` interface that uv supports by default.
|
||||
#[derive(Args)]
|
||||
pub struct VenvCompatArgs {
|
||||
#[clap(long, hide = true)]
|
||||
clear: bool,
|
||||
|
||||
#[clap(long, hide = true)]
|
||||
no_seed: bool,
|
||||
|
||||
|
@ -289,12 +286,6 @@ impl CompatArgs for VenvCompatArgs {
|
|||
/// behavior. If an argument is passed that does _not_ match uv's behavior, this method will
|
||||
/// return an error.
|
||||
fn validate(&self) -> Result<()> {
|
||||
if self.clear {
|
||||
warn_user!(
|
||||
"virtualenv's `--clear` has no effect (uv always clears the virtual environment)"
|
||||
);
|
||||
}
|
||||
|
||||
if self.no_seed {
|
||||
warn_user!(
|
||||
"virtualenv's `--no-seed` has no effect (uv omits seed packages by default)"
|
||||
|
|
|
@ -2562,16 +2562,23 @@ pub struct VenvArgs {
|
|||
#[arg(long, value_parser = clap::builder::BoolishValueParser::new(), env = EnvVars::UV_VENV_SEED)]
|
||||
pub seed: bool,
|
||||
|
||||
/// Remove any existing files or directories at the target path.
|
||||
///
|
||||
/// By default, `uv venv` will exit with an error if the given path is non-empty. The
|
||||
/// `--clear` option will instead clear a non-empty path before creating a new virtual
|
||||
/// environment.
|
||||
#[clap(long, short, conflicts_with = "allow_existing", value_parser = clap::builder::BoolishValueParser::new(), env = EnvVars::UV_VENV_CLEAR)]
|
||||
pub clear: bool,
|
||||
|
||||
/// Preserve any existing files or directories at the target path.
|
||||
///
|
||||
/// By default, `uv venv` will remove an existing virtual environment at the given path, and
|
||||
/// exit with an error if the path is non-empty but _not_ a virtual environment. The
|
||||
/// By default, `uv venv` will exit with an error if the given path is non-empty. The
|
||||
/// `--allow-existing` option will instead write to the given path, regardless of its contents,
|
||||
/// and without clearing it beforehand.
|
||||
///
|
||||
/// WARNING: This option can lead to unexpected behavior if the existing virtual environment and
|
||||
/// the newly-created virtual environment are linked to different Python interpreters.
|
||||
#[clap(long)]
|
||||
#[clap(long, conflicts_with = "clear")]
|
||||
pub allow_existing: bool,
|
||||
|
||||
/// The path to the virtual environment to create.
|
||||
|
|
|
@ -292,6 +292,13 @@ impl EnvVars {
|
|||
/// Distributions can be read from a local directory by using the `file://` URL scheme.
|
||||
pub const UV_PYPY_INSTALL_MIRROR: &'static str = "UV_PYPY_INSTALL_MIRROR";
|
||||
|
||||
/// Remove any existing files or directories at the target path.
|
||||
///
|
||||
/// By default, `uv venv` will exit with an error if the given path is non-empty. The
|
||||
/// `--clear` option will instead clear a non-empty path before creating a new virtual
|
||||
/// environment.
|
||||
pub const UV_VENV_CLEAR: &'static str = "UV_VENV_CLEAR";
|
||||
|
||||
/// Install seed packages (one or more of: `pip`, `setuptools`, and `wheel`) into the virtual environment
|
||||
/// created by `uv venv`.
|
||||
///
|
||||
|
|
|
@ -286,6 +286,7 @@ impl InstalledTools {
|
|||
uv_virtualenv::Prompt::None,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
|
|
|
@ -21,14 +21,17 @@ workspace = true
|
|||
|
||||
[dependencies]
|
||||
uv-configuration = { workspace = true }
|
||||
uv-console = { workspace = true }
|
||||
uv-fs = { workspace = true }
|
||||
uv-pypi-types = { workspace = true }
|
||||
uv-python = { workspace = true }
|
||||
uv-shell = { workspace = true }
|
||||
uv-version = { workspace = true }
|
||||
|
||||
console = { workspace = true }
|
||||
fs-err = { workspace = true }
|
||||
itertools = { workspace = true }
|
||||
owo-colors = { workspace = true }
|
||||
pathdiff = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
|
|
|
@ -51,6 +51,7 @@ pub fn create_venv(
|
|||
prompt: Prompt,
|
||||
system_site_packages: bool,
|
||||
allow_existing: bool,
|
||||
clear: bool,
|
||||
relocatable: bool,
|
||||
seed: bool,
|
||||
upgradeable: bool,
|
||||
|
@ -63,6 +64,7 @@ pub fn create_venv(
|
|||
prompt,
|
||||
system_site_packages,
|
||||
allow_existing,
|
||||
clear,
|
||||
relocatable,
|
||||
seed,
|
||||
upgradeable,
|
||||
|
|
|
@ -5,9 +5,11 @@ use std::io;
|
|||
use std::io::{BufWriter, Write};
|
||||
use std::path::Path;
|
||||
|
||||
use console::Term;
|
||||
use fs_err as fs;
|
||||
use fs_err::File;
|
||||
use itertools::Itertools;
|
||||
use owo_colors::OwoColorize;
|
||||
use tracing::debug;
|
||||
|
||||
use uv_configuration::PreviewMode;
|
||||
|
@ -53,6 +55,7 @@ pub(crate) fn create(
|
|||
prompt: Prompt,
|
||||
system_site_packages: bool,
|
||||
allow_existing: bool,
|
||||
clear: bool,
|
||||
relocatable: bool,
|
||||
seed: bool,
|
||||
upgradeable: bool,
|
||||
|
@ -83,10 +86,17 @@ pub(crate) fn create(
|
|||
format!("File exists at `{}`", location.user_display()),
|
||||
)));
|
||||
} else if metadata.is_dir() {
|
||||
let confirmation_required = !clear && !allow_existing;
|
||||
let confirmed_clear = confirmation_required && confirm_clear(location)?;
|
||||
|
||||
if allow_existing {
|
||||
debug!("Allowing existing directory");
|
||||
} else if uv_fs::is_virtualenv_base(location) {
|
||||
debug!("Removing existing directory");
|
||||
debug!("Allowing existing directory due to `--allow-existing`");
|
||||
} else if clear || confirmed_clear {
|
||||
if clear {
|
||||
debug!("Removing existing directory due to `--clear`");
|
||||
} else {
|
||||
debug!("Removing existing directory");
|
||||
}
|
||||
|
||||
// On Windows, if the current executable is in the directory, guard against
|
||||
// self-deletion.
|
||||
|
@ -110,8 +120,12 @@ pub(crate) fn create(
|
|||
return Err(Error::Io(io::Error::new(
|
||||
io::ErrorKind::AlreadyExists,
|
||||
format!(
|
||||
"The directory `{}` exists, but it's not a virtual environment",
|
||||
location.user_display()
|
||||
"The directory `{}` exists. \n\n{}{} Use `{}` to remove the directory first or `{}` to write to the directory without clearing",
|
||||
location.user_display(),
|
||||
"hint".bold().cyan(),
|
||||
":".bold(),
|
||||
"--clear".green(),
|
||||
"--allow-existing".green(),
|
||||
),
|
||||
)));
|
||||
}
|
||||
|
@ -464,6 +478,19 @@ pub(crate) fn create(
|
|||
})
|
||||
}
|
||||
|
||||
fn confirm_clear(location: &Path) -> Result<bool, io::Error> {
|
||||
let term = Term::stderr();
|
||||
if term.is_term() {
|
||||
let prompt = format!(
|
||||
"The directory `{}` exists. Did you mean to clear its contents (`--clear`)?",
|
||||
location.user_display(),
|
||||
);
|
||||
uv_console::confirm(&prompt, &term, true)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
enum WindowsExecutable {
|
||||
/// The `python.exe` executable (or `venvlauncher.exe` launcher shim).
|
||||
|
|
|
@ -98,6 +98,7 @@ impl CachedEnvironment {
|
|||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
preview,
|
||||
|
|
|
@ -1309,6 +1309,7 @@ impl ProjectEnvironment {
|
|||
prompt,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
upgradeable,
|
||||
|
@ -1348,6 +1349,7 @@ impl ProjectEnvironment {
|
|||
prompt,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
upgradeable,
|
||||
|
@ -1486,6 +1488,7 @@ impl ScriptEnvironment {
|
|||
prompt,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
upgradeable,
|
||||
|
@ -1522,6 +1525,7 @@ impl ScriptEnvironment {
|
|||
prompt,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
upgradeable,
|
||||
|
|
|
@ -453,6 +453,7 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl
|
|||
uv_virtualenv::Prompt::None,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
|
@ -657,6 +658,7 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl
|
|||
uv_virtualenv::Prompt::None,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
|
@ -886,6 +888,7 @@ hint: If you are running a script with `{}` in the shebang, you may need to incl
|
|||
uv_virtualenv::Prompt::None,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
|
|
|
@ -61,6 +61,7 @@ pub(crate) async fn venv(
|
|||
system_site_packages: bool,
|
||||
seed: bool,
|
||||
allow_existing: bool,
|
||||
clear: bool,
|
||||
exclude_newer: Option<ExcludeNewer>,
|
||||
concurrency: Concurrency,
|
||||
no_config: bool,
|
||||
|
@ -87,6 +88,7 @@ pub(crate) async fn venv(
|
|||
python_preference,
|
||||
python_downloads,
|
||||
allow_existing,
|
||||
clear,
|
||||
exclude_newer,
|
||||
concurrency,
|
||||
no_config,
|
||||
|
@ -144,6 +146,7 @@ async fn venv_impl(
|
|||
python_preference: PythonPreference,
|
||||
python_downloads: PythonDownloads,
|
||||
allow_existing: bool,
|
||||
clear: bool,
|
||||
exclude_newer: Option<ExcludeNewer>,
|
||||
concurrency: Concurrency,
|
||||
no_config: bool,
|
||||
|
@ -289,6 +292,7 @@ async fn venv_impl(
|
|||
prompt,
|
||||
system_site_packages,
|
||||
allow_existing,
|
||||
clear,
|
||||
relocatable,
|
||||
seed,
|
||||
upgradeable,
|
||||
|
|
|
@ -1043,6 +1043,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
|||
args.system_site_packages,
|
||||
args.seed,
|
||||
args.allow_existing,
|
||||
args.clear,
|
||||
args.settings.exclude_newer,
|
||||
globals.concurrency,
|
||||
cli.top_level.no_config,
|
||||
|
|
|
@ -2561,6 +2561,7 @@ impl BuildSettings {
|
|||
pub(crate) struct VenvSettings {
|
||||
pub(crate) seed: bool,
|
||||
pub(crate) allow_existing: bool,
|
||||
pub(crate) clear: bool,
|
||||
pub(crate) path: Option<PathBuf>,
|
||||
pub(crate) prompt: Option<String>,
|
||||
pub(crate) system_site_packages: bool,
|
||||
|
@ -2579,6 +2580,7 @@ impl VenvSettings {
|
|||
no_system,
|
||||
seed,
|
||||
allow_existing,
|
||||
clear,
|
||||
path,
|
||||
prompt,
|
||||
system_site_packages,
|
||||
|
@ -2596,6 +2598,7 @@ impl VenvSettings {
|
|||
Self {
|
||||
seed,
|
||||
allow_existing,
|
||||
clear,
|
||||
path,
|
||||
prompt,
|
||||
system_site_packages,
|
||||
|
|
|
@ -227,7 +227,7 @@ fn prune_unzipped() -> Result<()> {
|
|||
Removed [N] files ([SIZE])
|
||||
"###);
|
||||
|
||||
context.venv().assert().success();
|
||||
context.venv().arg("--clear").assert().success();
|
||||
|
||||
// Reinstalling the source distribution should not require re-downloading the source
|
||||
// distribution.
|
||||
|
|
|
@ -1390,6 +1390,7 @@ pub fn create_venv_from_executable<P: AsRef<Path>>(path: P, cache_dir: &ChildPat
|
|||
assert_cmd::Command::new(get_bin())
|
||||
.arg("venv")
|
||||
.arg(path.as_ref().as_os_str())
|
||||
.arg("--clear")
|
||||
.arg("--cache-dir")
|
||||
.arg(cache_dir.path())
|
||||
.arg("--python")
|
||||
|
|
|
@ -2776,7 +2776,7 @@ fn install_no_binary_cache() {
|
|||
);
|
||||
|
||||
// Re-create the virtual environment.
|
||||
context.venv().assert().success();
|
||||
context.venv().arg("--clear").assert().success();
|
||||
|
||||
// Re-install. The distribution should be installed from the cache.
|
||||
uv_snapshot!(
|
||||
|
@ -2794,7 +2794,7 @@ fn install_no_binary_cache() {
|
|||
);
|
||||
|
||||
// Re-create the virtual environment.
|
||||
context.venv().assert().success();
|
||||
context.venv().arg("--clear").assert().success();
|
||||
|
||||
// Install with `--no-binary`. The distribution should be built from source, despite a binary
|
||||
// distribution being available in the cache.
|
||||
|
@ -3005,7 +3005,7 @@ fn cache_priority() {
|
|||
);
|
||||
|
||||
// Re-create the virtual environment.
|
||||
context.venv().assert().success();
|
||||
context.venv().arg("--clear").assert().success();
|
||||
|
||||
// Install `idna` without a version specifier.
|
||||
uv_snapshot!(
|
||||
|
@ -8175,6 +8175,7 @@ fn install_relocatable() -> Result<()> {
|
|||
context
|
||||
.venv()
|
||||
.arg(context.venv.as_os_str())
|
||||
.arg("--clear")
|
||||
.arg("--python")
|
||||
.arg("3.12")
|
||||
.arg("--relocatable")
|
||||
|
|
|
@ -5625,7 +5625,7 @@ fn sync_seed() -> Result<()> {
|
|||
);
|
||||
|
||||
// Re-create the environment with seed packages.
|
||||
uv_snapshot!(context.filters(), context.venv()
|
||||
uv_snapshot!(context.filters(), context.venv().arg("--clear")
|
||||
.arg("--seed"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
|
|
|
@ -9595,6 +9595,7 @@ fn sync_when_virtual_environment_incompatible_with_interpreter() -> Result<()> {
|
|||
context
|
||||
.venv()
|
||||
.arg(context.venv.as_os_str())
|
||||
.arg("--clear")
|
||||
.arg("--python")
|
||||
.arg("3.12")
|
||||
.assert()
|
||||
|
|
|
@ -30,10 +30,34 @@ fn create_venv() {
|
|||
|
||||
context.venv.assert(predicates::path::is_dir());
|
||||
|
||||
// Create a virtual environment at the same location, which should replace it.
|
||||
// Attempt to create a virtual environment at the same location,
|
||||
// which should fail.
|
||||
uv_snapshot!(context.filters(), context.venv()
|
||||
.arg(context.venv.as_os_str())
|
||||
.arg("--python")
|
||||
.arg("3.12"), @r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Creating virtual environment at: .venv
|
||||
uv::venv::creation
|
||||
|
||||
× Failed to create virtualenv
|
||||
╰─▶ The directory `.venv` exists.
|
||||
|
||||
hint: Use `--clear` to remove the directory first or `--allow-existing` to write to the directory without clearing
|
||||
"
|
||||
);
|
||||
|
||||
// Create a virtual environment at the same location using `--clear`,
|
||||
// which should replace it.
|
||||
uv_snapshot!(context.filters(), context.venv()
|
||||
.arg(context.venv.as_os_str())
|
||||
.arg("--clear")
|
||||
.arg("--python")
|
||||
.arg("3.12"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
|
@ -162,7 +186,7 @@ fn create_venv_project_environment() -> Result<()> {
|
|||
.assert(predicates::path::is_dir());
|
||||
|
||||
// Or, of they opt-out with `--no-workspace` or `--no-project`
|
||||
uv_snapshot!(context.filters(), context.venv().arg("--no-workspace"), @r###"
|
||||
uv_snapshot!(context.filters(), context.venv().arg("--clear").arg("--no-workspace"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
@ -174,7 +198,7 @@ fn create_venv_project_environment() -> Result<()> {
|
|||
"###
|
||||
);
|
||||
|
||||
uv_snapshot!(context.filters(), context.venv().arg("--no-project"), @r###"
|
||||
uv_snapshot!(context.filters(), context.venv().arg("--clear").arg("--no-project"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
@ -252,7 +276,7 @@ fn create_venv_reads_request_from_python_version_file() {
|
|||
.write_str("3.12")
|
||||
.unwrap();
|
||||
|
||||
uv_snapshot!(context.filters(), context.venv(), @r###"
|
||||
uv_snapshot!(context.filters(), context.venv().arg("--clear"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
@ -291,7 +315,7 @@ fn create_venv_reads_request_from_python_versions_file() {
|
|||
.write_str("3.12\n3.11")
|
||||
.unwrap();
|
||||
|
||||
uv_snapshot!(context.filters(), context.venv(), @r###"
|
||||
uv_snapshot!(context.filters(), context.venv().arg("--clear"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
@ -334,7 +358,7 @@ fn create_venv_respects_pyproject_requires_python() -> Result<()> {
|
|||
"#
|
||||
})?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.venv(), @r###"
|
||||
uv_snapshot!(context.filters(), context.venv().arg("--clear"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
@ -357,7 +381,7 @@ fn create_venv_respects_pyproject_requires_python() -> Result<()> {
|
|||
"#
|
||||
})?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.venv(), @r###"
|
||||
uv_snapshot!(context.filters(), context.venv().arg("--clear"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
@ -380,7 +404,7 @@ fn create_venv_respects_pyproject_requires_python() -> Result<()> {
|
|||
"#
|
||||
})?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.venv(), @r###"
|
||||
uv_snapshot!(context.filters(), context.venv().arg("--clear"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
@ -414,7 +438,7 @@ fn create_venv_respects_pyproject_requires_python() -> Result<()> {
|
|||
"#
|
||||
})?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.venv(), @r###"
|
||||
uv_snapshot!(context.filters(), context.venv().arg("--clear"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
@ -437,7 +461,7 @@ fn create_venv_respects_pyproject_requires_python() -> Result<()> {
|
|||
"#
|
||||
})?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.venv(), @r###"
|
||||
uv_snapshot!(context.filters(), context.venv().arg("--clear"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
@ -460,7 +484,7 @@ fn create_venv_respects_pyproject_requires_python() -> Result<()> {
|
|||
"#
|
||||
})?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.venv(), @r###"
|
||||
uv_snapshot!(context.filters(), context.venv().arg("--clear"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
@ -475,7 +499,7 @@ fn create_venv_respects_pyproject_requires_python() -> Result<()> {
|
|||
context.venv.assert(predicates::path::is_dir());
|
||||
|
||||
// We warn if we receive an incompatible version
|
||||
uv_snapshot!(context.filters(), context.venv().arg("--python").arg("3.11"), @r"
|
||||
uv_snapshot!(context.filters(), context.venv().arg("--clear").arg("--python").arg("3.11"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
@ -527,7 +551,7 @@ fn create_venv_respects_group_requires_python() -> Result<()> {
|
|||
"#
|
||||
})?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.venv(), @r"
|
||||
uv_snapshot!(context.filters(), context.venv().arg("--clear"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
@ -560,7 +584,7 @@ fn create_venv_respects_group_requires_python() -> Result<()> {
|
|||
"#
|
||||
})?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.venv(), @r"
|
||||
uv_snapshot!(context.filters(), context.venv().arg("--clear"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
@ -593,7 +617,7 @@ fn create_venv_respects_group_requires_python() -> Result<()> {
|
|||
"#
|
||||
})?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.venv(), @r"
|
||||
uv_snapshot!(context.filters(), context.venv().arg("--clear"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
@ -621,7 +645,7 @@ fn create_venv_respects_group_requires_python() -> Result<()> {
|
|||
"#
|
||||
})?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.venv().arg("--python").arg("3.11"), @r"
|
||||
uv_snapshot!(context.filters(), context.venv().arg("--clear").arg("--python").arg("3.11"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
@ -654,7 +678,7 @@ fn create_venv_respects_group_requires_python() -> Result<()> {
|
|||
"#
|
||||
})?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.venv().arg("--python").arg("3.11"), @r"
|
||||
uv_snapshot!(context.filters(), context.venv().arg("--clear").arg("--python").arg("3.11"), @r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
|
@ -981,7 +1005,9 @@ fn non_empty_dir_exists() -> Result<()> {
|
|||
uv::venv::creation
|
||||
|
||||
× Failed to create virtualenv
|
||||
╰─▶ The directory `.venv` exists, but it's not a virtual environment
|
||||
╰─▶ The directory `.venv` exists.
|
||||
|
||||
hint: Use `--clear` to remove the directory first or `--allow-existing` to write to the directory without clearing
|
||||
"###
|
||||
);
|
||||
|
||||
|
@ -1011,7 +1037,9 @@ fn non_empty_dir_exists_allow_existing() -> Result<()> {
|
|||
uv::venv::creation
|
||||
|
||||
× Failed to create virtualenv
|
||||
╰─▶ The directory `.venv` exists, but it's not a virtual environment
|
||||
╰─▶ The directory `.venv` exists.
|
||||
|
||||
hint: Use `--clear` to remove the directory first or `--allow-existing` to write to the directory without clearing
|
||||
"###
|
||||
);
|
||||
|
||||
|
@ -1132,31 +1160,6 @@ fn windows_shims() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn virtualenv_compatibility() {
|
||||
let context = TestContext::new_with_versions(&["3.12"]);
|
||||
|
||||
// Create a virtual environment at `.venv`, passing the redundant `--clear` flag.
|
||||
uv_snapshot!(context.filters(), context.venv()
|
||||
.arg(context.venv.as_os_str())
|
||||
.arg("--clear")
|
||||
.arg("--python")
|
||||
.arg("3.12"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
warning: virtualenv's `--clear` has no effect (uv always clears the virtual environment)
|
||||
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Creating virtual environment at: .venv
|
||||
Activate with: source .venv/[BIN]/activate
|
||||
"###
|
||||
);
|
||||
|
||||
context.venv.assert(predicates::path::is_dir());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_pyvenv_cfg() {
|
||||
let context = TestContext::new("3.12");
|
||||
|
@ -1184,6 +1187,7 @@ fn verify_pyvenv_cfg_relocatable() {
|
|||
context
|
||||
.venv()
|
||||
.arg(context.venv.as_os_str())
|
||||
.arg("--clear")
|
||||
.arg("--python")
|
||||
.arg("3.12")
|
||||
.arg("--relocatable")
|
||||
|
|
|
@ -4554,7 +4554,7 @@ uv venv [OPTIONS] [PATH]
|
|||
<h3 class="cli-reference">Options</h3>
|
||||
|
||||
<dl class="cli-reference"><dt id="uv-venv--allow-existing"><a href="#uv-venv--allow-existing"><code>--allow-existing</code></a></dt><dd><p>Preserve any existing files or directories at the target path.</p>
|
||||
<p>By default, <code>uv venv</code> will remove an existing virtual environment at the given path, and exit with an error if the path is non-empty but <em>not</em> a virtual environment. The <code>--allow-existing</code> option will instead write to the given path, regardless of its contents, and without clearing it beforehand.</p>
|
||||
<p>By default, <code>uv venv</code> will exit with an error if the given path is non-empty. The <code>--allow-existing</code> option will instead write to the given path, regardless of its contents, and without clearing it beforehand.</p>
|
||||
<p>WARNING: This option can lead to unexpected behavior if the existing virtual environment and the newly-created virtual environment are linked to different Python interpreters.</p>
|
||||
</dd><dt id="uv-venv--allow-insecure-host"><a href="#uv-venv--allow-insecure-host"><code>--allow-insecure-host</code></a>, <code>--trusted-host</code> <i>allow-insecure-host</i></dt><dd><p>Allow insecure connections to a host.</p>
|
||||
<p>Can be provided multiple times.</p>
|
||||
|
@ -4563,7 +4563,9 @@ uv venv [OPTIONS] [PATH]
|
|||
<p>May also be set with the <code>UV_INSECURE_HOST</code> environment variable.</p></dd><dt id="uv-venv--cache-dir"><a href="#uv-venv--cache-dir"><code>--cache-dir</code></a> <i>cache-dir</i></dt><dd><p>Path to the cache directory.</p>
|
||||
<p>Defaults to <code>$XDG_CACHE_HOME/uv</code> or <code>$HOME/.cache/uv</code> on macOS and Linux, and <code>%LOCALAPPDATA%\uv\cache</code> on Windows.</p>
|
||||
<p>To view the location of the cache directory, run <code>uv cache dir</code>.</p>
|
||||
<p>May also be set with the <code>UV_CACHE_DIR</code> environment variable.</p></dd><dt id="uv-venv--color"><a href="#uv-venv--color"><code>--color</code></a> <i>color-choice</i></dt><dd><p>Control the use of color in output.</p>
|
||||
<p>May also be set with the <code>UV_CACHE_DIR</code> environment variable.</p></dd><dt id="uv-venv--clear"><a href="#uv-venv--clear"><code>--clear</code></a>, <code>-c</code></dt><dd><p>Remove any existing files or directories at the target path.</p>
|
||||
<p>By default, <code>uv venv</code> will exit with an error if the given path is non-empty. The <code>--clear</code> option will instead clear a non-empty path before creating a new virtual environment.</p>
|
||||
<p>May also be set with the <code>UV_VENV_CLEAR</code> environment variable.</p></dd><dt id="uv-venv--color"><a href="#uv-venv--color"><code>--color</code></a> <i>color-choice</i></dt><dd><p>Control the use of color in output.</p>
|
||||
<p>By default, uv will automatically detect support for colors when writing to a terminal.</p>
|
||||
<p>Possible values:</p>
|
||||
<ul>
|
||||
|
|
|
@ -433,6 +433,14 @@ Equivalent to the `--torch-backend` command-line argument (e.g., `cpu`, `cu126`,
|
|||
Used ephemeral environments like CI to install uv to a specific path while preventing
|
||||
the installer from modifying shell profiles or environment variables.
|
||||
|
||||
### `UV_VENV_CLEAR`
|
||||
|
||||
Remove any existing files or directories at the target path.
|
||||
|
||||
By default, `uv venv` will exit with an error if the given path is non-empty. The
|
||||
`--clear` option will instead clear a non-empty path before creating a new virtual
|
||||
environment.
|
||||
|
||||
### `UV_VENV_SEED`
|
||||
|
||||
Install seed packages (one or more of: `pip`, `setuptools`, and `wheel`) into the virtual environment
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue