Add some decoration to tool CLI (#4865)

Mostly small things. I added entrypoint counts and bolded the executable
names.

Closes https://github.com/astral-sh/uv/issues/4815.
This commit is contained in:
Charlie Marsh 2024-07-08 08:21:05 -05:00 committed by GitHub
parent fb19372a00
commit 947cfa13a8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 85 additions and 71 deletions

View file

@ -5,6 +5,7 @@ use std::str::FromStr;
use anyhow::{bail, Context, Result}; use anyhow::{bail, Context, Result};
use itertools::Itertools; use itertools::Itertools;
use owo_colors::OwoColorize;
use tracing::debug; use tracing::debug;
use distribution_types::Name; use distribution_types::Name;
@ -82,7 +83,7 @@ pub(crate) async fn install(
// Parse the positional name. If the user provided more than a package name, it's an error // Parse the positional name. If the user provided more than a package name, it's an error
// (e.g., `uv install foo==1.0 --from foo`). // (e.g., `uv install foo==1.0 --from foo`).
let Ok(package) = PackageName::from_str(&package) else { let Ok(package) = PackageName::from_str(&package) else {
bail!("Package requirement `{from}` provided with `--from` conflicts with install request `{package}`") bail!("Package requirement (`{from}`) provided with `--from` conflicts with install request (`{package}`)")
}; };
let from_requirement = resolve_requirements( let from_requirement = resolve_requirements(
@ -105,7 +106,7 @@ pub(crate) async fn install(
if from_requirement.name != package { if from_requirement.name != package {
// Determine if it's an entirely different package (e.g., `uv install foo --from bar`). // Determine if it's an entirely different package (e.g., `uv install foo --from bar`).
bail!( bail!(
"Package name `{}` provided with `--from` does not match install request `{}`", "Package name (`{}`) provided with `--from` does not match install request (`{}`)",
from_requirement.name, from_requirement.name,
package package
); );
@ -160,12 +161,12 @@ pub(crate) async fn install(
.filter(|environment| { .filter(|environment| {
python_request.as_ref().map_or(true, |python_request| { python_request.as_ref().map_or(true, |python_request| {
if python_request.satisfied(environment.interpreter(), cache) { if python_request.satisfied(environment.interpreter(), cache) {
debug!("Found existing environment for tool `{}`", from.name); debug!("Found existing environment for `{}`", from.name);
true true
} else { } else {
let _ = writeln!( let _ = writeln!(
printer.stderr(), printer.stderr(),
"Existing environment for `{}` does not satisfy the requested Python interpreter: `{}`", "Existing environment for `{}` does not satisfy the requested Python interpreter (`{}`)",
from.name, from.name,
python_request python_request
); );
@ -187,7 +188,7 @@ pub(crate) async fn install(
// And the user didn't request a reinstall or upgrade... // And the user didn't request a reinstall or upgrade...
if !force && settings.reinstall.is_none() && settings.upgrade.is_none() { if !force && settings.reinstall.is_none() && settings.upgrade.is_none() {
// We're done. // We're done.
writeln!(printer.stderr(), "Tool `{from}` is already installed")?; writeln!(printer.stderr(), "`{from}` is already installed")?;
return Ok(ExitStatus::Failure); return Ok(ExitStatus::Failure);
} }
} }
@ -269,7 +270,7 @@ pub(crate) async fn install(
.context("Failed to create executable directory")?; .context("Failed to create executable directory")?;
debug!( debug!(
"Installing tool entry points into {}", "Installing tool executables into: {}",
executable_directory.user_display() executable_directory.user_display()
); );
@ -298,7 +299,7 @@ pub(crate) async fn install(
// Clean up the environment we just created // Clean up the environment we just created
installed_tools.remove_environment(&from.name)?; installed_tools.remove_environment(&from.name)?;
bail!("No entry points found for tool `{}`", from.name); bail!("No executables found for `{}`", from.name);
} }
// Check if they exist, before installing // Check if they exist, before installing
@ -311,7 +312,7 @@ pub(crate) async fn install(
// will _not_ remove existing entry points when they are not managed by uv. // will _not_ remove existing entry points when they are not managed by uv.
if force || reinstall_entry_points { if force || reinstall_entry_points {
for (name, _, target) in existing_entry_points { for (name, _, target) in existing_entry_points {
debug!("Removing existing entry point `{name}`"); debug!("Removing existing executable: `{name}`");
fs_err::remove_file(target)?; fs_err::remove_file(target)?;
} }
} else if existing_entry_points.peek().is_some() { } else if existing_entry_points.peek().is_some() {
@ -328,25 +329,34 @@ pub(crate) async fn install(
("s", "exist") ("s", "exist")
}; };
bail!( bail!(
"Entry point{s} for tool already {exists}: {} (use `--force` to overwrite)", "Executable{s} already {exists}: {} (use `--force` to overwrite)",
existing_entry_points.iter().join(", ") existing_entry_points
.iter()
.map(|name| name.bold())
.join(", ")
) )
} }
for (name, source_path, target_path) in &target_entry_points { for (name, source_path, target_path) in &target_entry_points {
debug!("Installing `{name}`"); debug!("Installing executable: `{name}`");
#[cfg(unix)] #[cfg(unix)]
replace_symlink(source_path, target_path).context("Failed to install entrypoint")?; replace_symlink(source_path, target_path).context("Failed to install executable")?;
#[cfg(windows)] #[cfg(windows)]
fs_err::copy(source_path, target_path).context("Failed to install entrypoint")?; fs_err::copy(source_path, target_path).context("Failed to install entrypoint")?;
} }
let s = if target_entry_points.len() == 1 {
""
} else {
"s"
};
writeln!( writeln!(
printer.stderr(), printer.stderr(),
"Installed: {}", "Installed {} executable{s}: {}",
target_entry_points.len(),
target_entry_points target_entry_points
.iter() .iter()
.map(|(name, _, _)| name) .map(|(name, _, _)| name.bold())
.join(", ") .join(", ")
)?; )?;

View file

@ -1,6 +1,7 @@
use std::fmt::Write; use std::fmt::Write;
use anyhow::Result; use anyhow::Result;
use owo_colors::OwoColorize;
use uv_cache::Cache; use uv_cache::Cache;
use uv_configuration::PreviewMode; use uv_configuration::PreviewMode;
@ -40,11 +41,11 @@ pub(crate) async fn list(
} }
}; };
writeln!(printer.stdout(), "{name} v{version}")?; writeln!(printer.stdout(), "{}", format!("{name} v{version}").bold())?;
// Output tool entrypoints // Output tool entrypoints
for entrypoint in tool.entrypoints() { for entrypoint in tool.entrypoints() {
writeln!(printer.stdout(), " {}", &entrypoint.name)?; writeln!(printer.stdout(), "- {}", &entrypoint.name)?;
} }
} }

View file

@ -288,7 +288,7 @@ fn parse_target(target: &OsString) -> Result<(Cow<OsString>, Cow<str>)> {
// e.g. ignore `git+https://github.com/uv/uv.git@main` // e.g. ignore `git+https://github.com/uv/uv.git@main`
if PackageName::from_str(name).is_err() { if PackageName::from_str(name).is_err() {
debug!("Ignoring non-package name `{}` in command", name); debug!("Ignoring non-package name `{name}` in command");
return Ok((Cow::Borrowed(target), Cow::Borrowed(target_str))); return Ok((Cow::Borrowed(target), Cow::Borrowed(target_str)));
} }
@ -301,6 +301,6 @@ fn parse_target(target: &OsString) -> Result<(Cow<OsString>, Cow<str>)> {
} }
// e.g. `uv@invalid`, warn and treat the whole thing as the command // e.g. `uv@invalid`, warn and treat the whole thing as the command
debug!("Ignoring invalid version request `{}` in command", version); debug!("Ignoring invalid version request `{version}` in command");
Ok((Cow::Borrowed(target), Cow::Borrowed(target_str))) Ok((Cow::Borrowed(target), Cow::Borrowed(target_str)))
} }

View file

@ -2,6 +2,7 @@ use std::fmt::Write;
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use itertools::Itertools; use itertools::Itertools;
use owo_colors::OwoColorize;
use tracing::debug; use tracing::debug;
use uv_configuration::PreviewMode; use uv_configuration::PreviewMode;
@ -30,12 +31,12 @@ pub(crate) async fn uninstall(
Ok(()) => { Ok(()) => {
writeln!( writeln!(
printer.stderr(), printer.stderr(),
"Removed dangling environment for tool: `{name}` (missing receipt)" "Removed dangling environment for `{name}`"
)?; )?;
return Ok(ExitStatus::Success); return Ok(ExitStatus::Success);
} }
Err(uv_tool::Error::IO(err)) if err.kind() == std::io::ErrorKind::NotFound => { Err(uv_tool::Error::IO(err)) if err.kind() == std::io::ErrorKind::NotFound => {
bail!("Tool `{name}` is not installed"); bail!("`{name}` is not installed");
} }
Err(err) => { Err(err) => {
return Err(err.into()); return Err(err.into());
@ -50,14 +51,14 @@ pub(crate) async fn uninstall(
let entrypoints = receipt.entrypoints(); let entrypoints = receipt.entrypoints();
for entrypoint in entrypoints { for entrypoint in entrypoints {
debug!( debug!(
"Removing entrypoint: {}", "Removing executable: {}",
entrypoint.install_path.user_display() entrypoint.install_path.user_display()
); );
match fs_err::tokio::remove_file(&entrypoint.install_path).await { match fs_err::tokio::remove_file(&entrypoint.install_path).await {
Ok(()) => {} Ok(()) => {}
Err(err) if err.kind() == std::io::ErrorKind::NotFound => { Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
debug!( debug!(
"Entrypoint not found: {}", "Executable not found: {}",
entrypoint.install_path.user_display() entrypoint.install_path.user_display()
); );
} }
@ -67,12 +68,14 @@ pub(crate) async fn uninstall(
} }
} }
let s = if entrypoints.len() == 1 { "" } else { "s" };
writeln!( writeln!(
printer.stderr(), printer.stderr(),
"Uninstalled: {}", "Uninstalled {} executable{s}: {}",
entrypoints.len(),
entrypoints entrypoints
.iter() .iter()
.map(|entrypoint| &entrypoint.name) .map(|entrypoint| entrypoint.name.bold())
.join(", ") .join(", ")
)?; )?;

View file

@ -72,10 +72,10 @@ pub struct TestContext {
/// The Python version used for the virtual environment, if any. /// The Python version used for the virtual environment, if any.
pub python_version: Option<PythonVersion>, pub python_version: Option<PythonVersion>,
// All the Python versions available during this test context. /// All the Python versions available during this test context.
pub python_versions: Vec<(PythonVersion, PathBuf)>, pub python_versions: Vec<(PythonVersion, PathBuf)>,
// Standard filters for this test context /// Standard filters for this test context.
filters: Vec<(String, String)>, filters: Vec<(String, String)>,
} }
@ -120,7 +120,7 @@ impl TestContext {
#[must_use] #[must_use]
pub fn with_filtered_exe_suffix(mut self) -> Self { pub fn with_filtered_exe_suffix(mut self) -> Self {
self.filters self.filters
.push((std::env::consts::EXE_SUFFIX.to_string(), String::new())); .push((regex::escape(env::consts::EXE_SUFFIX), String::new()));
self self
} }

View file

@ -42,7 +42,7 @@ fn tool_install() {
+ packaging==24.0 + packaging==24.0
+ pathspec==0.12.1 + pathspec==0.12.1
+ platformdirs==4.2.0 + platformdirs==4.2.0
Installed: black, blackd Installed 2 executables: black, blackd
"###); "###);
tool_dir.child("black").assert(predicate::path::is_dir()); tool_dir.child("black").assert(predicate::path::is_dir());
@ -118,7 +118,7 @@ fn tool_install() {
+ jinja2==3.1.3 + jinja2==3.1.3
+ markupsafe==2.1.5 + markupsafe==2.1.5
+ werkzeug==3.0.1 + werkzeug==3.0.1
Installed: flask Installed 1 executable: flask
"###); "###);
tool_dir.child("flask").assert(predicate::path::is_dir()); tool_dir.child("flask").assert(predicate::path::is_dir());
@ -195,7 +195,7 @@ fn tool_install_version() {
+ packaging==24.0 + packaging==24.0
+ pathspec==0.12.1 + pathspec==0.12.1
+ platformdirs==4.2.0 + platformdirs==4.2.0
Installed: black, blackd Installed 2 executables: black, blackd
"###); "###);
tool_dir.child("black").assert(predicate::path::is_dir()); tool_dir.child("black").assert(predicate::path::is_dir());
@ -280,7 +280,7 @@ fn tool_install_from() {
+ packaging==24.0 + packaging==24.0
+ pathspec==0.12.1 + pathspec==0.12.1
+ platformdirs==4.2.0 + platformdirs==4.2.0
Installed: black, blackd Installed 2 executables: black, blackd
"###); "###);
// Attempt to install `black` using `--from` with a different package name // Attempt to install `black` using `--from` with a different package name
@ -296,7 +296,7 @@ fn tool_install_from() {
----- stderr ----- ----- stderr -----
warning: `uv tool install` is experimental and may change without warning. warning: `uv tool install` is experimental and may change without warning.
error: Package name `flask` provided with `--from` does not match install request `black` error: Package name (`flask`) provided with `--from` does not match install request (`black`)
"###); "###);
// Attempt to install `black` using `--from` with a different version // Attempt to install `black` using `--from` with a different version
@ -312,7 +312,7 @@ fn tool_install_from() {
----- stderr ----- ----- stderr -----
warning: `uv tool install` is experimental and may change without warning. warning: `uv tool install` is experimental and may change without warning.
error: Package requirement `black==24.3.0` provided with `--from` conflicts with install request `black==24.2.0` error: Package requirement (`black==24.3.0`) provided with `--from` conflicts with install request (`black==24.2.0`)
"###); "###);
} }
@ -345,7 +345,7 @@ fn tool_install_already_installed() {
+ packaging==24.0 + packaging==24.0
+ pathspec==0.12.1 + pathspec==0.12.1
+ platformdirs==4.2.0 + platformdirs==4.2.0
Installed: black, blackd Installed 2 executables: black, blackd
"###); "###);
tool_dir.child("black").assert(predicate::path::is_dir()); tool_dir.child("black").assert(predicate::path::is_dir());
@ -401,7 +401,7 @@ fn tool_install_already_installed() {
----- stderr ----- ----- stderr -----
warning: `uv tool install` is experimental and may change without warning. warning: `uv tool install` is experimental and may change without warning.
Tool `black` is already installed `black` is already installed
"###); "###);
tool_dir.child("black").assert(predicate::path::is_dir()); tool_dir.child("black").assert(predicate::path::is_dir());
@ -451,7 +451,7 @@ fn tool_install_already_installed() {
+ pathspec==0.12.1 + pathspec==0.12.1
- platformdirs==4.2.0 - platformdirs==4.2.0
+ platformdirs==4.2.0 + platformdirs==4.2.0
Installed: black, blackd Installed 2 executables: black, blackd
"###); "###);
// Install `black` again with `--reinstall-package` for `black` // Install `black` again with `--reinstall-package` for `black`
@ -473,7 +473,7 @@ fn tool_install_already_installed() {
Installed [N] packages in [TIME] Installed [N] packages in [TIME]
- black==24.3.0 - black==24.3.0
+ black==24.3.0 + black==24.3.0
Installed: black, blackd Installed 2 executables: black, blackd
"###); "###);
// Install `black` again with `--reinstall-package` for a dependency // Install `black` again with `--reinstall-package` for a dependency
@ -495,7 +495,7 @@ fn tool_install_already_installed() {
Installed [N] packages in [TIME] Installed [N] packages in [TIME]
- click==8.1.7 - click==8.1.7
+ click==8.1.7 + click==8.1.7
Installed: black, blackd Installed 2 executables: black, blackd
"###); "###);
} }
@ -531,7 +531,7 @@ fn tool_install_entry_point_exists() {
+ packaging==24.0 + packaging==24.0
+ pathspec==0.12.1 + pathspec==0.12.1
+ platformdirs==4.2.0 + platformdirs==4.2.0
error: Entry point for tool already exists: black (use `--force` to overwrite) error: Executable already exists: black (use `--force` to overwrite)
"###); "###);
// We should delete the virtual environment // We should delete the virtual environment
@ -569,7 +569,7 @@ fn tool_install_entry_point_exists() {
+ packaging==24.0 + packaging==24.0
+ pathspec==0.12.1 + pathspec==0.12.1
+ platformdirs==4.2.0 + platformdirs==4.2.0
error: Entry point for tool already exists: black (use `--force` to overwrite) error: Executable already exists: black (use `--force` to overwrite)
"###); "###);
// We should not create a virtual environment // We should not create a virtual environment
@ -609,7 +609,7 @@ fn tool_install_entry_point_exists() {
+ packaging==24.0 + packaging==24.0
+ pathspec==0.12.1 + pathspec==0.12.1
+ platformdirs==4.2.0 + platformdirs==4.2.0
error: Entry points for tool already exist: black, blackd (use `--force` to overwrite) error: Executables already exist: black, blackd (use `--force` to overwrite)
"###); "###);
// Install `black` with `--force` // Install `black` with `--force`
@ -632,7 +632,7 @@ fn tool_install_entry_point_exists() {
+ packaging==24.0 + packaging==24.0
+ pathspec==0.12.1 + pathspec==0.12.1
+ platformdirs==4.2.0 + platformdirs==4.2.0
Installed: black, blackd Installed 2 executables: black, blackd
"###); "###);
tool_dir.child("black").assert(predicate::path::is_dir()); tool_dir.child("black").assert(predicate::path::is_dir());
@ -649,7 +649,7 @@ fn tool_install_entry_point_exists() {
----- stderr ----- ----- stderr -----
warning: `uv tool install` is experimental and may change without warning. warning: `uv tool install` is experimental and may change without warning.
Installed: black, blackd Installed 2 executables: black, blackd
"###); "###);
tool_dir.child("black").assert(predicate::path::is_dir()); tool_dir.child("black").assert(predicate::path::is_dir());
@ -665,7 +665,7 @@ fn tool_install_entry_point_exists() {
----- stderr ----- ----- stderr -----
warning: `uv tool install` is experimental and may change without warning. warning: `uv tool install` is experimental and may change without warning.
Tool `black` is already installed `black` is already installed
"###); "###);
tool_dir.child("black").assert(predicate::path::is_dir()); tool_dir.child("black").assert(predicate::path::is_dir());
@ -697,7 +697,7 @@ fn tool_install_entry_point_exists() {
+ pathspec==0.12.1 + pathspec==0.12.1
- platformdirs==4.2.0 - platformdirs==4.2.0
+ platformdirs==4.2.0 + platformdirs==4.2.0
Installed: black, blackd Installed 2 executables: black, blackd
"###); "###);
tool_dir.child("black").assert(predicate::path::is_dir()); tool_dir.child("black").assert(predicate::path::is_dir());
@ -793,7 +793,7 @@ fn tool_install_home() {
+ packaging==24.0 + packaging==24.0
+ pathspec==0.12.1 + pathspec==0.12.1
+ platformdirs==4.2.0 + platformdirs==4.2.0
Installed: black, blackd Installed 2 executables: black, blackd
"###); "###);
context context
@ -829,7 +829,7 @@ fn tool_install_xdg_data_home() {
+ packaging==24.0 + packaging==24.0
+ pathspec==0.12.1 + pathspec==0.12.1
+ platformdirs==4.2.0 + platformdirs==4.2.0
Installed: black, blackd Installed 2 executables: black, blackd
"###); "###);
context context
@ -865,7 +865,7 @@ fn tool_install_xdg_bin_home() {
+ packaging==24.0 + packaging==24.0
+ pathspec==0.12.1 + pathspec==0.12.1
+ platformdirs==4.2.0 + platformdirs==4.2.0
Installed: black, blackd Installed 2 executables: black, blackd
"###); "###);
bin_dir bin_dir
@ -894,7 +894,7 @@ fn tool_install_no_entrypoints() {
Prepared 1 package in [TIME] Prepared 1 package in [TIME]
Installed 1 package in [TIME] Installed 1 package in [TIME]
+ iniconfig==2.0.0 + iniconfig==2.0.0
error: No entry points found for tool `iniconfig` error: No executables found for `iniconfig`
"###); "###);
} }
@ -925,7 +925,7 @@ fn tool_install_unnamed_package() {
+ packaging==24.0 + packaging==24.0
+ pathspec==0.12.1 + pathspec==0.12.1
+ platformdirs==4.2.0 + platformdirs==4.2.0
Installed: black, blackd Installed 2 executables: black, blackd
"###); "###);
tool_dir.child("black").assert(predicate::path::is_dir()); tool_dir.child("black").assert(predicate::path::is_dir());
@ -1002,7 +1002,7 @@ fn tool_install_unnamed_conflict() {
----- stderr ----- ----- stderr -----
warning: `uv tool install` is experimental and may change without warning. warning: `uv tool install` is experimental and may change without warning.
error: Package name `iniconfig` provided with `--from` does not match install request `black` error: Package name (`iniconfig`) provided with `--from` does not match install request (`black`)
"###); "###);
} }
@ -1035,7 +1035,7 @@ fn tool_install_unnamed_from() {
+ packaging==24.0 + packaging==24.0
+ pathspec==0.12.1 + pathspec==0.12.1
+ platformdirs==4.2.0 + platformdirs==4.2.0
Installed: black, blackd Installed 2 executables: black, blackd
"###); "###);
tool_dir.child("black").assert(predicate::path::is_dir()); tool_dir.child("black").assert(predicate::path::is_dir());
@ -1121,7 +1121,7 @@ fn tool_install_unnamed_with() {
+ packaging==24.0 + packaging==24.0
+ pathspec==0.12.1 + pathspec==0.12.1
+ platformdirs==4.2.0 + platformdirs==4.2.0
Installed: black, blackd Installed 2 executables: black, blackd
"###); "###);
tool_dir.child("black").assert(predicate::path::is_dir()); tool_dir.child("black").assert(predicate::path::is_dir());
@ -1209,7 +1209,7 @@ fn tool_install_upgrade() {
+ packaging==24.0 + packaging==24.0
+ pathspec==0.12.1 + pathspec==0.12.1
+ platformdirs==4.2.0 + platformdirs==4.2.0
Installed: black, blackd Installed 2 executables: black, blackd
"###); "###);
insta::with_settings!({ insta::with_settings!({
@ -1238,7 +1238,7 @@ fn tool_install_upgrade() {
----- stderr ----- ----- stderr -----
warning: `uv tool install` is experimental and may change without warning. warning: `uv tool install` is experimental and may change without warning.
Installed: black, blackd Installed 2 executables: black, blackd
"###); "###);
insta::with_settings!({ insta::with_settings!({
@ -1272,7 +1272,7 @@ fn tool_install_upgrade() {
Prepared [N] packages in [TIME] Prepared [N] packages in [TIME]
Installed [N] packages in [TIME] Installed [N] packages in [TIME]
+ iniconfig==2.0.0 (from https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl) + iniconfig==2.0.0 (from https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl)
Installed: black, blackd Installed 2 executables: black, blackd
"###); "###);
insta::with_settings!({ insta::with_settings!({
@ -1312,7 +1312,7 @@ fn tool_install_upgrade() {
- black==24.1.1 - black==24.1.1
+ black==24.3.0 + black==24.3.0
- iniconfig==2.0.0 (from https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl) - iniconfig==2.0.0 (from https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl)
Installed: black, blackd Installed 2 executables: black, blackd
"###); "###);
insta::with_settings!({ insta::with_settings!({
@ -1361,7 +1361,7 @@ fn tool_install_python_request() {
+ packaging==24.0 + packaging==24.0
+ pathspec==0.12.1 + pathspec==0.12.1
+ platformdirs==4.2.0 + platformdirs==4.2.0
Installed: black, blackd Installed 2 executables: black, blackd
"###); "###);
// Install with Python 3.12 (compatible). // Install with Python 3.12 (compatible).
@ -1377,7 +1377,7 @@ fn tool_install_python_request() {
----- stderr ----- ----- stderr -----
warning: `uv tool install` is experimental and may change without warning. warning: `uv tool install` is experimental and may change without warning.
Tool `black` is already installed `black` is already installed
"###); "###);
// Install with Python 3.11 (incompatible). // Install with Python 3.11 (incompatible).
@ -1393,7 +1393,7 @@ fn tool_install_python_request() {
----- stderr ----- ----- stderr -----
warning: `uv tool install` is experimental and may change without warning. warning: `uv tool install` is experimental and may change without warning.
Existing environment for `black` does not satisfy the requested Python interpreter: `Python 3.11` Existing environment for `black` does not satisfy the requested Python interpreter (`Python 3.11`)
Resolved [N] packages in [TIME] Resolved [N] packages in [TIME]
Prepared [N] packages in [TIME] Prepared [N] packages in [TIME]
Installed [N] packages in [TIME] Installed [N] packages in [TIME]
@ -1403,7 +1403,7 @@ fn tool_install_python_request() {
+ packaging==24.0 + packaging==24.0
+ pathspec==0.12.1 + pathspec==0.12.1
+ platformdirs==4.2.0 + platformdirs==4.2.0
Installed: black, blackd Installed 2 executables: black, blackd
"###); "###);
} }
@ -1436,7 +1436,7 @@ fn tool_install_preserve_environment() {
+ packaging==24.0 + packaging==24.0
+ pathspec==0.12.1 + pathspec==0.12.1
+ platformdirs==4.2.0 + platformdirs==4.2.0
Installed: black, blackd Installed 2 executables: black, blackd
"###); "###);
// Install `black`, but with an incompatible requirement. // Install `black`, but with an incompatible requirement.
@ -1467,6 +1467,6 @@ fn tool_install_preserve_environment() {
----- stderr ----- ----- stderr -----
warning: `uv tool install` is experimental and may change without warning. warning: `uv tool install` is experimental and may change without warning.
Tool `black==24.1.1` is already installed `black==24.1.1` is already installed
"###); "###);
} }

View file

@ -31,9 +31,9 @@ fn tool_list() {
exit_code: 0 exit_code: 0
----- stdout ----- ----- stdout -----
black v24.2.0 black v24.2.0
black - black
blackd - blackd
----- stderr ----- ----- stderr -----
warning: `uv tool list` is experimental and may change without warning. warning: `uv tool list` is experimental and may change without warning.
"###); "###);
@ -131,7 +131,7 @@ fn tool_list_bad_environment() -> Result<()> {
exit_code: 0 exit_code: 0
----- stdout ----- ----- stdout -----
ruff v0.3.4 ruff v0.3.4
ruff - ruff
----- stderr ----- ----- stderr -----
warning: `uv tool list` is experimental and may change without warning. warning: `uv tool list` is experimental and may change without warning.

View file

@ -31,7 +31,7 @@ fn tool_uninstall() {
----- stderr ----- ----- stderr -----
warning: `uv tool uninstall` is experimental and may change without warning. warning: `uv tool uninstall` is experimental and may change without warning.
Uninstalled: black, blackd Uninstalled 2 executables: black, blackd
"###); "###);
// After uninstalling the tool, it shouldn't be listed. // After uninstalling the tool, it shouldn't be listed.
@ -66,7 +66,7 @@ fn tool_uninstall() {
+ packaging==24.0 + packaging==24.0
+ pathspec==0.12.1 + pathspec==0.12.1
+ platformdirs==4.2.0 + platformdirs==4.2.0
Installed: black, blackd Installed 2 executables: black, blackd
"###); "###);
} }
@ -85,7 +85,7 @@ fn tool_uninstall_not_installed() {
----- stderr ----- ----- stderr -----
warning: `uv tool uninstall` is experimental and may change without warning. warning: `uv tool uninstall` is experimental and may change without warning.
error: Tool `black` is not installed error: `black` is not installed
"###); "###);
} }
@ -115,6 +115,6 @@ fn tool_uninstall_missing_receipt() {
----- stderr ----- ----- stderr -----
warning: `uv tool uninstall` is experimental and may change without warning. warning: `uv tool uninstall` is experimental and may change without warning.
Removed dangling environment for tool: `black` (missing receipt) Removed dangling environment for `black`
"###); "###);
} }