Clarify behavior and hint on tool install when no executables are available (#14423)

Closes https://github.com/astral-sh/uv/issues/14416
This commit is contained in:
Zanie Blue 2025-07-02 13:11:17 -05:00 committed by GitHub
parent 743260b1f5
commit a6bb65c78d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 19 additions and 15 deletions

View File

@ -218,7 +218,7 @@ pub(crate) fn finalize_tool_install(
if target_entry_points.is_empty() { if target_entry_points.is_empty() {
writeln!( writeln!(
printer.stdout(), printer.stdout(),
"No executables are provided by `{from}`", "No executables are provided by package `{from}`; removing tool",
from = name.cyan() from = name.cyan()
)?; )?;
@ -354,7 +354,9 @@ fn hint_executable_from_dependency(
let command = format!("uv tool install {}", package.name()); let command = format!("uv tool install {}", package.name());
writeln!( writeln!(
printer.stdout(), printer.stdout(),
"However, an executable with the name `{}` is available via dependency `{}`.\nDid you mean `{}`?", "{}{} An executable with the name `{}` is available via dependency `{}`.\n Did you mean `{}`?",
"hint".bold().cyan(),
":".bold(),
name.cyan(), name.cyan(),
package.name().cyan(), package.name().cyan(),
command.bold(), command.bold(),
@ -363,7 +365,9 @@ fn hint_executable_from_dependency(
packages => { packages => {
writeln!( writeln!(
printer.stdout(), printer.stdout(),
"However, an executable with the name `{}` is available via the following dependencies::", "{}{} An executable with the name `{}` is available via the following dependencies::",
"hint".bold().cyan(),
":".bold(),
name.cyan(), name.cyan(),
)?; )?;

View File

@ -448,12 +448,12 @@ fn tool_install_suggest_other_packages_with_executable() {
uv_snapshot!(filters, context.tool_install() uv_snapshot!(filters, context.tool_install()
.arg("fastapi==0.111.0") .arg("fastapi==0.111.0")
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str()) .env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str()), @r###" .env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str()), @r"
success: false success: false
exit_code: 1 exit_code: 1
----- stdout ----- ----- stdout -----
No executables are provided by `fastapi` No executables are provided by package `fastapi`; removing tool
However, an executable with the name `fastapi` is available via dependency `fastapi-cli`. hint: An executable with the name `fastapi` is available via dependency `fastapi-cli`.
Did you mean `uv tool install fastapi-cli`? Did you mean `uv tool install fastapi-cli`?
----- stderr ----- ----- stderr -----
@ -494,7 +494,7 @@ fn tool_install_suggest_other_packages_with_executable() {
+ uvicorn==0.29.0 + uvicorn==0.29.0
+ watchfiles==0.21.0 + watchfiles==0.21.0
+ websockets==12.0 + websockets==12.0
"###); ");
} }
/// Test installing a tool at a version /// Test installing a tool at a version
@ -821,11 +821,11 @@ fn tool_install_remove_on_empty() -> Result<()> {
.arg(black.path()) .arg(black.path())
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str()) .env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str()) .env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str())
.env(EnvVars::PATH, bin_dir.as_os_str()), @r###" .env(EnvVars::PATH, bin_dir.as_os_str()), @r"
success: false success: false
exit_code: 1 exit_code: 1
----- stdout ----- ----- stdout -----
No executables are provided by `black` No executables are provided by package `black`; removing tool
----- stderr ----- ----- stderr -----
Resolved 1 package in [TIME] Resolved 1 package in [TIME]
@ -839,7 +839,7 @@ fn tool_install_remove_on_empty() -> Result<()> {
- packaging==24.0 - packaging==24.0
- pathspec==0.12.1 - pathspec==0.12.1
- platformdirs==4.2.0 - platformdirs==4.2.0
"###); ");
// Re-request `black`. It should reinstall, without requiring `--force`. // Re-request `black`. It should reinstall, without requiring `--force`.
uv_snapshot!(context.filters(), context.tool_install() uv_snapshot!(context.filters(), context.tool_install()
@ -1649,18 +1649,18 @@ fn tool_install_no_entrypoints() {
.arg("iniconfig") .arg("iniconfig")
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str()) .env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str()) .env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str())
.env(EnvVars::PATH, bin_dir.as_os_str()), @r###" .env(EnvVars::PATH, bin_dir.as_os_str()), @r"
success: false success: false
exit_code: 1 exit_code: 1
----- stdout ----- ----- stdout -----
No executables are provided by `iniconfig` No executables are provided by package `iniconfig`; removing tool
----- stderr ----- ----- stderr -----
Resolved 1 package in [TIME] Resolved 1 package in [TIME]
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
"###); ");
// Ensure the tool environment is not created. // Ensure the tool environment is not created.
tool_dir tool_dir