From 524e2faa803df1cebb9bf4fc0eefdaf5e32ab9a4 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Tue, 19 Mar 2024 22:39:04 -0400 Subject: [PATCH] Add to trait --- Cargo.lock | 1 + crates/distribution-types/src/installed.rs | 8 +- crates/install-wheel-rs/src/lib.rs | 4 +- crates/install-wheel-rs/src/wheel.rs | 2 +- crates/requirements-txt/src/lib.rs | 54 +++++------ crates/uv-fs/Cargo.toml | 1 + crates/uv-fs/src/lib.rs | 6 +- crates/uv-fs/src/path.rs | 26 +++--- crates/uv-git/src/git.rs | 4 +- crates/uv-installer/src/compile.rs | 2 +- crates/uv-installer/src/plan.rs | 2 +- crates/uv-interpreter/src/interpreter.rs | 6 +- crates/uv-virtualenv/src/bare.rs | 4 +- crates/uv/src/commands/cache_clean.rs | 9 +- crates/uv/src/commands/cache_dir.rs | 2 +- crates/uv/src/commands/mod.rs | 2 +- crates/uv/src/commands/pip_check.rs | 2 +- crates/uv/src/commands/pip_compile.rs | 4 +- crates/uv/src/commands/pip_freeze.rs | 2 +- crates/uv/src/commands/pip_install.rs | 8 +- crates/uv/src/commands/pip_list.rs | 2 +- crates/uv/src/commands/pip_show.rs | 2 +- crates/uv/src/commands/pip_sync.rs | 8 +- crates/uv/src/commands/pip_uninstall.rs | 6 +- crates/uv/src/commands/venv.rs | 12 +-- crates/uv/src/requirements.rs | 6 +- crates/uv/tests/pip_compile.rs | 22 ++--- crates/uv/tests/pip_sync.rs | 24 ++--- crates/uv/tests/pip_uninstall.rs | 17 +--- crates/uv/tests/venv.rs | 104 ++++++++------------- 30 files changed, 147 insertions(+), 205 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e69064024c3a0..ef9feed6d4f38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4748,6 +4748,7 @@ dependencies = [ "fs-err", "fs2", "junction", + "once_cell", "tempfile", "tokio", "tracing", diff --git a/crates/distribution-types/src/installed.rs b/crates/distribution-types/src/installed.rs index 74f190a8917cd..541a329699903 100644 --- a/crates/distribution-types/src/installed.rs +++ b/crates/distribution-types/src/installed.rs @@ -114,12 +114,8 @@ impl InstalledDist { pub fn metadata(&self) -> Result { let path = self.path().join("METADATA"); let contents = fs::read(&path)?; - pypi_types::Metadata23::parse_metadata(&contents).with_context(|| { - format!( - "Failed to parse METADATA file at: {}", - path.simplified_display() - ) - }) + pypi_types::Metadata23::parse_metadata(&contents) + .with_context(|| format!("Failed to parse METADATA file at: {}", path.user_display())) } /// Return the `INSTALLER` of the distribution. diff --git a/crates/install-wheel-rs/src/lib.rs b/crates/install-wheel-rs/src/lib.rs index d9051c7a873b1..bacd0651ab4e3 100644 --- a/crates/install-wheel-rs/src/lib.rs +++ b/crates/install-wheel-rs/src/lib.rs @@ -41,7 +41,7 @@ pub enum Error { #[error(transparent)] Io(#[from] io::Error), /// Custom error type to add a path to error reading a file from a zip - #[error("Failed to reflink {} to {}", from.simplified_display(), to.simplified_display())] + #[error("Failed to reflink {} to {}", from.user_display(), to.user_display())] Reflink { from: PathBuf, to: PathBuf, @@ -82,7 +82,7 @@ pub enum Error { DirectUrlJson(#[from] serde_json::Error), #[error("No .dist-info directory found")] MissingDistInfo, - #[error("Cannot uninstall package; RECORD file not found at: {}", _0.simplified_display())] + #[error("Cannot uninstall package; RECORD file not found at: {}", _0.user_display())] MissingRecord(PathBuf), #[error("Multiple .dist-info directories found: {0}")] MultipleDistInfo(String), diff --git a/crates/install-wheel-rs/src/wheel.rs b/crates/install-wheel-rs/src/wheel.rs index 28dd7ed2cae38..a457cf6617ed2 100644 --- a/crates/install-wheel-rs/src/wheel.rs +++ b/crates/install-wheel-rs/src/wheel.rs @@ -201,7 +201,7 @@ pub(crate) fn windows_script_launcher( } let python = python_executable.as_ref(); - let python_path = python.simplified().to_string_lossy(); + let python_path = python.simplified_display().to_string(); let mut launcher: Vec = Vec::with_capacity(launcher_bin.len() + payload.len()); launcher.extend_from_slice(launcher_bin); diff --git a/crates/requirements-txt/src/lib.rs b/crates/requirements-txt/src/lib.rs index fd04bd58d7352..6d6d44bb46d67 100644 --- a/crates/requirements-txt/src/lib.rs +++ b/crates/requirements-txt/src/lib.rs @@ -385,7 +385,7 @@ impl RequirementsTxt { if data == Self::default() { warn_user!( "Requirements file {} does not contain any dependencies", - requirements_txt.simplified_display() + requirements_txt.user_display() ); } @@ -1024,35 +1024,35 @@ impl Display for RequirementsTxtFileError { write!( f, "Invalid URL in `{}` at position {start}: `{url}`", - self.file.simplified_display(), + self.file.user_display(), ) } RequirementsTxtParserError::InvalidEditablePath(given) => { write!( f, "Invalid editable path in `{}`: {given}", - self.file.simplified_display() + self.file.user_display() ) } RequirementsTxtParserError::UnsupportedUrl(url) => { write!( f, "Unsupported URL (expected a `file://` scheme) in `{}`: `{url}`", - self.file.simplified_display(), + self.file.user_display(), ) } RequirementsTxtParserError::MissingRequirementPrefix(given) => { write!( f, "Requirement `{given}` in `{}` looks like a requirements file but was passed as a package name. Did you mean `-r {given}`?", - self.file.simplified_display(), + self.file.user_display(), ) } RequirementsTxtParserError::MissingEditablePrefix(given) => { write!( f, "Requirement `{given}` in `{}` looks like a directory but was passed as a package name. Did you mean `-e {given}`?", - self.file.simplified_display(), + self.file.user_display(), ) } RequirementsTxtParserError::Parser { @@ -1063,28 +1063,28 @@ impl Display for RequirementsTxtFileError { write!( f, "{message} at {}:{line}:{column}", - self.file.simplified_display(), + self.file.user_display(), ) } RequirementsTxtParserError::UnsupportedRequirement { start, .. } => { write!( f, "Unsupported requirement in {} at position {start}", - self.file.simplified_display(), + self.file.user_display(), ) } RequirementsTxtParserError::Pep508 { start, .. } => { write!( f, "Couldn't parse requirement in `{}` at position {start}", - self.file.simplified_display(), + self.file.user_display(), ) } RequirementsTxtParserError::Subfile { start, .. } => { write!( f, "Error parsing included file in `{}` at position {start}", - self.file.simplified_display(), + self.file.user_display(), ) } RequirementsTxtParserError::NonUnicodeUrl { url } => { @@ -1099,7 +1099,7 @@ impl Display for RequirementsTxtFileError { write!( f, "Error while accessing remote requirements file {}: {err}", - self.file.simplified_display(), + self.file.user_display(), ) } } @@ -1276,9 +1276,8 @@ mod test { .take(2) .join("\n"); - let requirement_txt = - regex::escape(&requirements_txt.path().simplified_display().to_string()); - let missing_txt = regex::escape(&missing_txt.path().simplified_display().to_string()); + let requirement_txt = regex::escape(&requirements_txt.path().user_display().to_string()); + let missing_txt = regex::escape(&missing_txt.path().user_display().to_string()); let filters = vec![ (requirement_txt.as_str(), ""), (missing_txt.as_str(), ""), @@ -1313,8 +1312,7 @@ mod test { .unwrap_err(); let errors = anyhow::Error::new(error).chain().join("\n"); - let requirement_txt = - regex::escape(&requirements_txt.path().simplified_display().to_string()); + let requirement_txt = regex::escape(&requirements_txt.path().user_display().to_string()); let filters = vec![ (requirement_txt.as_str(), ""), (r"\\", "/"), @@ -1350,8 +1348,7 @@ mod test { .unwrap_err(); let errors = anyhow::Error::new(error).chain().join("\n"); - let requirement_txt = - regex::escape(&requirements_txt.path().simplified_display().to_string()); + let requirement_txt = regex::escape(&requirements_txt.path().user_display().to_string()); let filters = vec![ (requirement_txt.as_str(), ""), (r"\\", "/"), @@ -1387,8 +1384,7 @@ mod test { .unwrap_err(); let errors = anyhow::Error::new(error).chain().join("\n"); - let requirement_txt = - regex::escape(&requirements_txt.path().simplified_display().to_string()); + let requirement_txt = regex::escape(&requirements_txt.path().user_display().to_string()); let filters = vec![ (requirement_txt.as_str(), ""), (r"\\", "/"), @@ -1419,8 +1415,7 @@ mod test { .unwrap_err(); let errors = anyhow::Error::new(error).chain().join("\n"); - let requirement_txt = - regex::escape(&requirements_txt.path().simplified_display().to_string()); + let requirement_txt = regex::escape(&requirements_txt.path().user_display().to_string()); let filters = vec![(requirement_txt.as_str(), "")]; insta::with_settings!({ filters => filters @@ -1453,8 +1448,7 @@ mod test { .unwrap_err(); let errors = anyhow::Error::new(error).chain().join("\n"); - let requirement_txt = - regex::escape(&requirements_txt.path().simplified_display().to_string()); + let requirement_txt = regex::escape(&requirements_txt.path().user_display().to_string()); let filters = vec![ (requirement_txt.as_str(), ""), (r"\\", "/"), @@ -1488,8 +1482,7 @@ mod test { .unwrap_err(); let errors = anyhow::Error::new(error).chain().join("\n"); - let requirement_txt = - regex::escape(&requirements_txt.path().simplified_display().to_string()); + let requirement_txt = regex::escape(&requirements_txt.path().user_display().to_string()); let filters = vec![ (requirement_txt.as_str(), ""), (r"\\", "/"), @@ -1528,8 +1521,7 @@ mod test { .unwrap_err(); let errors = anyhow::Error::new(error).chain().join("\n"); - let requirement_txt = - regex::escape(&requirements_txt.path().simplified_display().to_string()); + let requirement_txt = regex::escape(&requirements_txt.path().user_display().to_string()); let filters = vec![ (requirement_txt.as_str(), ""), (r"\\", "/"), @@ -1692,8 +1684,7 @@ mod test { .unwrap_err(); let errors = anyhow::Error::new(error).chain().join("\n"); - let requirement_txt = - regex::escape(&requirements_txt.path().simplified_display().to_string()); + let requirement_txt = regex::escape(&requirements_txt.path().user_display().to_string()); let filters = vec![ (requirement_txt.as_str(), ""), (r"\\", "/"), @@ -1746,8 +1737,7 @@ mod test { .unwrap_err(); let errors = anyhow::Error::new(error).chain().join("\n"); - let requirement_txt = - regex::escape(&requirements_txt.path().simplified_display().to_string()); + let requirement_txt = regex::escape(&requirements_txt.path().user_display().to_string()); let filters = vec![ (requirement_txt.as_str(), ""), (r"\\", "/"), diff --git a/crates/uv-fs/Cargo.toml b/crates/uv-fs/Cargo.toml index cca796721322d..83feda40f25c2 100644 --- a/crates/uv-fs/Cargo.toml +++ b/crates/uv-fs/Cargo.toml @@ -21,6 +21,7 @@ encoding_rs_io = { workspace = true } fs-err = { workspace = true } fs2 = { workspace = true } junction = { workspace = true } +once_cell = { workspace = true } tempfile = { workspace = true } tokio = { workspace = true, optional = true } tracing = { workspace = true } diff --git a/crates/uv-fs/src/lib.rs b/crates/uv-fs/src/lib.rs index 008c13cfe5b50..468e7d44e7553 100644 --- a/crates/uv-fs/src/lib.rs +++ b/crates/uv-fs/src/lib.rs @@ -114,7 +114,7 @@ pub async fn write_atomic(path: impl AsRef, data: impl AsRef<[u8]>) -> std std::io::ErrorKind::Other, format!( "Failed to persist temporary file to {}: {}", - path.simplified_display(), + path.user_display(), err.error ), ) @@ -135,7 +135,7 @@ pub fn write_atomic_sync(path: impl AsRef, data: impl AsRef<[u8]>) -> std: std::io::ErrorKind::Other, format!( "Failed to persist temporary file to {}: {}", - path.simplified_display(), + path.user_display(), err.error ), ) @@ -288,7 +288,7 @@ impl LockedFile { warn_user!( "Waiting to acquire lock for {} (lockfile: {})", resource, - path.simplified_display(), + path.user_display(), ); file.file().lock_exclusive()?; Ok(Self(file)) diff --git a/crates/uv-fs/src/path.rs b/crates/uv-fs/src/path.rs index 5fd9bf3a22044..f4864d1a55324 100644 --- a/crates/uv-fs/src/path.rs +++ b/crates/uv-fs/src/path.rs @@ -1,31 +1,29 @@ use std::borrow::Cow; use std::path::{Component, Path, PathBuf}; -pub trait Simplified { - /// Relativize a [`Path`] against the current working directory. - /// - /// If the current working directory is not a parent of the path, the path is returned as-is. - fn relativize(&self) -> &Path; +use once_cell::sync::Lazy; + +pub static CWD: Lazy = Lazy::new(|| std::env::current_dir().unwrap()); +pub trait Simplified { /// Simplify a [`Path`]. /// /// On Windows, this will strip the `\\?\` prefix from paths. On other platforms, it's a no-op. fn simplified(&self) -> &Path; - /// Render a [`Path`] for user-facing display. + /// Render a [`Path`] for display. /// /// On Windows, this will strip the `\\?\` prefix from paths. On other platforms, it's /// equivalent to [`std::path::Display`]. fn simplified_display(&self) -> std::path::Display; + + /// Render a [`Path`] for user-facing display. + /// + /// Like [`simplified_display`], but relativizes the path against the current working directory. + fn user_display(&self) -> std::path::Display; } impl> Simplified for T { - fn relativize(&self) -> &Path { - let path = self.as_ref(); - let cwd = std::env::current_dir().expect("failed to get current working directory"); - path.strip_prefix(cwd).unwrap_or(path) - } - fn simplified(&self) -> &Path { dunce::simplified(self.as_ref()) } @@ -33,6 +31,10 @@ impl> Simplified for T { fn simplified_display(&self) -> std::path::Display { dunce::simplified(self.as_ref()).display() } + + fn user_display(&self) -> std::path::Display { + dunce::simplified(self.as_ref().strip_prefix(&*CWD).unwrap_or(self.as_ref())).display() + } } pub trait PythonExt { diff --git a/crates/uv-git/src/git.rs b/crates/uv-git/src/git.rs index 9bde40bbaac46..f865f21dfb35f 100644 --- a/crates/uv-git/src/git.rs +++ b/crates/uv-git/src/git.rs @@ -170,7 +170,7 @@ impl GitRemote { let reference = locked_ref.as_ref().unwrap_or(reference); if let Some(mut db) = db { fetch(&mut db.repo, self.url.as_str(), reference, strategy, client) - .with_context(|| format!("failed to fetch into: {}", into.simplified_display()))?; + .with_context(|| format!("failed to fetch into: {}", into.user_display()))?; let resolved_commit_hash = match locked_rev { Some(rev) => db.contains(rev).then_some(rev), @@ -190,7 +190,7 @@ impl GitRemote { paths::create_dir_all(into)?; let mut repo = init(into, true)?; fetch(&mut repo, self.url.as_str(), reference, strategy, client) - .with_context(|| format!("failed to clone into: {}", into.simplified_display()))?; + .with_context(|| format!("failed to clone into: {}", into.user_display()))?; let rev = match locked_rev { Some(rev) => rev, None => reference.resolve(&repo)?, diff --git a/crates/uv-installer/src/compile.rs b/crates/uv-installer/src/compile.rs index d4140f9759194..d3ceb0f4bd646 100644 --- a/crates/uv-installer/src/compile.rs +++ b/crates/uv-installer/src/compile.rs @@ -201,7 +201,7 @@ async fn worker( Ok(()) => { debug!( "Bytecode compilation `python` at {} stderr:\n{}\n---", - interpreter.simplified_display(), + interpreter.user_display(), stderr ); Ok(()) diff --git a/crates/uv-installer/src/plan.rs b/crates/uv-installer/src/plan.rs index ad478c9d1ee52..772e8f4aa6ae8 100644 --- a/crates/uv-installer/src/plan.rs +++ b/crates/uv-installer/src/plan.rs @@ -305,7 +305,7 @@ impl<'a> Planner<'a> { if !wheel.filename.is_compatible(tags) { bail!( "A path dependency is incompatible with the current platform: {}", - wheel.path.simplified_display() + wheel.path.user_display() ); } diff --git a/crates/uv-interpreter/src/interpreter.rs b/crates/uv-interpreter/src/interpreter.rs index aa167fc9a52e7..84c168eb9a4ac 100644 --- a/crates/uv-interpreter/src/interpreter.rs +++ b/crates/uv-interpreter/src/interpreter.rs @@ -485,20 +485,20 @@ impl InterpreterInfo { debug!( "Cached interpreter info for Python {}, skipping probing: {}", cached.data.markers.python_full_version, - executable.simplified_display() + executable.user_display() ); return Ok(cached.data); } debug!( "Ignoring stale cached markers for: {}", - executable.simplified_display() + executable.user_display() ); } Err(err) => { warn!( "Broken cache entry at {}, removing: {err}", - cache_entry.path().simplified_display() + cache_entry.path().user_display() ); let _ = fs_err::remove_file(cache_entry.path()); } diff --git a/crates/uv-virtualenv/src/bare.rs b/crates/uv-virtualenv/src/bare.rs index 65e591861c389..acfa11c5d619e 100644 --- a/crates/uv-virtualenv/src/bare.rs +++ b/crates/uv-virtualenv/src/bare.rs @@ -86,7 +86,7 @@ pub fn create_bare_venv( if metadata.is_file() { return Err(Error::IO(io::Error::new( io::ErrorKind::AlreadyExists, - format!("File exists at `{}`", location.simplified_display()), + format!("File exists at `{}`", location.user_display()), ))); } else if metadata.is_dir() { if location.join("pyvenv.cfg").is_file() { @@ -103,7 +103,7 @@ pub fn create_bare_venv( io::ErrorKind::AlreadyExists, format!( "The directory `{}` exists, but it's not a virtualenv", - location.simplified_display() + location.user_display() ), ))); } diff --git a/crates/uv/src/commands/cache_clean.rs b/crates/uv/src/commands/cache_clean.rs index 4fed9cab8958f..60e669f71e575 100644 --- a/crates/uv/src/commands/cache_clean.rs +++ b/crates/uv/src/commands/cache_clean.rs @@ -20,7 +20,7 @@ pub(crate) fn cache_clean( writeln!( printer.stderr(), "No cache found at: {}", - cache.root().simplified_display().cyan() + cache.root().user_display().cyan() )?; return Ok(ExitStatus::Success); } @@ -29,14 +29,11 @@ pub(crate) fn cache_clean( writeln!( printer.stderr(), "Clearing cache at: {}", - cache.root().simplified_display().cyan() + cache.root().user_display().cyan() )?; let summary = cache.clear().with_context(|| { - format!( - "Failed to clear cache at: {}", - cache.root().simplified_display() - ) + format!("Failed to clear cache at: {}", cache.root().user_display()) })?; // Write a summary of the number of files and directories removed. diff --git a/crates/uv/src/commands/cache_dir.rs b/crates/uv/src/commands/cache_dir.rs index 2ff7977339a2e..6347ec314a95c 100644 --- a/crates/uv/src/commands/cache_dir.rs +++ b/crates/uv/src/commands/cache_dir.rs @@ -4,5 +4,5 @@ use uv_fs::Simplified; /// Show the cache directory. pub(crate) fn cache_dir(cache: &Cache) { - anstream::println!("{}", cache.root().simplified_display().cyan()); + anstream::println!("{}", cache.root().user_display().cyan()); } diff --git a/crates/uv/src/commands/mod.rs b/crates/uv/src/commands/mod.rs index cbf0f0e3c1c41..1ec679ed2140e 100644 --- a/crates/uv/src/commands/mod.rs +++ b/crates/uv/src/commands/mod.rs @@ -138,7 +138,7 @@ pub(super) async fn compile_bytecode( .with_context(|| { format!( "Failed to bytecode-compile Python file in: {}", - site_packages.simplified_display() + site_packages.user_display() ) })?; } diff --git a/crates/uv/src/commands/pip_check.rs b/crates/uv/src/commands/pip_check.rs index 6fc05abc40ca8..7c972d604046f 100644 --- a/crates/uv/src/commands/pip_check.rs +++ b/crates/uv/src/commands/pip_check.rs @@ -41,7 +41,7 @@ pub(crate) fn pip_check( debug!( "Using Python {} environment at {}", venv.interpreter().python_version(), - venv.python_executable().simplified_display().cyan() + venv.python_executable().user_display().cyan() ); // Build the installed index. diff --git a/crates/uv/src/commands/pip_compile.rs b/crates/uv/src/commands/pip_compile.rs index aae20fae1b8ed..020abedc1d9ed 100644 --- a/crates/uv/src/commands/pip_compile.rs +++ b/crates/uv/src/commands/pip_compile.rs @@ -133,7 +133,7 @@ pub(crate) async fn pip_compile( debug!( "Using Python {} interpreter at {} for builds", interpreter.python_version(), - interpreter.sys_executable().simplified_display().cyan() + interpreter.sys_executable().user_display().cyan() ); if let Some(python_version) = python_version.as_ref() { @@ -440,7 +440,7 @@ pub(crate) async fn pip_compile( fn cmd(include_index_url: bool, include_find_links: bool) -> String { let args = env::args_os() .skip(1) - .map(|arg| arg.simplified_display().to_string()) + .map(|arg| arg.user_display().to_string()) .scan(None, move |skip_next, arg| { if matches!(skip_next, Some(true)) { // Reset state; skip this iteration. diff --git a/crates/uv/src/commands/pip_freeze.rs b/crates/uv/src/commands/pip_freeze.rs index 603d7cb34eaa6..7cdafc7a54106 100644 --- a/crates/uv/src/commands/pip_freeze.rs +++ b/crates/uv/src/commands/pip_freeze.rs @@ -40,7 +40,7 @@ pub(crate) fn pip_freeze( debug!( "Using Python {} environment at {}", venv.interpreter().python_version(), - venv.python_executable().simplified_display().cyan() + venv.python_executable().user_display().cyan() ); // Build the installed index. diff --git a/crates/uv/src/commands/pip_install.rs b/crates/uv/src/commands/pip_install.rs index a3ee2798c6e3f..f56611fb4f21b 100644 --- a/crates/uv/src/commands/pip_install.rs +++ b/crates/uv/src/commands/pip_install.rs @@ -120,7 +120,7 @@ pub(crate) async fn pip_install( debug!( "Using Python {} environment at {}", venv.interpreter().python_version(), - venv.python_executable().simplified_display().cyan() + venv.python_executable().user_display().cyan() ); // If the environment is externally managed, abort. @@ -131,13 +131,13 @@ pub(crate) async fn pip_install( return if let Some(error) = externally_managed.into_error() { Err(anyhow::anyhow!( "The interpreter at {} is externally managed, and indicates the following:\n\n{}\n\nConsider creating a virtual environment with `uv venv`.", - venv.root().simplified_display().cyan(), + venv.root().user_display().cyan(), textwrap::indent(&error, " ").green(), )) } else { Err(anyhow::anyhow!( "The interpreter at {} is externally managed. Instead, create a virtual environment with `uv venv`.", - venv.root().simplified_display().cyan() + venv.root().user_display().cyan() )) }; } @@ -688,7 +688,7 @@ async fn install( )) => { warn_user!( "Failed to uninstall package at {} due to missing RECORD file. Installation may result in an incomplete environment.", - dist_info.path().simplified_display().cyan(), + dist_info.path().user_display().cyan(), ); } Err(err) => return Err(err.into()), diff --git a/crates/uv/src/commands/pip_list.rs b/crates/uv/src/commands/pip_list.rs index da2aef9d32741..e19907db880c0 100644 --- a/crates/uv/src/commands/pip_list.rs +++ b/crates/uv/src/commands/pip_list.rs @@ -51,7 +51,7 @@ pub(crate) fn pip_list( debug!( "Using Python {} environment at {}", venv.interpreter().python_version(), - venv.python_executable().simplified_display().cyan() + venv.python_executable().user_display().cyan() ); // Build the installed index. diff --git a/crates/uv/src/commands/pip_show.rs b/crates/uv/src/commands/pip_show.rs index 7a230537c9e61..b3a4a4692e5ba 100644 --- a/crates/uv/src/commands/pip_show.rs +++ b/crates/uv/src/commands/pip_show.rs @@ -56,7 +56,7 @@ pub(crate) fn pip_show( debug!( "Using Python {} environment at {}", venv.interpreter().python_version(), - venv.python_executable().simplified_display().cyan() + venv.python_executable().user_display().cyan() ); // Build the installed index. diff --git a/crates/uv/src/commands/pip_sync.rs b/crates/uv/src/commands/pip_sync.rs index 6dceb9161ab04..a2141d7e84bdc 100644 --- a/crates/uv/src/commands/pip_sync.rs +++ b/crates/uv/src/commands/pip_sync.rs @@ -84,7 +84,7 @@ pub(crate) async fn pip_sync( debug!( "Using Python {} environment at {}", venv.interpreter().python_version(), - venv.python_executable().simplified_display().cyan() + venv.python_executable().user_display().cyan() ); // If the environment is externally managed, abort. @@ -95,13 +95,13 @@ pub(crate) async fn pip_sync( return if let Some(error) = externally_managed.into_error() { Err(anyhow::anyhow!( "The interpreter at {} is externally managed, and indicates the following:\n\n{}\n\nConsider creating a virtual environment with `uv venv`.", - venv.root().simplified_display().cyan(), + venv.root().user_display().cyan(), textwrap::indent(&error, " ").green(), )) } else { Err(anyhow::anyhow!( "The interpreter at {} is externally managed. Instead, create a virtual environment with `uv venv`.", - venv.root().simplified_display().cyan() + venv.root().user_display().cyan() )) }; } @@ -303,7 +303,7 @@ pub(crate) async fn pip_sync( )) => { warn_user!( "Failed to uninstall package at {} due to missing RECORD file. Installation may result in an incomplete environment.", - dist_info.path().simplified_display().cyan(), + dist_info.path().user_display().cyan(), ); } Err(err) => return Err(err.into()), diff --git a/crates/uv/src/commands/pip_uninstall.rs b/crates/uv/src/commands/pip_uninstall.rs index 2022fe630ad31..99a0d5365f14a 100644 --- a/crates/uv/src/commands/pip_uninstall.rs +++ b/crates/uv/src/commands/pip_uninstall.rs @@ -51,7 +51,7 @@ pub(crate) async fn pip_uninstall( debug!( "Using Python {} environment at {}", venv.interpreter().python_version(), - venv.python_executable().simplified_display().cyan(), + venv.python_executable().user_display().cyan(), ); // If the environment is externally managed, abort. @@ -62,13 +62,13 @@ pub(crate) async fn pip_uninstall( return if let Some(error) = externally_managed.into_error() { Err(anyhow::anyhow!( "The interpreter at {} is externally managed, and indicates the following:\n\n{}\n\nConsider creating a virtual environment with `uv venv`.", - venv.root().relativize().simplified_display().cyan(), + venv.root().user_display().cyan(), textwrap::indent(&error, " ").green(), )) } else { Err(anyhow::anyhow!( "The interpreter at {} is externally managed. Instead, create a virtual environment with `uv venv`.", - venv.root().relativize().simplified_display().cyan() + venv.root().user_display().cyan() )) }; } diff --git a/crates/uv/src/commands/venv.rs b/crates/uv/src/commands/venv.rs index fd66accefaff3..fd64d90215f6f 100644 --- a/crates/uv/src/commands/venv.rs +++ b/crates/uv/src/commands/venv.rs @@ -116,18 +116,14 @@ async fn venv_impl( printer.stderr(), "Using Python {} interpreter at: {}", interpreter.python_version(), - interpreter - .sys_executable() - .relativize() - .simplified_display() - .cyan() + interpreter.sys_executable().user_display().cyan() ) .into_diagnostic()?; writeln!( printer.stderr(), "Creating virtualenv at: {}", - path.simplified_display().cyan() + path.user_display().cyan() ) .into_diagnostic()?; @@ -268,7 +264,7 @@ async fn venv_impl( /// Quote a path, if necessary, for safe use in a POSIX-compatible shell command. fn shlex_posix(executable: impl AsRef) -> String { // Convert to a display path. - let executable = executable.as_ref().simplified_display().to_string(); + let executable = executable.as_ref().user_display().to_string(); // Like Python's `shlex.quote`: // > Use single quotes, and put single quotes into double quotes @@ -283,7 +279,7 @@ fn shlex_posix(executable: impl AsRef) -> String { /// Quote a path, if necessary, for safe use in `PowerShell` and `cmd`. fn shlex_windows(executable: impl AsRef, shell: Shell) -> String { // Convert to a display path. - let executable = executable.as_ref().simplified_display().to_string(); + let executable = executable.as_ref().user_display().to_string(); // Wrap the executable in quotes (and a `&` invocation on PowerShell), if it contains spaces. if executable.contains(' ') { diff --git a/crates/uv/src/requirements.rs b/crates/uv/src/requirements.rs index dea672bd8be8f..1a1ca7beff4f2 100644 --- a/crates/uv/src/requirements.rs +++ b/crates/uv/src/requirements.rs @@ -213,7 +213,7 @@ impl RequirementsSpecification { RequirementsSource::PyprojectToml(path) => { let contents = uv_fs::read_to_string(path).await?; let pyproject_toml = toml::from_str::(&contents) - .with_context(|| format!("Failed to parse `{}`", path.simplified_display()))?; + .with_context(|| format!("Failed to parse `{}`", path.user_display()))?; let mut used_extras = FxHashSet::default(); let mut requirements = Vec::new(); let mut project_name = None; @@ -222,7 +222,7 @@ impl RequirementsSpecification { // Parse the project name. let parsed_project_name = PackageName::new(project.name).with_context(|| { - format!("Invalid `project.name` in {}", path.simplified_display()) + format!("Invalid `project.name` in {}", path.user_display()) })?; // Include the default dependencies. @@ -258,7 +258,7 @@ impl RequirementsSpecification { .any(|v| v.name.as_dist_info_name().starts_with("poetry")) }) { - warn_user!("`{}` does not contain any dependencies (hint: specify dependencies in the `project.dependencies` section; `tool.poetry.dependencies` is not currently supported)", path.simplified_display()); + warn_user!("`{}` does not contain any dependencies (hint: specify dependencies in the `project.dependencies` section; `tool.poetry.dependencies` is not currently supported)", path.user_display()); } Self { diff --git a/crates/uv/tests/pip_compile.rs b/crates/uv/tests/pip_compile.rs index 8c1747bc05e23..9fde08a013fc1 100644 --- a/crates/uv/tests/pip_compile.rs +++ b/crates/uv/tests/pip_compile.rs @@ -2019,7 +2019,7 @@ fn compile_wheel_path_dependency() -> Result<()> { requirements_in.write_str(&format!("flask @ {}", flask_wheel.path().display()))?; // In addition to the standard filters, remove the temporary directory from the snapshot. - let filter_path = regex::escape(&flask_wheel.simplified_display().to_string()); + let filter_path = regex::escape(&flask_wheel.user_display().to_string()); let filters: Vec<_> = [(filter_path.as_str(), "/[TEMP_DIR]/")] .into_iter() .chain(INSTA_FILTERS.to_vec()) @@ -2532,7 +2532,7 @@ fn compile_editable() -> Result<()> { " })?; - let filter_path = regex::escape(&requirements_in.simplified_display().to_string()); + let filter_path = regex::escape(&requirements_in.user_display().to_string()); let filters: Vec<_> = [(filter_path.as_str(), "requirements.in")] .into_iter() .chain(INSTA_FILTERS.to_vec()) @@ -2591,7 +2591,7 @@ fn recursive_extras_direct_url() -> Result<()> { let requirements_in = context.temp_dir.child("requirements.in"); requirements_in.write_str("black[dev] @ ../../scripts/editable-installs/black_editable")?; - let filter_path = regex::escape(&requirements_in.simplified_display().to_string()); + let filter_path = regex::escape(&requirements_in.user_display().to_string()); let filters: Vec<_> = [(filter_path.as_str(), "requirements.in")] .into_iter() .chain(INSTA_FILTERS.to_vec()) @@ -2654,7 +2654,7 @@ fn compile_editable_url_requirement() -> Result<()> { let requirements_in = context.temp_dir.child("requirements.in"); requirements_in.write_str("-e ../../scripts/editable-installs/hatchling_editable")?; - let filter_path = regex::escape(&requirements_in.simplified_display().to_string()); + let filter_path = regex::escape(&requirements_in.user_display().to_string()); let filters: Vec<_> = [(filter_path.as_str(), "requirements.in")] .into_iter() .chain(INSTA_FILTERS.to_vec()) @@ -2739,7 +2739,7 @@ fn cache_errors_are_non_fatal() -> Result<()> { for file in &cache_files { let file = context.cache_dir.join(file); if !file.is_file() { - bail!("Missing cache file {}", file.simplified_display()); + bail!("Missing cache file {}", file.user_display()); } fs_err::write(file, "I borken you cache")?; } @@ -2754,7 +2754,7 @@ fn cache_errors_are_non_fatal() -> Result<()> { for file in cache_files { let file = context.cache_dir.join(file); if !file.is_file() { - bail!("Missing cache file {}", file.simplified_display()); + bail!("Missing cache file {}", file.user_display()); } fs_err::OpenOptions::new() @@ -3055,7 +3055,7 @@ fn find_links_directory() -> Result<()> { "})?; let project_root = fs_err::canonicalize(std::env::current_dir()?.join("..").join(".."))?; - let project_root_string = regex::escape(&project_root.simplified_display().to_string()); + let project_root_string = regex::escape(&project_root.user_display().to_string()); let filters: Vec<_> = [ (project_root_string.as_str(), "[PROJECT_ROOT]"), // Unify trailing (back)slash between Windows and Unix. @@ -4147,7 +4147,7 @@ fn editable_invalid_extra() -> Result<()> { let requirements_in = context.temp_dir.child("requirements.in"); requirements_in.write_str("-e ../../scripts/editable-installs/black_editable[empty]")?; - let requirements_path = regex::escape(&requirements_in.simplified_display().to_string()); + let requirements_path = regex::escape(&requirements_in.user_display().to_string()); let filters: Vec<_> = [ (r" file://.*/", " file://[TEMP_DIR]/"), (requirements_path.as_str(), "requirements.in"), @@ -4464,8 +4464,8 @@ fn override_editable() -> Result<()> { let overrides_txt = context.temp_dir.child("overrides.txt"); overrides_txt.write_str("black==23.10.1")?; - let requirements_path = regex::escape(&requirements_in.simplified_display().to_string()); - let overrides_path = regex::escape(&overrides_txt.simplified_display().to_string()); + let requirements_path = regex::escape(&requirements_in.user_display().to_string()); + let overrides_path = regex::escape(&overrides_txt.user_display().to_string()); let filters: Vec<_> = [ (requirements_path.as_str(), "requirements.in"), (overrides_path.as_str(), "overrides.txt"), @@ -4812,7 +4812,7 @@ fn editable_direct_dependency() -> Result<()> { let requirements_in = context.temp_dir.child("requirements.in"); requirements_in.write_str("-e ../../scripts/editable-installs/setuptools_editable")?; - let requirements_path = regex::escape(&requirements_in.simplified_display().to_string()); + let requirements_path = regex::escape(&requirements_in.user_display().to_string()); let filters: Vec<_> = [ (r" file://.*/", " file://[TEMP_DIR]/"), (requirements_path.as_str(), "requirements.in"), diff --git a/crates/uv/tests/pip_sync.rs b/crates/uv/tests/pip_sync.rs index 26e9e13c5a289..af3f494619d1f 100644 --- a/crates/uv/tests/pip_sync.rs +++ b/crates/uv/tests/pip_sync.rs @@ -2205,7 +2205,7 @@ fn sync_editable() -> Result<()> { current_dir = current_dir.simplified_display(), })?; - let filter_path = regex::escape(&requirements_txt.simplified_display().to_string()); + let filter_path = regex::escape(&requirements_txt.user_display().to_string()); let filters = INSTA_FILTERS .iter() .chain(&[ @@ -2328,7 +2328,7 @@ fn sync_editable_and_registry() -> Result<()> { " })?; - let filter_path = regex::escape(&requirements_txt.simplified_display().to_string()); + let filter_path = regex::escape(&requirements_txt.user_display().to_string()); let filters = INSTA_FILTERS .iter() .chain(&[ @@ -2367,7 +2367,7 @@ fn sync_editable_and_registry() -> Result<()> { " })?; - let filter_path = regex::escape(&requirements_txt.simplified_display().to_string()); + let filter_path = regex::escape(&requirements_txt.user_display().to_string()); let filters = INSTA_FILTERS .iter() .chain(&[ @@ -2401,7 +2401,7 @@ fn sync_editable_and_registry() -> Result<()> { " })?; - let filter_path = regex::escape(&requirements_txt.simplified_display().to_string()); + let filter_path = regex::escape(&requirements_txt.user_display().to_string()); let filters = INSTA_FILTERS .iter() .chain(&[ @@ -2430,7 +2430,7 @@ fn sync_editable_and_registry() -> Result<()> { " })?; - let filter_path = regex::escape(&requirements_txt.simplified_display().to_string()); + let filter_path = regex::escape(&requirements_txt.user_display().to_string()); let filters = INSTA_FILTERS .iter() .chain(&[ @@ -2480,13 +2480,7 @@ fn incompatible_wheel() -> Result<()> { Url::from_file_path(wheel.path()).unwrap() ))?; - let wheel_dir = regex::escape( - &wheel_dir - .path() - .canonicalize()? - .simplified_display() - .to_string(), - ); + let wheel_dir = regex::escape(&wheel_dir.path().canonicalize()?.user_display().to_string()); let filters: Vec<_> = [(wheel_dir.as_str(), "[TEMP_DIR]")] .into_iter() .chain(INSTA_FILTERS.to_vec()) @@ -2573,7 +2567,7 @@ fn find_links() -> Result<()> { "})?; let project_root = fs_err::canonicalize(std::env::current_dir()?.join("../.."))?; - let project_root_string = regex::escape(&project_root.simplified_display().to_string()); + let project_root_string = regex::escape(&project_root.user_display().to_string()); let filters: Vec<_> = [(project_root_string.as_str(), "[PROJECT_ROOT]")] .into_iter() .chain(INSTA_FILTERS.to_vec()) @@ -2921,11 +2915,13 @@ fn compile_invalid_pyc_invalidation_mode() -> Result<()> { .site_packages() .canonicalize() .unwrap() - .simplified_display() + .user_display() .to_string(), ); let filters: Vec<_> = [ (site_packages.as_str(), "[SITE-PACKAGES]"), + (r"\.venv/lib/python3.12/site-packages", "[SITE-PACKAGES]"), + (r"\.venv/Lib/site-packages", "[SITE-PACKAGES]"), ( r#"\[SITE-PACKAGES\].*.py", received: "#, r#"[SITE-PACKAGES]/[FIRST-FILE]", received: "#, diff --git a/crates/uv/tests/pip_uninstall.rs b/crates/uv/tests/pip_uninstall.rs index a4effb1fde244..ad13050ac2236 100644 --- a/crates/uv/tests/pip_uninstall.rs +++ b/crates/uv/tests/pip_uninstall.rs @@ -6,7 +6,6 @@ use assert_fs::prelude::*; use url::Url; use common::{uv_snapshot, INSTA_FILTERS}; -use uv_fs::Simplified; use crate::common::{get_bin, venv_to_interpreter, TestContext}; @@ -352,26 +351,14 @@ fn missing_record() -> Result<()> { .unwrap(); fs_err::remove_file(dist_info.join("RECORD"))?; - let dist_info_str = regex::escape(&format!( - "RECORD file not found at: {}", - dist_info.simplified_display() - )); - let filters: Vec<_> = [( - dist_info_str.as_str(), - "RECORD file not found at: [DIST_INFO]", - )] - .into_iter() - .chain(INSTA_FILTERS.to_vec()) - .collect(); - - uv_snapshot!(filters, uninstall_command(&context) + uv_snapshot!(uninstall_command(&context) .arg("MarkupSafe"), @r###" success: false exit_code: 2 ----- stdout ----- ----- stderr ----- - error: Cannot uninstall package; RECORD file not found at: [DIST_INFO]/RECORD + error: Cannot uninstall package; RECORD file not found at: .venv/lib/python3.12/site-packages/MarkupSafe-2.1.3.dist-info/RECORD "### ); diff --git a/crates/uv/tests/venv.rs b/crates/uv/tests/venv.rs index 5f46d812b4114..067c14146be65 100644 --- a/crates/uv/tests/venv.rs +++ b/crates/uv/tests/venv.rs @@ -29,11 +29,8 @@ fn create_venv() -> Result<()> { r"Using Python 3\.\d+\.\d+ interpreter at: .+", "Using Python [VERSION] interpreter at: [PATH]", ), - (&filter_venv, "/home/ferris/project/.venv"), - ( - filter_prompt, - "Activate with: source /home/ferris/project/.venv/bin/activate", - ), + (filter_prompt, "Activate with: source .venv/bin/activate"), + (&filter_venv, ".venv"), ]; uv_snapshot!(filters, Command::new(get_bin()) .arg("venv") @@ -52,8 +49,8 @@ fn create_venv() -> Result<()> { ----- stderr ----- Using Python [VERSION] interpreter at: [PATH] - Creating virtualenv at: /home/ferris/project/.venv - Activate with: source /home/ferris/project/.venv/bin/activate + Creating virtualenv at: .venv + Activate with: source .venv/bin/activate "### ); @@ -67,11 +64,8 @@ fn create_venv() -> Result<()> { r"Using Python 3\.\d+\.\d+ interpreter at: .+", "Using Python [VERSION] interpreter at: [PATH]", ), - (&filter_venv, "/home/ferris/project/.venv"), - ( - filter_prompt, - "Activate with: source /home/ferris/project/.venv/bin/activate", - ), + (filter_prompt, "Activate with: source .venv/bin/activate"), + (&filter_venv, ".venv"), ]; uv_snapshot!(filters, Command::new(get_bin()) .arg("venv") @@ -91,8 +85,8 @@ fn create_venv() -> Result<()> { ----- stderr ----- Using Python [VERSION] interpreter at: [PATH] - Creating virtualenv at: /home/ferris/project/.venv - Activate with: source /home/ferris/project/.venv/bin/activate + Creating virtualenv at: .venv + Activate with: source .venv/bin/activate "### ); @@ -115,7 +109,7 @@ fn create_venv_defaults_to_cwd() -> Result<()> { r"Using Python 3\.\d+\.\d+ interpreter at: .+", "Using Python [VERSION] interpreter at: [PATH]", ), - (&filter_venv, "/home/ferris/project/.venv"), + (&filter_venv, ".venv"), (filter_prompt, "Activate with: source .venv/bin/activate"), ]; uv_snapshot!(filters, Command::new(get_bin()) @@ -159,11 +153,8 @@ fn seed() -> Result<()> { r"Using Python 3\.\d+\.\d+ interpreter at: .+", "Using Python [VERSION] interpreter at: [PATH]", ), - (&filter_venv, "/home/ferris/project/.venv"), - ( - filter_prompt, - "Activate with: source /home/ferris/project/.venv/bin/activate", - ), + (filter_prompt, "Activate with: source .venv/bin/activate"), + (&filter_venv, ".venv"), ]; uv_snapshot!(filters, Command::new(get_bin()) .arg("venv") @@ -184,9 +175,9 @@ fn seed() -> Result<()> { ----- stderr ----- Using Python [VERSION] interpreter at: [PATH] - Creating virtualenv at: /home/ferris/project/.venv + Creating virtualenv at: .venv + pip==23.3.1 - Activate with: source /home/ferris/project/.venv/bin/activate + Activate with: source .venv/bin/activate "### ); @@ -209,11 +200,8 @@ fn seed_older_python_version() -> Result<()> { r"Using Python 3\.\d+\.\d+ interpreter at: .+", "Using Python [VERSION] interpreter at: [PATH]", ), - (&filter_venv, "/home/ferris/project/.venv"), - ( - filter_prompt, - "Activate with: source /home/ferris/project/.venv/bin/activate", - ), + (filter_prompt, "Activate with: source .venv/bin/activate"), + (&filter_venv, ".venv"), ]; uv_snapshot!(filters, Command::new(get_bin()) .arg("venv") @@ -234,11 +222,11 @@ fn seed_older_python_version() -> Result<()> { ----- stderr ----- Using Python [VERSION] interpreter at: [PATH] - Creating virtualenv at: /home/ferris/project/.venv + Creating virtualenv at: .venv + pip==23.3.1 + setuptools==68.2.2 + wheel==0.41.3 - Activate with: source /home/ferris/project/.venv/bin/activate + Activate with: source .venv/bin/activate "### ); @@ -311,7 +299,7 @@ fn create_venv_unknown_python_patch() -> Result<()> { r"No Python 3\.8\.0 found through `py --list-paths` or in `PATH`\. Is Python 3\.8\.0 installed\?", "No Python 3.8.0 in `PATH`. Is Python 3.8.0 installed?", ), - (&filter_venv, "/home/ferris/project/.venv"), + (&filter_venv, ".venv"), ]; uv_snapshot!(filters, Command::new(get_bin()) .arg("venv") @@ -351,11 +339,8 @@ fn create_venv_python_patch() -> Result<()> { let filter_prompt = r"Activate with: (?:.*)\\Scripts\\activate"; let filters = &[ (r"interpreter at: .+", "interpreter at: [PATH]"), - (&filter_venv, "/home/ferris/project/.venv"), - ( - filter_prompt, - "Activate with: source /home/ferris/project/.venv/bin/activate", - ), + (filter_prompt, "Activate with: source .venv/bin/activate"), + (&filter_venv, ".venv"), ]; uv_snapshot!(filters, Command::new(get_bin()) .arg("venv") @@ -375,8 +360,8 @@ fn create_venv_python_patch() -> Result<()> { ----- stderr ----- Using Python 3.12.1 interpreter at: [PATH] - Creating virtualenv at: /home/ferris/project/.venv - Activate with: source /home/ferris/project/.venv/bin/activate + Creating virtualenv at: .venv + Activate with: source .venv/bin/activate "### ); @@ -401,7 +386,7 @@ fn file_exists() -> Result<()> { r"Using Python 3\.\d+\.\d+ interpreter at: .+", "Using Python [VERSION] interpreter at: [PATH]", ), - (&filter_venv, "/home/ferris/project/.venv"), + (&filter_venv, ".venv"), ]; uv_snapshot!(filters, Command::new(get_bin()) .arg("venv") @@ -421,11 +406,11 @@ fn file_exists() -> Result<()> { ----- stderr ----- Using Python [VERSION] interpreter at: [PATH] - Creating virtualenv at: /home/ferris/project/.venv + Creating virtualenv at: .venv uv::venv::creation × Failed to create virtualenv - ╰─▶ File exists at `/home/ferris/project/.venv` + ╰─▶ File exists at `.venv` "### ); @@ -449,11 +434,8 @@ fn empty_dir_exists() -> Result<()> { r"Using Python 3\.\d+\.\d+ interpreter at: .+", "Using Python [VERSION] interpreter at: [PATH]", ), - (&filter_venv, "/home/ferris/project/.venv"), - ( - filter_prompt, - "Activate with: source /home/ferris/project/.venv/bin/activate", - ), + (filter_prompt, "Activate with: source .venv/bin/activate"), + (&filter_venv, ".venv"), ]; uv_snapshot!(filters, Command::new(get_bin()) .arg("venv") @@ -473,8 +455,8 @@ fn empty_dir_exists() -> Result<()> { ----- stderr ----- Using Python [VERSION] interpreter at: [PATH] - Creating virtualenv at: /home/ferris/project/.venv - Activate with: source /home/ferris/project/.venv/bin/activate + Creating virtualenv at: .venv + Activate with: source .venv/bin/activate "### ); @@ -500,7 +482,7 @@ fn non_empty_dir_exists() -> Result<()> { r"Using Python 3\.\d+\.\d+ interpreter at: .+", "Using Python [VERSION] interpreter at: [PATH]", ), - (&filter_venv, "/home/ferris/project/.venv"), + (&filter_venv, ".venv"), ]; uv_snapshot!(filters, Command::new(get_bin()) .arg("venv") @@ -520,11 +502,11 @@ fn non_empty_dir_exists() -> Result<()> { ----- stderr ----- Using Python [VERSION] interpreter at: [PATH] - Creating virtualenv at: /home/ferris/project/.venv + Creating virtualenv at: .venv uv::venv::creation × Failed to create virtualenv - ╰─▶ The directory `/home/ferris/project/.venv` exists, but it's not a virtualenv + ╰─▶ The directory `.venv` exists, but it's not a virtualenv "### ); @@ -565,11 +547,8 @@ fn windows_shims() -> Result<()> { r"Using Python 3\.8.\d+ interpreter at: .+", "Using Python 3.8.x interpreter at: [PATH]", ), - (&filter_venv, "/home/ferris/project/.venv"), - ( - &filter_prompt, - "Activate with: source /home/ferris/project/.venv/bin/activate", - ), + (&filter_prompt, "Activate with: source .venv/bin/activate"), + (&filter_venv, ".venv"), ]; uv_snapshot!(filters, Command::new(get_bin()) .arg("venv") @@ -588,8 +567,8 @@ fn windows_shims() -> Result<()> { ----- stderr ----- warning: virtualenv's `--clear` has no effect (uv always clears the virtual environment). Using Python 3.8.x interpreter at: [PATH] - Creating virtualenv at: /home/ferris/project/.venv - Activate with: source /home/ferris/project/.venv/bin/activate + Creating virtualenv at: .venv + Activate with: source .venv/bin/activate "### ); @@ -613,11 +592,8 @@ fn virtualenv_compatibility() -> Result<()> { r"Using Python 3\.\d+\.\d+ interpreter at: .+", "Using Python [VERSION] interpreter at: [PATH]", ), - (&filter_venv, "/home/ferris/project/.venv"), - ( - filter_prompt, - "Activate with: source /home/ferris/project/.venv/bin/activate", - ), + (filter_prompt, "Activate with: source .venv/bin/activate"), + (&filter_venv, ".venv"), ]; uv_snapshot!(filters, Command::new(get_bin()) .arg("venv") @@ -638,8 +614,8 @@ fn virtualenv_compatibility() -> Result<()> { ----- stderr ----- warning: virtualenv's `--clear` has no effect (uv always clears the virtual environment). Using Python [VERSION] interpreter at: [PATH] - Creating virtualenv at: /home/ferris/project/.venv - Activate with: source /home/ferris/project/.venv/bin/activate + Creating virtualenv at: .venv + Activate with: source .venv/bin/activate "### );