mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 13:25:00 +00:00
add --show-extras
to uv tool list
to list extra requirements installed with tools (#13783)
## Summary Implemented as suggested in #13761 eg. ``` $ uv tool install 'harlequin[postgres]' $ uv tool list --show-extras harlequin v2.1.2 [extras: postgres] - harlequin ``` ## Test Plan Added a new test with the argument along with the others from the `uv tool list` cli.
This commit is contained in:
parent
5400434957
commit
459c902425
6 changed files with 145 additions and 2 deletions
|
@ -4419,6 +4419,10 @@ pub struct ToolListArgs {
|
|||
#[arg(long)]
|
||||
pub show_with: bool,
|
||||
|
||||
/// Whether to display the extra requirements installed with each tool.
|
||||
#[arg(long)]
|
||||
pub show_extras: bool,
|
||||
|
||||
// Hide unused global Python options.
|
||||
#[arg(long, hide = true)]
|
||||
pub python_preference: Option<PythonPreference>,
|
||||
|
|
|
@ -13,10 +13,12 @@ use crate::commands::ExitStatus;
|
|||
use crate::printer::Printer;
|
||||
|
||||
/// List installed tools.
|
||||
#[allow(clippy::fn_params_excessive_bools)]
|
||||
pub(crate) async fn list(
|
||||
show_paths: bool,
|
||||
show_version_specifiers: bool,
|
||||
show_with: bool,
|
||||
show_extras: bool,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
) -> Result<ExitStatus> {
|
||||
|
@ -80,6 +82,21 @@ pub(crate) async fn list(
|
|||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
let extra_requirements = show_extras
|
||||
.then(|| {
|
||||
tool.requirements()
|
||||
.iter()
|
||||
.filter(|req| req.name == name)
|
||||
.flat_map(|req| req.extras.iter()) // Flatten the extras from all matching requirements
|
||||
.peekable()
|
||||
})
|
||||
.take_if(|extras| extras.peek().is_some())
|
||||
.map(|extras| {
|
||||
let extras_str = extras.map(ToString::to_string).join(", ");
|
||||
format!(" [extras: {extras_str}]")
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
let with_requirements = show_with
|
||||
.then(|| {
|
||||
tool.requirements()
|
||||
|
@ -100,14 +117,20 @@ pub(crate) async fn list(
|
|||
writeln!(
|
||||
printer.stdout(),
|
||||
"{} ({})",
|
||||
format!("{name} v{version}{version_specifier}{with_requirements}").bold(),
|
||||
format!(
|
||||
"{name} v{version}{version_specifier}{extra_requirements}{with_requirements}"
|
||||
)
|
||||
.bold(),
|
||||
installed_tools.tool_dir(&name).simplified_display().cyan(),
|
||||
)?;
|
||||
} else {
|
||||
writeln!(
|
||||
printer.stdout(),
|
||||
"{}",
|
||||
format!("{name} v{version}{version_specifier}{with_requirements}").bold()
|
||||
format!(
|
||||
"{name} v{version}{version_specifier}{extra_requirements}{with_requirements}"
|
||||
)
|
||||
.bold()
|
||||
)?;
|
||||
}
|
||||
|
||||
|
|
|
@ -1289,6 +1289,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
|||
args.show_paths,
|
||||
args.show_version_specifiers,
|
||||
args.show_with,
|
||||
args.show_extras,
|
||||
&cache,
|
||||
printer,
|
||||
)
|
||||
|
|
|
@ -782,6 +782,7 @@ pub(crate) struct ToolListSettings {
|
|||
pub(crate) show_paths: bool,
|
||||
pub(crate) show_version_specifiers: bool,
|
||||
pub(crate) show_with: bool,
|
||||
pub(crate) show_extras: bool,
|
||||
}
|
||||
|
||||
impl ToolListSettings {
|
||||
|
@ -792,6 +793,7 @@ impl ToolListSettings {
|
|||
show_paths,
|
||||
show_version_specifiers,
|
||||
show_with,
|
||||
show_extras,
|
||||
python_preference: _,
|
||||
no_python_downloads: _,
|
||||
} = args;
|
||||
|
@ -800,6 +802,7 @@ impl ToolListSettings {
|
|||
show_paths,
|
||||
show_version_specifiers,
|
||||
show_with,
|
||||
show_extras,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -452,3 +452,114 @@ fn tool_list_show_with() {
|
|||
----- stderr -----
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tool_list_show_extras() {
|
||||
let context = TestContext::new("3.12").with_filtered_exe_suffix();
|
||||
let tool_dir = context.temp_dir.child("tools");
|
||||
let bin_dir = context.temp_dir.child("bin");
|
||||
|
||||
// Install `black` without extras
|
||||
context
|
||||
.tool_install()
|
||||
.arg("black==24.2.0")
|
||||
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
|
||||
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str())
|
||||
.assert()
|
||||
.success();
|
||||
|
||||
// Install `flask` with extras and additional requirements
|
||||
context
|
||||
.tool_install()
|
||||
.arg("flask[async,dotenv]")
|
||||
.arg("--with")
|
||||
.arg("requests")
|
||||
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
|
||||
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str())
|
||||
.assert()
|
||||
.success();
|
||||
|
||||
// Test with --show-extras only
|
||||
uv_snapshot!(context.filters(), context.tool_list().arg("--show-extras")
|
||||
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
|
||||
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str()), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
black v24.2.0
|
||||
- black
|
||||
- blackd
|
||||
flask v3.0.2 [extras: async, dotenv]
|
||||
- flask
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
|
||||
// Test with both --show-extras and --show-with
|
||||
uv_snapshot!(context.filters(), context.tool_list().arg("--show-extras").arg("--show-with")
|
||||
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
|
||||
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str()), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
black v24.2.0
|
||||
- black
|
||||
- blackd
|
||||
flask v3.0.2 [extras: async, dotenv] [with: requests]
|
||||
- flask
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
|
||||
// Test with --show-extras and --show-paths
|
||||
uv_snapshot!(context.filters(), context.tool_list().arg("--show-extras").arg("--show-paths")
|
||||
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
|
||||
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str()), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
black v24.2.0 ([TEMP_DIR]/tools/black)
|
||||
- black ([TEMP_DIR]/bin/black)
|
||||
- blackd ([TEMP_DIR]/bin/blackd)
|
||||
flask v3.0.2 [extras: async, dotenv] ([TEMP_DIR]/tools/flask)
|
||||
- flask ([TEMP_DIR]/bin/flask)
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
|
||||
// Test with --show-extras and --show-version-specifiers
|
||||
uv_snapshot!(context.filters(), context.tool_list().arg("--show-extras").arg("--show-version-specifiers")
|
||||
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
|
||||
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str()), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
black v24.2.0 [required: ==24.2.0]
|
||||
- black
|
||||
- blackd
|
||||
flask v3.0.2 [extras: async, dotenv]
|
||||
- flask
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
|
||||
// Test with all flags including --show-extras
|
||||
uv_snapshot!(context.filters(), context.tool_list()
|
||||
.arg("--show-extras")
|
||||
.arg("--show-with")
|
||||
.arg("--show-version-specifiers")
|
||||
.arg("--show-paths")
|
||||
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
|
||||
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str()), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
black v24.2.0 [required: ==24.2.0] ([TEMP_DIR]/tools/black)
|
||||
- black ([TEMP_DIR]/bin/black)
|
||||
- blackd ([TEMP_DIR]/bin/blackd)
|
||||
flask v3.0.2 [extras: async, dotenv] [with: requests] ([TEMP_DIR]/tools/flask)
|
||||
- flask ([TEMP_DIR]/bin/flask)
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
}
|
||||
|
|
|
@ -2293,6 +2293,7 @@ uv tool list [OPTIONS]
|
|||
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
|
||||
<p>May also be set with the <code>UV_PROJECT</code> environment variable.</p></dd><dt id="uv-tool-list--quiet"><a href="#uv-tool-list--quiet"><code>--quiet</code></a>, <code>-q</code></dt><dd><p>Use quiet output.</p>
|
||||
<p>Repeating this option, e.g., <code>-qq</code>, will enable a silent mode in which uv will write no output to stdout.</p>
|
||||
</dd><dt id="uv-tool-list--show-extras"><a href="#uv-tool-list--show-extras"><code>--show-extras</code></a></dt><dd><p>Whether to display the extra requirements installed with each tool</p>
|
||||
</dd><dt id="uv-tool-list--show-paths"><a href="#uv-tool-list--show-paths"><code>--show-paths</code></a></dt><dd><p>Whether to display the path to each tool environment and installed executable</p>
|
||||
</dd><dt id="uv-tool-list--show-version-specifiers"><a href="#uv-tool-list--show-version-specifiers"><code>--show-version-specifiers</code></a></dt><dd><p>Whether to display the version specifier(s) used to install each tool</p>
|
||||
</dd><dt id="uv-tool-list--show-with"><a href="#uv-tool-list--show-with"><code>--show-with</code></a></dt><dd><p>Whether to display the additional requirements installed with each tool</p>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue