mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 13:25:00 +00:00
Move virtual environment test context into main context (#4370)
It was becoming problematic that the virtual environment test context diverged from the other one i.e. we had to implement filtering twice. This combines the contexts and tweaks the `TestContext` API and filtering mechanisms for Python versions. Combined with my previous changes to the test context at #4364 and https://github.com/astral-sh/uv/pull/4368 this finally unblocks the snapshots for test cases in #4360 and https://github.com/astral-sh/uv/pull/4362.
This commit is contained in:
parent
a193834813
commit
76c26db444
8 changed files with 229 additions and 323 deletions
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
@ -168,7 +168,7 @@ jobs:
|
|||
steps:
|
||||
- name: Create Dev Drive using ReFS
|
||||
run: |
|
||||
$Volume = New-VHD -Path C:/uv_dev_drive.vhdx -SizeBytes 10GB |
|
||||
$Volume = New-VHD -Path C:/uv_dev_drive.vhdx -SizeBytes 12GB |
|
||||
Mount-VHD -Passthru |
|
||||
Initialize-Disk -Passthru |
|
||||
New-Partition -AssignDriveLetter -UseMaximumSize |
|
||||
|
|
|
@ -5,9 +5,9 @@ use assert_cmd::assert::{Assert, OutputAssertExt};
|
|||
use assert_cmd::Command;
|
||||
use assert_fs::assert::PathAssert;
|
||||
use assert_fs::fixture::{ChildPath, PathChild};
|
||||
use predicates::prelude::predicate;
|
||||
use regex::Regex;
|
||||
use std::borrow::BorrowMut;
|
||||
use std::collections::VecDeque;
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::iter::Iterator;
|
||||
|
@ -54,28 +54,55 @@ pub const INSTA_FILTERS: &[(&str, &str)] = &[
|
|||
/// * Set the current directory to a temporary directory (`temp_dir`).
|
||||
/// * Set the cache dir to a different temporary directory (`cache_dir`).
|
||||
/// * Set a cutoff for versions used in the resolution so the snapshots don't change after a new release.
|
||||
/// * Set the venv to a fresh `.venv` in `temp_dir`.
|
||||
#[derive(Debug)]
|
||||
/// * Set the venv to a fresh `.venv` in `temp_dir`
|
||||
pub struct TestContext {
|
||||
pub temp_dir: assert_fs::TempDir,
|
||||
pub cache_dir: assert_fs::TempDir,
|
||||
pub venv: PathBuf,
|
||||
pub python_version: String,
|
||||
pub venv: ChildPath,
|
||||
pub workspace_root: PathBuf,
|
||||
|
||||
// Additional Python versions
|
||||
python_versions: Vec<(PythonVersion, PathBuf)>,
|
||||
/// The Python version used for the virtual environment, if any.
|
||||
pub python_version: Option<PythonVersion>,
|
||||
|
||||
// All the Python versions available during this test context.
|
||||
pub python_versions: Vec<(PythonVersion, PathBuf)>,
|
||||
|
||||
// Standard filters for this test context
|
||||
filters: VecDeque<(String, String)>,
|
||||
filters: Vec<(String, String)>,
|
||||
}
|
||||
|
||||
impl TestContext {
|
||||
/// Create a new test context with a virtual environment.
|
||||
///
|
||||
/// See [`TestContext::new_with_versions`] if multiple versions are needed or
|
||||
/// if creation of the virtual environment should be deferred.
|
||||
pub fn new(python_version: &str) -> Self {
|
||||
let new = Self::new_with_versions(&[python_version]);
|
||||
new.create_venv();
|
||||
new
|
||||
}
|
||||
|
||||
/// Create a new test context with multiple Python versions.
|
||||
///
|
||||
/// Does not create a virtual environment by default, but the first Python version
|
||||
/// can be used to create a virtual environment with [`TestContext::create_venv`].
|
||||
///
|
||||
/// See [`TestContext::new`] if only a single version is desired.
|
||||
pub fn new_with_versions(python_versions: &[&str]) -> Self {
|
||||
let temp_dir = assert_fs::TempDir::new().expect("Failed to create temp dir");
|
||||
let cache_dir = assert_fs::TempDir::new().expect("Failed to create cache dir");
|
||||
let python = get_toolchain(python_version);
|
||||
let venv = create_venv_from_executable(&temp_dir, &cache_dir, &python);
|
||||
|
||||
// Canonicalize the temp dir for consistent snapshot behavior
|
||||
let canonical_temp_dir = temp_dir.canonicalize().unwrap();
|
||||
let venv = ChildPath::new(canonical_temp_dir.join(".venv"));
|
||||
|
||||
let python_version = python_versions
|
||||
.first()
|
||||
.map(|version| PythonVersion::from_str(version).unwrap());
|
||||
|
||||
let site_packages = python_version
|
||||
.as_ref()
|
||||
.map(|version| site_packages_path(&venv, &format!("python{version}")));
|
||||
|
||||
// The workspace root directory is not available without walking up the tree
|
||||
// https://github.com/rust-lang/cargo/issues/3946
|
||||
|
@ -86,28 +113,51 @@ impl TestContext {
|
|||
.expect("CARGO_MANIFEST_DIR should be doubly nested in workspace")
|
||||
.to_path_buf();
|
||||
|
||||
let site_packages = site_packages_path(&venv, &format!("python{python_version}"));
|
||||
let python_versions: Vec<_> = python_versions
|
||||
.iter()
|
||||
.map(|version| PythonVersion::from_str(version).unwrap())
|
||||
.zip(
|
||||
python_toolchains_for_versions(&temp_dir, python_versions)
|
||||
.expect("Failed to find test Python versions"),
|
||||
)
|
||||
.collect();
|
||||
|
||||
let python_version =
|
||||
PythonVersion::from_str(python_version).expect("Tests must use valid Python versions");
|
||||
|
||||
let mut filters = VecDeque::new();
|
||||
let mut filters = Vec::new();
|
||||
|
||||
filters.extend(
|
||||
Self::path_patterns(&cache_dir)
|
||||
.into_iter()
|
||||
.map(|pattern| (pattern, "[CACHE_DIR]/".to_string())),
|
||||
);
|
||||
filters.extend(
|
||||
Self::path_patterns(&site_packages)
|
||||
.into_iter()
|
||||
.map(|pattern| (pattern, "[SITE_PACKAGES]/".to_string())),
|
||||
);
|
||||
if let Some(ref site_packages) = site_packages {
|
||||
filters.extend(
|
||||
Self::path_patterns(site_packages)
|
||||
.into_iter()
|
||||
.map(|pattern| (pattern, "[SITE_PACKAGES]/".to_string())),
|
||||
);
|
||||
}
|
||||
filters.extend(
|
||||
Self::path_patterns(&venv)
|
||||
.into_iter()
|
||||
.map(|pattern| (pattern, "[VENV]/".to_string())),
|
||||
);
|
||||
for (version, executable) in &python_versions {
|
||||
// Add filtering for the interpreter path
|
||||
filters.extend(
|
||||
Self::path_patterns(executable)
|
||||
.into_iter()
|
||||
.map(|pattern| (format!("{pattern}python.*"), format!("[PYTHON-{version}]"))),
|
||||
);
|
||||
|
||||
// Add Python patch version filtering unless explicitly requested to ensure
|
||||
// snapshots are patch version agnostic when it is not a part of the test.
|
||||
if version.patch().is_none() {
|
||||
filters.push((
|
||||
format!(r"({})\.\d+", regex::escape(version.to_string().as_str())),
|
||||
"$1.[X]".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
filters.extend(
|
||||
Self::path_patterns(&temp_dir)
|
||||
.into_iter()
|
||||
|
@ -119,86 +169,42 @@ impl TestContext {
|
|||
.map(|pattern| (pattern, "[WORKSPACE]/".to_string())),
|
||||
);
|
||||
|
||||
// Make virtual environment activation cross-platform
|
||||
filters.push((
|
||||
r"Activate with: (?:.*)\\Scripts\\activate".to_string(),
|
||||
"Activate with: source .venv/bin/activate".to_string(),
|
||||
));
|
||||
|
||||
// Account for [`Simplified::user_display`] which is relative to the command working directory
|
||||
filters.push_back((
|
||||
Self::path_pattern(
|
||||
site_packages
|
||||
.strip_prefix(&temp_dir)
|
||||
.expect("The test site-packages directory is always in the tempdir"),
|
||||
),
|
||||
"[SITE_PACKAGES]/".to_string(),
|
||||
));
|
||||
filters.push_back((
|
||||
Self::path_pattern(
|
||||
venv.strip_prefix(&temp_dir)
|
||||
.expect("The test virtual environment directory is always in the tempdir"),
|
||||
),
|
||||
"[VENV]/".to_string(),
|
||||
));
|
||||
if let Some(site_packages) = site_packages {
|
||||
filters.push((
|
||||
Self::path_pattern(
|
||||
site_packages
|
||||
.strip_prefix(&canonical_temp_dir)
|
||||
.expect("The test site-packages directory is always in the tempdir"),
|
||||
),
|
||||
"[SITE_PACKAGES]/".to_string(),
|
||||
));
|
||||
};
|
||||
|
||||
// Filter non-deterministic temporary directory names
|
||||
// Note we apply this _after_ all the full paths to avoid breaking their matching
|
||||
filters.push_back((r"(\\|\/)\.tmp.*(\\|\/)".to_string(), "/[TMP]/".to_string()));
|
||||
filters.push((r"(\\|\/)\.tmp.*(\\|\/)".to_string(), "/[TMP]/".to_string()));
|
||||
|
||||
// Account for platform prefix differences `file://` (Unix) vs `file:///` (Windows)
|
||||
filters.push_back((r"file:///".to_string(), "file://".to_string()));
|
||||
filters.push((r"file:///".to_string(), "file://".to_string()));
|
||||
|
||||
// Destroy any remaining UNC prefixes (Windows only)
|
||||
filters.push_back((r"\\\\\?\\".to_string(), String::new()));
|
||||
filters.push((r"\\\\\?\\".to_string(), String::new()));
|
||||
|
||||
let mut result = Self {
|
||||
Self {
|
||||
temp_dir,
|
||||
cache_dir,
|
||||
venv,
|
||||
python_version: python_version.to_string(),
|
||||
filters,
|
||||
python_versions: Vec::new(),
|
||||
workspace_root,
|
||||
};
|
||||
|
||||
result.add_filters_for_python_version(&python_version, python);
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub fn new_with_versions(python_versions: &[&str]) -> Self {
|
||||
let mut context = Self::new(
|
||||
python_versions
|
||||
.first()
|
||||
.expect("At least one test Python version must be provided"),
|
||||
);
|
||||
|
||||
let python_versions: Vec<_> = python_versions
|
||||
.iter()
|
||||
.map(|version| PythonVersion::from_str(version).unwrap())
|
||||
.zip(
|
||||
python_toolchains_for_versions(&context.temp_dir, python_versions)
|
||||
.expect("Failed to find test Python versions"),
|
||||
)
|
||||
.collect();
|
||||
|
||||
for (version, path) in &python_versions {
|
||||
context.add_filters_for_python_version(version, path.clone());
|
||||
}
|
||||
|
||||
context.python_versions = python_versions;
|
||||
|
||||
context
|
||||
}
|
||||
|
||||
fn add_filters_for_python_version(&mut self, version: &PythonVersion, executable: PathBuf) {
|
||||
// Add filtering for the interpreter path
|
||||
for pattern in Self::path_patterns(executable) {
|
||||
self.filters
|
||||
.push_front((format!("{pattern}python.*"), format!("[PYTHON-{version}]")));
|
||||
}
|
||||
// Add Python patch version filtering unless explicitly requested to ensure
|
||||
// snapshots are patch version agnostic when it is not a part of the test.
|
||||
if version.patch().is_none() {
|
||||
self.filters.push_back((
|
||||
format!(r"({})\.\d+", regex::escape(version.to_string().as_str())),
|
||||
"$1.[X]".to_string(),
|
||||
));
|
||||
python_version,
|
||||
python_versions,
|
||||
filters,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -223,6 +229,7 @@ impl TestContext {
|
|||
.arg(self.cache_dir.path())
|
||||
.env("VIRTUAL_ENV", self.venv.as_os_str())
|
||||
.env("UV_NO_WRAP", "1")
|
||||
.env("UV_TOOLCHAIN_DIR", "")
|
||||
.env("UV_TEST_PYTHON_PATH", &self.python_path())
|
||||
.current_dir(self.temp_dir.path());
|
||||
|
||||
|
@ -235,6 +242,22 @@ impl TestContext {
|
|||
cmd
|
||||
}
|
||||
|
||||
/// Create a `uv venv` command
|
||||
pub fn venv(&self) -> std::process::Command {
|
||||
let mut command = std::process::Command::new(get_bin());
|
||||
command
|
||||
.arg("venv")
|
||||
.arg("--exclude-newer")
|
||||
.arg(EXCLUDE_NEWER)
|
||||
.env("UV_CACHE_DIR", self.cache_dir.path())
|
||||
.env("UV_TOOLCHAIN_DIR", "")
|
||||
.env("UV_TEST_PYTHON_PATH", &self.python_path())
|
||||
.env("UV_NO_WRAP", "1")
|
||||
.env("UV_STACK_SIZE", (2 * 1024 * 1024).to_string())
|
||||
.current_dir(self.temp_dir.as_os_str());
|
||||
command
|
||||
}
|
||||
|
||||
/// Create a `pip install` command with options shared across scenarios.
|
||||
pub fn install(&self) -> std::process::Command {
|
||||
let mut command = self.install_without_exclude_newer();
|
||||
|
@ -257,6 +280,7 @@ impl TestContext {
|
|||
.arg(self.cache_dir.path())
|
||||
.env("VIRTUAL_ENV", self.venv.as_os_str())
|
||||
.env("UV_NO_WRAP", "1")
|
||||
.env("UV_TOOLCHAIN_DIR", "")
|
||||
.env("UV_TEST_PYTHON_PATH", &self.python_path())
|
||||
.current_dir(&self.temp_dir);
|
||||
|
||||
|
@ -277,8 +301,10 @@ impl TestContext {
|
|||
.arg("--cache-dir")
|
||||
.arg(self.cache_dir.path())
|
||||
.env("VIRTUAL_ENV", self.venv.as_os_str())
|
||||
.env("UV_TOOLCHAIN_DIR", "")
|
||||
.env("UV_TEST_PYTHON_PATH", &self.python_path())
|
||||
.env("UV_NO_WRAP", "1")
|
||||
.env("UV_TOOLCHAIN_DIR", "")
|
||||
.env("UV_TEST_PYTHON_PATH", &self.python_path())
|
||||
.current_dir(&self.temp_dir);
|
||||
|
||||
|
@ -297,6 +323,7 @@ impl TestContext {
|
|||
command
|
||||
.arg("--exclude-newer")
|
||||
.arg(EXCLUDE_NEWER)
|
||||
.env("UV_TOOLCHAIN_DIR", "")
|
||||
.env("UV_TEST_PYTHON_PATH", &self.python_path());
|
||||
command
|
||||
}
|
||||
|
@ -315,6 +342,7 @@ impl TestContext {
|
|||
.arg(self.cache_dir.path())
|
||||
.env("VIRTUAL_ENV", self.venv.as_os_str())
|
||||
.env("UV_NO_WRAP", "1")
|
||||
.env("UV_TOOLCHAIN_DIR", "")
|
||||
.env("UV_TEST_PYTHON_PATH", &self.python_path())
|
||||
.current_dir(&self.temp_dir);
|
||||
|
||||
|
@ -327,10 +355,6 @@ impl TestContext {
|
|||
command
|
||||
}
|
||||
|
||||
pub fn toolchains_dir(&self) -> ChildPath {
|
||||
self.temp_dir.child("toolchains")
|
||||
}
|
||||
|
||||
/// Create a `uv toolchain find` command with options shared across scenarios.
|
||||
pub fn toolchain_find(&self) -> std::process::Command {
|
||||
let mut command = std::process::Command::new(get_bin());
|
||||
|
@ -341,9 +365,10 @@ impl TestContext {
|
|||
.arg(self.cache_dir.path())
|
||||
.env("VIRTUAL_ENV", self.venv.as_os_str())
|
||||
.env("UV_NO_WRAP", "1")
|
||||
.env("UV_TOOLCHAIN_DIR", "")
|
||||
.env("UV_TEST_PYTHON_PATH", &self.python_path())
|
||||
.env("UV_PREVIEW", "1")
|
||||
.env("UV_TOOLCHAIN_DIR", self.toolchains_dir().as_os_str())
|
||||
.env("UV_TOOLCHAIN_DIR", "")
|
||||
.current_dir(&self.temp_dir);
|
||||
|
||||
if cfg!(all(windows, debug_assertions)) {
|
||||
|
@ -376,6 +401,7 @@ impl TestContext {
|
|||
.arg(self.cache_dir.path())
|
||||
.env("VIRTUAL_ENV", self.venv.as_os_str())
|
||||
.env("UV_NO_WRAP", "1")
|
||||
.env("UV_TOOLCHAIN_DIR", "")
|
||||
.env("UV_TEST_PYTHON_PATH", &self.python_path())
|
||||
.current_dir(&self.temp_dir);
|
||||
|
||||
|
@ -497,7 +523,7 @@ impl TestContext {
|
|||
)
|
||||
}
|
||||
|
||||
fn python_path(&self) -> OsString {
|
||||
pub fn python_path(&self) -> OsString {
|
||||
std::env::join_paths(self.python_versions.iter().map(|(_, path)| path)).unwrap()
|
||||
}
|
||||
|
||||
|
@ -522,33 +548,29 @@ impl TestContext {
|
|||
pub fn site_packages(&self) -> PathBuf {
|
||||
site_packages_path(
|
||||
&self.venv,
|
||||
&format!("{}{}", self.python_kind(), self.python_version),
|
||||
&format!(
|
||||
"{}{}",
|
||||
self.python_kind(),
|
||||
self.python_version.as_ref().expect(
|
||||
"A Python version must be provided to retrieve the test site packages path"
|
||||
)
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/// Reset the virtual environment in the test context.
|
||||
pub fn reset_venv(&self) {
|
||||
create_venv_from_executable(
|
||||
&self.temp_dir,
|
||||
&self.cache_dir,
|
||||
&get_toolchain(&self.python_version),
|
||||
);
|
||||
self.create_venv();
|
||||
}
|
||||
|
||||
/// Create a new virtual environment named `.venv` in the test context.
|
||||
fn create_venv(&mut self, python: &str) -> PathBuf {
|
||||
let parent = self.temp_dir.to_path_buf();
|
||||
self.create_venv_in_parent(parent, python)
|
||||
}
|
||||
|
||||
/// Create a new virtual environment named `.venv` in the given directory.
|
||||
fn create_venv_in_parent<P: AsRef<Path>>(&mut self, path: P, python: &str) -> PathBuf {
|
||||
let executable = get_toolchain(python);
|
||||
self.add_filters_for_python_version(
|
||||
&PythonVersion::from_str(python).unwrap(),
|
||||
executable.clone(),
|
||||
fn create_venv(&self) {
|
||||
let executable = get_toolchain(
|
||||
self.python_version
|
||||
.as_ref()
|
||||
.expect("A Python version must be provided to create a test virtual environment"),
|
||||
);
|
||||
create_venv_from_executable(&ChildPath::new(path.as_ref()), &self.cache_dir, &executable)
|
||||
create_venv_from_executable(&self.venv, &self.cache_dir, &executable);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -562,11 +584,11 @@ pub fn site_packages_path(venv: &Path, python: &str) -> PathBuf {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn venv_bin_path(venv: &Path) -> PathBuf {
|
||||
pub fn venv_bin_path<P: AsRef<Path>>(venv: &P) -> PathBuf {
|
||||
if cfg!(unix) {
|
||||
venv.join("bin")
|
||||
venv.as_ref().join("bin")
|
||||
} else if cfg!(windows) {
|
||||
venv.join("Scripts")
|
||||
venv.as_ref().join("Scripts")
|
||||
} else {
|
||||
unimplemented!("Only Windows and Unix are supported")
|
||||
}
|
||||
|
@ -583,14 +605,11 @@ pub fn venv_to_interpreter(venv: &Path) -> PathBuf {
|
|||
}
|
||||
|
||||
/// Get the path to the python interpreter for a specific toolchain version.
|
||||
pub fn get_toolchain(python: &str) -> PathBuf {
|
||||
pub fn get_toolchain(version: &PythonVersion) -> PathBuf {
|
||||
InstalledToolchains::from_settings()
|
||||
.map(|installed_toolchains| {
|
||||
installed_toolchains
|
||||
.find_version(
|
||||
&PythonVersion::from_str(python)
|
||||
.expect("Tests should use a valid Python version"),
|
||||
)
|
||||
.find_version(version)
|
||||
.expect("Tests are run on a supported platform")
|
||||
.next()
|
||||
.as_ref()
|
||||
|
@ -599,31 +618,26 @@ pub fn get_toolchain(python: &str) -> PathBuf {
|
|||
// We'll search for the request Python on the PATH if not found in the toolchain versions
|
||||
// We hack this into a `PathBuf` to satisfy the compiler but it's just a string
|
||||
.unwrap_or_default()
|
||||
.unwrap_or(PathBuf::from(python))
|
||||
.unwrap_or(PathBuf::from(version.to_string()))
|
||||
}
|
||||
|
||||
/// Create a virtual environment named `.venv` in a temporary directory with the given
|
||||
/// Python executable.
|
||||
pub fn create_venv_from_executable<
|
||||
Parent: assert_fs::prelude::PathChild + AsRef<std::path::Path>,
|
||||
>(
|
||||
temp_dir: &Parent,
|
||||
/// Create a virtual environment at the given path.
|
||||
pub fn create_venv_from_executable<P: AsRef<std::path::Path>>(
|
||||
path: P,
|
||||
cache_dir: &assert_fs::TempDir,
|
||||
python: &Path,
|
||||
) -> PathBuf {
|
||||
let venv = temp_dir.child(".venv");
|
||||
) {
|
||||
Command::new(get_bin())
|
||||
.arg("venv")
|
||||
.arg(venv.as_os_str())
|
||||
.arg(path.as_ref().as_os_str())
|
||||
.arg("--cache-dir")
|
||||
.arg(cache_dir.path())
|
||||
.arg("--python")
|
||||
.arg(python)
|
||||
.current_dir(temp_dir)
|
||||
.current_dir(path.as_ref().parent().unwrap())
|
||||
.assert()
|
||||
.success();
|
||||
venv.assert(predicates::path::is_dir());
|
||||
venv.to_path_buf()
|
||||
ChildPath::new(path.as_ref()).assert(predicate::path::is_dir());
|
||||
}
|
||||
|
||||
/// Returns the uv binary that cargo built before launching the tests.
|
||||
|
|
|
@ -1894,7 +1894,7 @@ fn lock_requires_python() -> Result<()> {
|
|||
|
||||
----- stderr -----
|
||||
warning: `uv sync` is experimental and may change without warning.
|
||||
Removing virtual environment at: [VENV]/
|
||||
Removing virtual environment at: .venv
|
||||
error: No interpreter found for Python >=3.12 in provided path, active virtual environment, or search path
|
||||
"###);
|
||||
|
||||
|
|
|
@ -127,24 +127,23 @@ fn missing_requirements_in() {
|
|||
fn missing_venv() -> Result<()> {
|
||||
let context = TestContext::new("3.12");
|
||||
context.temp_dir.child("requirements.in").touch()?;
|
||||
fs_err::remove_dir_all(context.temp_dir.child(".venv").path())?;
|
||||
fs_err::remove_dir_all(context.venv.path())?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.compile()
|
||||
.arg("requirements.in"), @r###"
|
||||
success: false
|
||||
exit_code: 2
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
# This file was autogenerated by uv via the following command:
|
||||
# uv pip compile --cache-dir [CACHE_DIR] --exclude-newer 2024-03-25T00:00:00Z requirements.in
|
||||
|
||||
----- stderr -----
|
||||
warning: Requirements file requirements.in does not contain any dependencies
|
||||
error: No Python interpreters found in provided path, active virtual environment, or search path
|
||||
Resolved 0 packages in [TIME]
|
||||
"###
|
||||
);
|
||||
|
||||
context
|
||||
.temp_dir
|
||||
.child(".venv")
|
||||
.assert(predicates::path::missing());
|
||||
context.venv.assert(predicates::path::missing());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -3954,7 +3954,7 @@ fn install_package_basic_auth_from_keyring() {
|
|||
.arg("subprocess")
|
||||
.arg("--strict")
|
||||
.env("KEYRING_TEST_CREDENTIALS", r#"{"pypi-proxy.fly.dev": {"public": "heron"}}"#)
|
||||
.env("PATH", venv_bin_path(context.venv.as_path())), @r###"
|
||||
.env("PATH", venv_bin_path(&context.venv)), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
@ -4001,7 +4001,7 @@ fn install_package_basic_auth_from_keyring_wrong_password() {
|
|||
.arg("subprocess")
|
||||
.arg("--strict")
|
||||
.env("KEYRING_TEST_CREDENTIALS", r#"{"pypi-proxy.fly.dev": {"public": "foobar"}}"#)
|
||||
.env("PATH", venv_bin_path(context.venv.as_path())), @r###"
|
||||
.env("PATH", venv_bin_path(&context.venv)), @r###"
|
||||
success: false
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
@ -4042,7 +4042,7 @@ fn install_package_basic_auth_from_keyring_wrong_username() {
|
|||
.arg("subprocess")
|
||||
.arg("--strict")
|
||||
.env("KEYRING_TEST_CREDENTIALS", r#"{"pypi-proxy.fly.dev": {"other": "heron"}}"#)
|
||||
.env("PATH", venv_bin_path(context.venv.as_path())), @r###"
|
||||
.env("PATH", venv_bin_path(&context.venv)), @r###"
|
||||
success: false
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
|
|
@ -51,6 +51,8 @@ fn run_with_python_version() -> Result<()> {
|
|||
3.7.0
|
||||
|
||||
----- stderr -----
|
||||
Using Python 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Creating virtualenv at: .venv
|
||||
Resolved 5 packages in [TIME]
|
||||
Downloaded 4 packages in [TIME]
|
||||
Installed 4 packages in [TIME]
|
||||
|
@ -100,9 +102,9 @@ fn run_with_python_version() -> Result<()> {
|
|||
3.6.0
|
||||
|
||||
----- stderr -----
|
||||
Removing virtual environment at: [VENV]/
|
||||
Removing virtual environment at: .venv
|
||||
Using Python 3.11.[X] interpreter at: [PYTHON-3.11]
|
||||
Creating virtualenv at: [VENV]/
|
||||
Creating virtualenv at: .venv
|
||||
Resolved 5 packages in [TIME]
|
||||
Downloaded 4 packages in [TIME]
|
||||
Installed 4 packages in [TIME]
|
||||
|
|
|
@ -1,117 +1,19 @@
|
|||
#![cfg(feature = "python")]
|
||||
|
||||
use std::process::Command;
|
||||
use std::{ffi::OsString, str::FromStr};
|
||||
|
||||
use anyhow::Result;
|
||||
use assert_cmd::prelude::*;
|
||||
use assert_fs::fixture::ChildPath;
|
||||
use assert_fs::prelude::*;
|
||||
#[cfg(windows)]
|
||||
use uv_fs::Simplified;
|
||||
use uv_toolchain::PythonVersion;
|
||||
|
||||
use crate::common::{get_bin, python_path_with_versions, uv_snapshot, TestContext, EXCLUDE_NEWER};
|
||||
use crate::common::{uv_snapshot, TestContext};
|
||||
|
||||
mod common;
|
||||
|
||||
struct VenvTestContext {
|
||||
cache_dir: assert_fs::TempDir,
|
||||
temp_dir: assert_fs::TempDir,
|
||||
venv: ChildPath,
|
||||
toolchain_dir: ChildPath,
|
||||
python_path: OsString,
|
||||
python_versions: Vec<PythonVersion>,
|
||||
}
|
||||
|
||||
impl VenvTestContext {
|
||||
fn new(python_versions: &[&str]) -> Self {
|
||||
let temp_dir = assert_fs::TempDir::new().unwrap();
|
||||
let python_path = python_path_with_versions(&temp_dir, python_versions)
|
||||
.expect("Failed to create Python test path");
|
||||
|
||||
let toolchain_dir = temp_dir.child("toolchains");
|
||||
toolchain_dir.create_dir_all().unwrap();
|
||||
|
||||
// Canonicalize the virtual environment path for consistent snapshots across platforms
|
||||
let venv = ChildPath::new(temp_dir.canonicalize().unwrap().join(".venv"));
|
||||
|
||||
let python_versions = python_versions
|
||||
.iter()
|
||||
.map(|version| {
|
||||
PythonVersion::from_str(version).expect("Tests should use valid Python versions")
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
Self {
|
||||
cache_dir: assert_fs::TempDir::new().unwrap(),
|
||||
temp_dir,
|
||||
toolchain_dir,
|
||||
venv,
|
||||
python_path,
|
||||
python_versions,
|
||||
}
|
||||
}
|
||||
|
||||
fn venv_command(&self) -> Command {
|
||||
let mut command = Command::new(get_bin());
|
||||
command
|
||||
.arg("venv")
|
||||
.arg("--cache-dir")
|
||||
.arg(self.cache_dir.path())
|
||||
.arg("--exclude-newer")
|
||||
.arg(EXCLUDE_NEWER)
|
||||
.env("UV_TOOLCHAIN_DIR", self.toolchain_dir.as_os_str())
|
||||
.env("UV_TEST_PYTHON_PATH", self.python_path.clone())
|
||||
.env("UV_NO_WRAP", "1")
|
||||
.env("UV_STACK_SIZE", (2 * 1024 * 1024).to_string())
|
||||
.current_dir(self.temp_dir.as_os_str());
|
||||
command
|
||||
}
|
||||
|
||||
fn filters(&self) -> Vec<(String, String)> {
|
||||
let mut filters = Vec::new();
|
||||
filters.extend(
|
||||
TestContext::path_patterns(&self.temp_dir)
|
||||
.into_iter()
|
||||
.map(|pattern| (pattern, "[TEMP_DIR]/".to_string())),
|
||||
);
|
||||
filters.push((
|
||||
r"interpreter at: .+".to_string(),
|
||||
"interpreter at: [PATH]".to_string(),
|
||||
));
|
||||
filters.push((
|
||||
r"Activate with: (?:.*)\\Scripts\\activate".to_string(),
|
||||
"Activate with: source .venv/bin/activate".to_string(),
|
||||
));
|
||||
|
||||
// Add Python patch version filtering unless one was explicitly requested to ensure
|
||||
// snapshots are patch version agnostic when it is not a part of the test.
|
||||
if self
|
||||
.python_versions
|
||||
.iter()
|
||||
.all(|version| version.patch().is_none())
|
||||
{
|
||||
for python_version in &self.python_versions {
|
||||
filters.push((
|
||||
format!(
|
||||
r"({})\.\d+",
|
||||
regex::escape(python_version.to_string().as_str())
|
||||
),
|
||||
"$1.[X]".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
filters
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_venv() {
|
||||
let context = VenvTestContext::new(&["3.12"]);
|
||||
let context = TestContext::new_with_versions(&["3.12"]);
|
||||
|
||||
// Create a virtual environment at `.venv`.
|
||||
uv_snapshot!(context.filters(), context.venv_command()
|
||||
uv_snapshot!(context.filters(), context.venv()
|
||||
.arg(context.venv.as_os_str())
|
||||
.arg("--python")
|
||||
.arg("3.12"), @r###"
|
||||
|
@ -120,7 +22,7 @@ fn create_venv() {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using Python 3.12.[X] interpreter at: [PATH]
|
||||
Using Python 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Creating virtualenv at: .venv
|
||||
Activate with: source .venv/bin/activate
|
||||
"###
|
||||
|
@ -129,7 +31,7 @@ fn create_venv() {
|
|||
context.venv.assert(predicates::path::is_dir());
|
||||
|
||||
// Create a virtual environment at the same location, which should replace it.
|
||||
uv_snapshot!(context.filters(), context.venv_command()
|
||||
uv_snapshot!(context.filters(), context.venv()
|
||||
.arg(context.venv.as_os_str())
|
||||
.arg("--python")
|
||||
.arg("3.12"), @r###"
|
||||
|
@ -138,7 +40,7 @@ fn create_venv() {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using Python 3.12.[X] interpreter at: [PATH]
|
||||
Using Python 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Creating virtualenv at: .venv
|
||||
Activate with: source .venv/bin/activate
|
||||
"###
|
||||
|
@ -149,8 +51,8 @@ fn create_venv() {
|
|||
|
||||
#[test]
|
||||
fn create_venv_defaults_to_cwd() {
|
||||
let context = VenvTestContext::new(&["3.12"]);
|
||||
uv_snapshot!(context.filters(), context.venv_command()
|
||||
let context = TestContext::new_with_versions(&["3.12"]);
|
||||
uv_snapshot!(context.filters(), context.venv()
|
||||
.arg("--python")
|
||||
.arg("3.12"), @r###"
|
||||
success: true
|
||||
|
@ -158,7 +60,7 @@ fn create_venv_defaults_to_cwd() {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using Python 3.12.[X] interpreter at: [PATH]
|
||||
Using Python 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Creating virtualenv at: .venv
|
||||
Activate with: source .venv/bin/activate
|
||||
"###
|
||||
|
@ -169,17 +71,17 @@ fn create_venv_defaults_to_cwd() {
|
|||
|
||||
#[test]
|
||||
fn create_venv_ignores_virtual_env_variable() {
|
||||
let context = VenvTestContext::new(&["3.12"]);
|
||||
let context = TestContext::new_with_versions(&["3.12"]);
|
||||
// We shouldn't care if `VIRTUAL_ENV` is set to an non-existent directory
|
||||
// because we ignore virtual environment interpreter sources (we require a system interpreter)
|
||||
uv_snapshot!(context.filters(), context.venv_command()
|
||||
uv_snapshot!(context.filters(), context.venv()
|
||||
.env("VIRTUAL_ENV", context.temp_dir.child("does-not-exist").as_os_str()), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using Python 3.12.[X] interpreter at: [PATH]
|
||||
Using Python 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Creating virtualenv at: .venv
|
||||
Activate with: source .venv/bin/activate
|
||||
"###
|
||||
|
@ -188,8 +90,8 @@ fn create_venv_ignores_virtual_env_variable() {
|
|||
|
||||
#[test]
|
||||
fn seed() {
|
||||
let context = VenvTestContext::new(&["3.12"]);
|
||||
uv_snapshot!(context.filters(), context.venv_command()
|
||||
let context = TestContext::new_with_versions(&["3.12"]);
|
||||
uv_snapshot!(context.filters(), context.venv()
|
||||
.arg(context.venv.as_os_str())
|
||||
.arg("--seed")
|
||||
.arg("--python")
|
||||
|
@ -199,7 +101,7 @@ fn seed() {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using Python 3.12.[X] interpreter at: [PATH]
|
||||
Using Python 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Creating virtualenv at: .venv
|
||||
+ pip==24.0
|
||||
Activate with: source .venv/bin/activate
|
||||
|
@ -211,8 +113,8 @@ fn seed() {
|
|||
|
||||
#[test]
|
||||
fn seed_older_python_version() {
|
||||
let context = VenvTestContext::new(&["3.10"]);
|
||||
uv_snapshot!(context.filters(), context.venv_command()
|
||||
let context = TestContext::new_with_versions(&["3.10"]);
|
||||
uv_snapshot!(context.filters(), context.venv()
|
||||
.arg(context.venv.as_os_str())
|
||||
.arg("--seed")
|
||||
.arg("--python")
|
||||
|
@ -222,7 +124,7 @@ fn seed_older_python_version() {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using Python 3.10.[X] interpreter at: [PATH]
|
||||
Using Python 3.10.[X] interpreter at: [PYTHON-3.10]
|
||||
Creating virtualenv at: .venv
|
||||
+ pip==24.0
|
||||
+ setuptools==69.2.0
|
||||
|
@ -236,9 +138,9 @@ fn seed_older_python_version() {
|
|||
|
||||
#[test]
|
||||
fn create_venv_unknown_python_minor() {
|
||||
let context = VenvTestContext::new(&["3.12"]);
|
||||
let context = TestContext::new_with_versions(&["3.12"]);
|
||||
|
||||
let mut command = context.venv_command();
|
||||
let mut command = context.venv();
|
||||
command
|
||||
.arg(context.venv.as_os_str())
|
||||
// Request a version we know we'll never see
|
||||
|
@ -274,9 +176,9 @@ fn create_venv_unknown_python_minor() {
|
|||
|
||||
#[test]
|
||||
fn create_venv_unknown_python_patch() {
|
||||
let context = VenvTestContext::new(&["3.12"]);
|
||||
let context = TestContext::new_with_versions(&["3.12"]);
|
||||
|
||||
let mut command = context.venv_command();
|
||||
let mut command = context.venv();
|
||||
command
|
||||
.arg(context.venv.as_os_str())
|
||||
// Request a version we know we'll never see
|
||||
|
@ -313,9 +215,9 @@ fn create_venv_unknown_python_patch() {
|
|||
#[cfg(feature = "python-patch")]
|
||||
#[test]
|
||||
fn create_venv_python_patch() {
|
||||
let context = VenvTestContext::new(&["3.12.1"]);
|
||||
let context = TestContext::new_with_versions(&["3.12.1"]);
|
||||
|
||||
uv_snapshot!(context.filters(), context.venv_command()
|
||||
uv_snapshot!(context.filters(), context.venv()
|
||||
.arg(context.venv.as_os_str())
|
||||
.arg("--python")
|
||||
.arg("3.12.1"), @r###"
|
||||
|
@ -324,7 +226,7 @@ fn create_venv_python_patch() {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using Python 3.12.1 interpreter at: [PATH]
|
||||
Using Python 3.12.1 interpreter at: [PYTHON-3.12.1]
|
||||
Creating virtualenv at: .venv
|
||||
Activate with: source .venv/bin/activate
|
||||
"###
|
||||
|
@ -335,12 +237,12 @@ fn create_venv_python_patch() {
|
|||
|
||||
#[test]
|
||||
fn file_exists() -> Result<()> {
|
||||
let context = VenvTestContext::new(&["3.12"]);
|
||||
let context = TestContext::new_with_versions(&["3.12"]);
|
||||
|
||||
// Create a file at `.venv`. Creating a virtualenv at the same path should fail.
|
||||
context.venv.touch()?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.venv_command()
|
||||
uv_snapshot!(context.filters(), context.venv()
|
||||
.arg(context.venv.as_os_str())
|
||||
.arg("--python")
|
||||
.arg("3.12"), @r###"
|
||||
|
@ -349,7 +251,7 @@ fn file_exists() -> Result<()> {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using Python 3.12.[X] interpreter at: [PATH]
|
||||
Using Python 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Creating virtualenv at: .venv
|
||||
uv::venv::creation
|
||||
|
||||
|
@ -363,11 +265,11 @@ fn file_exists() -> Result<()> {
|
|||
|
||||
#[test]
|
||||
fn empty_dir_exists() -> Result<()> {
|
||||
let context = VenvTestContext::new(&["3.12"]);
|
||||
let context = TestContext::new_with_versions(&["3.12"]);
|
||||
|
||||
// Create an empty directory at `.venv`. Creating a virtualenv at the same path should succeed.
|
||||
context.venv.create_dir_all()?;
|
||||
uv_snapshot!(context.filters(), context.venv_command()
|
||||
uv_snapshot!(context.filters(), context.venv()
|
||||
.arg(context.venv.as_os_str())
|
||||
.arg("--python")
|
||||
.arg("3.12"), @r###"
|
||||
|
@ -376,7 +278,7 @@ fn empty_dir_exists() -> Result<()> {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using Python 3.12.[X] interpreter at: [PATH]
|
||||
Using Python 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Creating virtualenv at: .venv
|
||||
Activate with: source .venv/bin/activate
|
||||
"###
|
||||
|
@ -389,13 +291,13 @@ fn empty_dir_exists() -> Result<()> {
|
|||
|
||||
#[test]
|
||||
fn non_empty_dir_exists() -> Result<()> {
|
||||
let context = VenvTestContext::new(&["3.12"]);
|
||||
let context = TestContext::new_with_versions(&["3.12"]);
|
||||
|
||||
// Create a non-empty directory at `.venv`. Creating a virtualenv at the same path should fail.
|
||||
context.venv.create_dir_all()?;
|
||||
context.venv.child("file").touch()?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.venv_command()
|
||||
uv_snapshot!(context.filters(), context.venv()
|
||||
.arg(context.venv.as_os_str())
|
||||
.arg("--python")
|
||||
.arg("3.12"), @r###"
|
||||
|
@ -404,7 +306,7 @@ fn non_empty_dir_exists() -> Result<()> {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using Python 3.12.[X] interpreter at: [PATH]
|
||||
Using Python 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Creating virtualenv at: .venv
|
||||
uv::venv::creation
|
||||
|
||||
|
@ -418,14 +320,14 @@ fn non_empty_dir_exists() -> Result<()> {
|
|||
|
||||
#[test]
|
||||
fn non_empty_dir_exists_allow_existing() -> Result<()> {
|
||||
let context = VenvTestContext::new(&["3.12"]);
|
||||
let context = TestContext::new_with_versions(&["3.12"]);
|
||||
|
||||
// Create a non-empty directory at `.venv`. Creating a virtualenv at the same path should
|
||||
// succeed when `--allow-existing` is specified, but fail when it is not.
|
||||
context.venv.create_dir_all()?;
|
||||
context.venv.child("file").touch()?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.venv_command()
|
||||
uv_snapshot!(context.filters(), context.venv()
|
||||
.arg(context.venv.as_os_str())
|
||||
.arg("--python")
|
||||
.arg("3.12"), @r###"
|
||||
|
@ -434,7 +336,7 @@ fn non_empty_dir_exists_allow_existing() -> Result<()> {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using Python 3.12.[X] interpreter at: [PATH]
|
||||
Using Python 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Creating virtualenv at: .venv
|
||||
uv::venv::creation
|
||||
|
||||
|
@ -443,7 +345,7 @@ fn non_empty_dir_exists_allow_existing() -> Result<()> {
|
|||
"###
|
||||
);
|
||||
|
||||
uv_snapshot!(context.filters(), context.venv_command()
|
||||
uv_snapshot!(context.filters(), context.venv()
|
||||
.arg(context.venv.as_os_str())
|
||||
.arg("--allow-existing")
|
||||
.arg("--python")
|
||||
|
@ -453,7 +355,7 @@ fn non_empty_dir_exists_allow_existing() -> Result<()> {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using Python 3.12.[X] interpreter at: [PATH]
|
||||
Using Python 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Creating virtualenv at: .venv
|
||||
Activate with: source .venv/bin/activate
|
||||
"###
|
||||
|
@ -461,7 +363,7 @@ fn non_empty_dir_exists_allow_existing() -> Result<()> {
|
|||
|
||||
// Running again should _also_ succeed, overwriting existing symlinks and respecting existing
|
||||
// directories.
|
||||
uv_snapshot!(context.filters(), context.venv_command()
|
||||
uv_snapshot!(context.filters(), context.venv()
|
||||
.arg(context.venv.as_os_str())
|
||||
.arg("--allow-existing")
|
||||
.arg("--python")
|
||||
|
@ -471,7 +373,7 @@ fn non_empty_dir_exists_allow_existing() -> Result<()> {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using Python 3.12.[X] interpreter at: [PATH]
|
||||
Using Python 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Creating virtualenv at: .venv
|
||||
Activate with: source .venv/bin/activate
|
||||
"###
|
||||
|
@ -483,37 +385,37 @@ fn non_empty_dir_exists_allow_existing() -> Result<()> {
|
|||
#[test]
|
||||
#[cfg(windows)]
|
||||
fn windows_shims() -> Result<()> {
|
||||
let context = VenvTestContext::new(&["3.9", "3.8"]);
|
||||
let context = TestContext::new_with_versions(&["3.9", "3.8"]);
|
||||
let shim_path = context.temp_dir.child("shim");
|
||||
|
||||
let py38 = std::env::split_paths(&context.python_path)
|
||||
let py38 = context
|
||||
.python_versions
|
||||
.last()
|
||||
.expect("python_path_with_versions to set up the python versions");
|
||||
|
||||
// We want 3.8 and the first version should be 3.9.
|
||||
// Picking the last is necessary to prove that shims work because the python version selects
|
||||
// the python version from the first path segment by default, so we take the last to prove it's not
|
||||
// returning that version.
|
||||
assert!(py38.to_str().unwrap().contains("3.8"));
|
||||
assert!(py38.0.to_string().contains("3.8"));
|
||||
|
||||
// Write the shim script that forwards the arguments to the python3.8 installation.
|
||||
fs_err::create_dir(&shim_path)?;
|
||||
fs_err::write(
|
||||
shim_path.child("python.bat"),
|
||||
format!("@echo off\r\n{}/python.exe %*", py38.display()),
|
||||
format!("@echo off\r\n{}/python.exe %*", py38.1.display()),
|
||||
)?;
|
||||
|
||||
// Create a virtual environment at `.venv`, passing the redundant `--clear` flag.
|
||||
uv_snapshot!(context.filters(), context.venv_command()
|
||||
// Create a virtual environment at `.venv` with the shim
|
||||
uv_snapshot!(context.filters(), context.venv()
|
||||
.arg(context.venv.as_os_str())
|
||||
.arg("--clear")
|
||||
.env("UV_TEST_PYTHON_PATH", format!("{};{}", shim_path.display(), context.python_path.simplified_display())), @r###"
|
||||
.env("UV_TEST_PYTHON_PATH", format!("{};{}", shim_path.display(), context.python_path().to_string_lossy())), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
warning: virtualenv's `--clear` has no effect (uv always clears the virtual environment).
|
||||
Using Python 3.8.[X] interpreter at: [PATH]
|
||||
Using Python 3.8.[X] interpreter at: [PYTHON-3.8]
|
||||
Creating virtualenv at: .venv
|
||||
Activate with: source .venv/bin/activate
|
||||
"###
|
||||
|
@ -526,10 +428,10 @@ fn windows_shims() -> Result<()> {
|
|||
|
||||
#[test]
|
||||
fn virtualenv_compatibility() {
|
||||
let context = VenvTestContext::new(&["3.12"]);
|
||||
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_command()
|
||||
uv_snapshot!(context.filters(), context.venv()
|
||||
.arg(context.venv.as_os_str())
|
||||
.arg("--clear")
|
||||
.arg("--python")
|
||||
|
@ -540,7 +442,7 @@ fn virtualenv_compatibility() {
|
|||
|
||||
----- stderr -----
|
||||
warning: virtualenv's `--clear` has no effect (uv always clears the virtual environment).
|
||||
Using Python 3.12.[X] interpreter at: [PATH]
|
||||
Using Python 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Creating virtualenv at: .venv
|
||||
Activate with: source .venv/bin/activate
|
||||
"###
|
||||
|
@ -552,10 +454,9 @@ fn virtualenv_compatibility() {
|
|||
#[test]
|
||||
fn verify_pyvenv_cfg() {
|
||||
let context = TestContext::new("3.12");
|
||||
let venv = context.temp_dir.child(".venv");
|
||||
let pyvenv_cfg = venv.child("pyvenv.cfg");
|
||||
let pyvenv_cfg = context.venv.child("pyvenv.cfg");
|
||||
|
||||
venv.assert(predicates::path::is_dir());
|
||||
context.venv.assert(predicates::path::is_dir());
|
||||
|
||||
// Check pyvenv.cfg exists
|
||||
pyvenv_cfg.assert(predicates::path::is_file());
|
||||
|
@ -569,11 +470,11 @@ fn verify_pyvenv_cfg() {
|
|||
/// Ensure that a nested virtual environment uses the same `home` directory as the parent.
|
||||
#[test]
|
||||
fn verify_nested_pyvenv_cfg() -> Result<()> {
|
||||
let context = VenvTestContext::new(&["3.12"]);
|
||||
let context = TestContext::new_with_versions(&["3.12"]);
|
||||
|
||||
// Create a virtual environment at `.venv`.
|
||||
context
|
||||
.venv_command()
|
||||
.venv()
|
||||
.arg(context.venv.as_os_str())
|
||||
.arg("--python")
|
||||
.arg("3.12")
|
||||
|
@ -595,7 +496,7 @@ fn verify_nested_pyvenv_cfg() -> Result<()> {
|
|||
// Now, create a virtual environment from within the virtual environment.
|
||||
let subvenv = context.temp_dir.child(".subvenv");
|
||||
context
|
||||
.venv_command()
|
||||
.venv()
|
||||
.arg(subvenv.as_os_str())
|
||||
.arg("--python")
|
||||
.arg("3.12")
|
||||
|
@ -622,29 +523,19 @@ fn verify_nested_pyvenv_cfg() -> Result<()> {
|
|||
#[test]
|
||||
#[cfg(windows)]
|
||||
fn path_with_trailing_space_gives_proper_error() {
|
||||
let context = VenvTestContext::new(&["3.12"]);
|
||||
let context = TestContext::new_with_versions(&["3.12"]);
|
||||
|
||||
let mut filters = context.filters();
|
||||
filters.push((
|
||||
regex::escape(&context.cache_dir.path().display().to_string()).to_string(),
|
||||
r"C:\Path\to\Cache\dir".to_string(),
|
||||
));
|
||||
// Create a virtual environment at `.venv`.
|
||||
uv_snapshot!(filters, Command::new(get_bin())
|
||||
.arg("venv")
|
||||
.arg(context.venv.as_os_str())
|
||||
.arg("--python")
|
||||
.arg("3.12")
|
||||
.env("UV_CACHE_DIR", format!("{} ", context.cache_dir.path().display()))
|
||||
.env("UV_TEST_PYTHON_PATH", context.python_path.clone())
|
||||
.current_dir(context.temp_dir.path()), @r###"
|
||||
// Set a custom cache directory with a trailing space
|
||||
uv_snapshot!(context.filters(), context.venv()
|
||||
.env("UV_CACHE_DIR", format!("{} ", context.cache_dir.path().display())), @r###"
|
||||
success: false
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
error: failed to open file `C:\Path\to\Cache\dir \CACHEDIR.TAG`
|
||||
error: failed to open file `[CACHE_DIR]/ /CACHEDIR.TAG`
|
||||
Caused by: The system cannot find the path specified. (os error 3)
|
||||
"###
|
||||
);
|
||||
// Note the extra trailing `/` in the snapshot is due to the filters, not the actual output.
|
||||
}
|
||||
|
|
|
@ -419,7 +419,7 @@ fn test_uv_run_with_package_virtual_workspace() -> Result<()> {
|
|||
|
||||
----- stderr -----
|
||||
Using Python 3.12.[X] interpreter at: [PYTHON]
|
||||
Creating virtualenv at: [VENV]/
|
||||
Creating virtualenv at: .venv
|
||||
Resolved 8 packages in [TIME]
|
||||
Downloaded 5 packages in [TIME]
|
||||
Installed 5 packages in [TIME]
|
||||
|
@ -479,7 +479,7 @@ fn test_uv_run_with_package_root_workspace() -> Result<()> {
|
|||
|
||||
----- stderr -----
|
||||
Using Python 3.12.[X] interpreter at: [PYTHON]
|
||||
Creating virtualenv at: [VENV]/
|
||||
Creating virtualenv at: .venv
|
||||
Resolved 8 packages in [TIME]
|
||||
Downloaded 5 packages in [TIME]
|
||||
Installed 5 packages in [TIME]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue