Repository: astral-sh/uv
Pull request #13264: Add `--show-with` to `uv tool list` to list packages included by `--with`
Author: login: gaardhus
Labels: name: cli
description: Related to the command line interface
Created: 2025-05-02T12:36:00Z | Merged: 2025-05-06T20:23:50Z

## Summary

Add a `--show-extras` argument to the `uv tool list` cli, to show which extra dependencies were installed with the tool.

i.e.

```bash
$ uv tool install fastapi --with requests --with typer==0.14
```

```bash
$ uv tool list --show-extras
fastapi v0.115.12 [extras: requests, typer==0.14]
- fastapi
```

## Test Plan

Added a new test function based on the others in the same file, with the other arguments tested with the new argument as well.


Diff:
diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs
index 8cbb05779ce80..8ca8e5cdcb17e 100644
--- a/crates/uv-cli/src/lib.rs
+++ b/crates/uv-cli/src/lib.rs
@@ -4246,11 +4246,11 @@ pub struct ToolInstallArgs {
     #[arg(long, hide = true)]
     pub from: Option<String>,
 
-    /// Include the following extra requirements.
+    /// Include the following additional requirements.
     #[arg(long)]
     pub with: Vec<comma::CommaSeparatedRequirements>,
 
-    /// Run all requirements listed in the given `requirements.txt` files.
+    /// Include all requirements listed in the given `requirements.txt` files.
     #[arg(long, value_delimiter = ',', value_parser = parse_maybe_file_path)]
     pub with_requirements: Vec<Maybe<PathBuf>>,
 
@@ -4334,6 +4334,10 @@ pub struct ToolListArgs {
     #[arg(long)]
     pub show_version_specifiers: bool,
 
+    /// Whether to display the additional requirements installed with each tool.
+    #[arg(long)]
+    pub show_with: bool,
+
     // Hide unused global Python options.
     #[arg(long, hide = true)]
     pub python_preference: Option<PythonPreference>,
diff --git a/crates/uv/src/commands/tool/list.rs b/crates/uv/src/commands/tool/list.rs
index 3af75ae5c63d8..4def9cfe48f9d 100644
--- a/crates/uv/src/commands/tool/list.rs
+++ b/crates/uv/src/commands/tool/list.rs
@@ -16,6 +16,7 @@ use crate::printer::Printer;
 pub(crate) async fn list(
     show_paths: bool,
     show_version_specifiers: bool,
+    show_with: bool,
     cache: &Cache,
     printer: Printer,
 ) -> Result<ExitStatus> {
@@ -63,35 +64,50 @@ pub(crate) async fn list(
             }
         };
 
-        let version_specifier = if show_version_specifiers {
-            let specifiers = tool
-                .requirements()
-                .iter()
-                .filter(|req| req.name == name)
-                .map(|req| req.source.to_string())
-                .filter(|s| !s.is_empty())
-                .join(", ");
-            if specifiers.is_empty() {
-                String::new()
-            } else {
+        let version_specifier = show_version_specifiers
+            .then(|| {
+                tool.requirements()
+                    .iter()
+                    .filter(|req| req.name == name)
+                    .map(|req| req.source.to_string())
+                    .filter(|s| !s.is_empty())
+                    .peekable()
+            })
+            .take_if(|specifiers| specifiers.peek().is_some())
+            .map(|mut specifiers| {
+                let specifiers = specifiers.join(", ");
                 format!(" [required: {specifiers}]")
-            }
-        } else {
-            String::new()
-        };
+            })
+            .unwrap_or_default();
+
+        let with_requirements = show_with
+            .then(|| {
+                tool.requirements()
+                    .iter()
+                    .filter(|req| req.name != name)
+                    .peekable()
+            })
+            .take_if(|requirements| requirements.peek().is_some())
+            .map(|requirements| {
+                let requirements = requirements
+                    .map(|req| format!("{}{}", req.name, req.source))
+                    .join(", ");
+                format!(" [with: {requirements}]")
+            })
+            .unwrap_or_default();
 
         if show_paths {
             writeln!(
                 printer.stdout(),
                 "{} ({})",
-                format!("{name} v{version}{version_specifier}").bold(),
+                format!("{name} v{version}{version_specifier}{with_requirements}").bold(),
                 installed_tools.tool_dir(&name).simplified_display().cyan(),
             )?;
         } else {
             writeln!(
                 printer.stdout(),
                 "{}",
-                format!("{name} v{version}{version_specifier}").bold()
+                format!("{name} v{version}{version_specifier}{with_requirements}").bold()
             )?;
         }
 
diff --git a/crates/uv/src/lib.rs b/crates/uv/src/lib.rs
index e6dd8d7bb8f51..323138a2e01dd 100644
--- a/crates/uv/src/lib.rs
+++ b/crates/uv/src/lib.rs
@@ -1258,6 +1258,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
             commands::tool_list(
                 args.show_paths,
                 args.show_version_specifiers,
+                args.show_with,
                 &cache,
                 printer,
             )
diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs
index 162826826fd5d..24512903483d4 100644
--- a/crates/uv/src/settings.rs
+++ b/crates/uv/src/settings.rs
@@ -772,6 +772,7 @@ impl ToolUpgradeSettings {
 pub(crate) struct ToolListSettings {
     pub(crate) show_paths: bool,
     pub(crate) show_version_specifiers: bool,
+    pub(crate) show_with: bool,
 }
 
 impl ToolListSettings {
@@ -781,6 +782,7 @@ impl ToolListSettings {
         let ToolListArgs {
             show_paths,
             show_version_specifiers,
+            show_with,
             python_preference: _,
             no_python_downloads: _,
         } = args;
@@ -788,6 +790,7 @@ impl ToolListSettings {
         Self {
             show_paths,
             show_version_specifiers,
+            show_with,
         }
     }
 }
diff --git a/crates/uv/tests/it/tool_install.rs b/crates/uv/tests/it/tool_install.rs
index 5733df92d746c..9b32bcc2695ea 100644
--- a/crates/uv/tests/it/tool_install.rs
+++ b/crates/uv/tests/it/tool_install.rs
@@ -2021,7 +2021,7 @@ fn tool_install_unnamed_with() {
     "###);
 }
 
-/// Test installing a tool with extra requirements from a `requirements.txt` file.
+/// Test installing a tool with additional requirements from a `requirements.txt` file.
 #[test]
 fn tool_install_requirements_txt() {
     let context = TestContext::new("3.12")
diff --git a/crates/uv/tests/it/tool_list.rs b/crates/uv/tests/it/tool_list.rs
index 3326bb7beb136..7bc00116d07d9 100644
--- a/crates/uv/tests/it/tool_list.rs
+++ b/crates/uv/tests/it/tool_list.rs
@@ -337,3 +337,118 @@ fn tool_list_show_version_specifiers() {
     ----- stderr -----
     "###);
 }
+
+#[test]
+fn tool_list_show_with() {
+    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 additional requirements
+    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 additional requirements
+    context
+        .tool_install()
+        .arg("flask")
+        .arg("--with")
+        .arg("requests")
+        .arg("--with")
+        .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 `ruff` with version specifier and additional requirements
+    context
+        .tool_install()
+        .arg("ruff==0.3.4")
+        .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-with
+    uv_snapshot!(context.filters(), context.tool_list().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 [with: requests, black==24.2.0]
+    - flask
+    ruff v0.3.4 [with: requests]
+    - ruff
+
+    ----- stderr -----
+    "###);
+
+    // Test with both --show-with and --show-paths
+    uv_snapshot!(context.filters(), context.tool_list().arg("--show-with").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 [with: requests, black==24.2.0] ([TEMP_DIR]/tools/flask)
+    - flask ([TEMP_DIR]/bin/flask)
+    ruff v0.3.4 [with: requests] ([TEMP_DIR]/tools/ruff)
+    - ruff ([TEMP_DIR]/bin/ruff)
+
+    ----- stderr -----
+    "###);
+
+    // Test with both --show-with and --show-version-specifiers
+    uv_snapshot!(context.filters(), context.tool_list().arg("--show-with").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 [with: requests, black==24.2.0]
+    - flask
+    ruff v0.3.4 [required: ==0.3.4] [with: requests]
+    - ruff
+
+    ----- stderr -----
+    "###);
+
+    // Test with all flags
+    uv_snapshot!(context.filters(), context.tool_list()
+    .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 [with: requests, black==24.2.0] ([TEMP_DIR]/tools/flask)
+    - flask ([TEMP_DIR]/bin/flask)
+    ruff v0.3.4 [required: ==0.3.4] [with: requests] ([TEMP_DIR]/tools/ruff)
+    - ruff ([TEMP_DIR]/bin/ruff)
+
+    ----- stderr -----
+    "###);
+}
diff --git a/docs/reference/cli.md b/docs/reference/cli.md
index 0d121791ebd4b..b49fa027ea241 100644
--- a/docs/reference/cli.md
+++ b/docs/reference/cli.md
@@ -3759,11 +3759,11 @@ uv tool install [OPTIONS] <PACKAGE>
 
 <p>You can configure fine-grained logging using the <code>RUST_LOG</code> environment variable. (&lt;https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives&gt;)</p>
 
-</dd><dt id="uv-tool-install--with"><a href="#uv-tool-install--with"><code>--with</code></a> <i>with</i></dt><dd><p>Include the following extra requirements</p>
+</dd><dt id="uv-tool-install--with"><a href="#uv-tool-install--with"><code>--with</code></a> <i>with</i></dt><dd><p>Include the following additional requirements</p>
 
 </dd><dt id="uv-tool-install--with-editable"><a href="#uv-tool-install--with-editable"><code>--with-editable</code></a> <i>with-editable</i></dt><dd><p>Include the given packages in editable mode</p>
 
-</dd><dt id="uv-tool-install--with-requirements"><a href="#uv-tool-install--with-requirements"><code>--with-requirements</code></a> <i>with-requirements</i></dt><dd><p>Run all requirements listed in the given <code>requirements.txt</code> files</p>
+</dd><dt id="uv-tool-install--with-requirements"><a href="#uv-tool-install--with-requirements"><code>--with-requirements</code></a> <i>with-requirements</i></dt><dd><p>Include all requirements listed in the given <code>requirements.txt</code> files</p>
 
 </dd></dl>
 
@@ -4176,6 +4176,8 @@ uv tool list [OPTIONS]
 
 </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>
+
 </dd><dt id="uv-tool-list--verbose"><a href="#uv-tool-list--verbose"><code>--verbose</code></a>, <code>-v</code></dt><dd><p>Use verbose output.</p>
 
 <p>You can configure fine-grained logging using the <code>RUST_LOG</code> environment variable. (&lt;https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives&gt;)</p>


Reviews:
user: login: zanieb
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-06T12:53:43Z
user: login: zanieb
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-06T12:54:29Z
user: login: zanieb
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-06T13:01:23Z
user: login: zanieb
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-06T13:04:12Z
user: login: gaardhus
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T13:12:54Z
user: login: gaardhus
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T13:44:37Z
user: login: gaardhus
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T14:27:04Z
user: login: gaardhus
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T14:57:30Z
user: login: zanieb
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-06T15:02:14Z
user: login: zanieb
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-06T15:02:24Z
user: login: zanieb
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-06T15:03:53Z
user: login: gaardhus
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T17:43:23Z
user: login: zanieb
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-06T17:51:47Z
user: login: zanieb
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-06T17:58:05Z
user: login: zanieb
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-06T17:59:17Z
user: login: zanieb
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-06T18:03:59Z
user: login: gaardhus
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T18:54:57Z
user: login: zanieb
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-06T19:05:14Z
user: login: zanieb
body: Thanks for your patience!
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-06T19:05:38Z
user: login: zanieb
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-06T19:06:26Z
user: login: zanieb
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-06T19:06:45Z
user: login: zanieb
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-06T19:07:00Z

Review comments:
diff_hunk: @@ -80,18 +81,41 @@ pub(crate) async fn list(
             String::new()
         };
 
+        let extra_requirements = if show_with {
path: crates/uv/src/commands/tool/list.rs
user: login: zanieb
body: Can you rename this variable to match, e.g., `with_requirements`?
created_at: 2025-05-06T12:53:43Z
author_association: MEMBER
diff_hunk: @@ -337,3 +337,99 @@ fn tool_list_show_version_specifiers() {
     ----- stderr -----
     "###);
 }
+
+#[test]
+fn tool_list_show_with() {
+    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 `flask` with extra requirements
+    context
+        .tool_install()
+        .arg("flask")
+        .arg("--with")
+        .arg("requests")
+        .arg("--with")
+        .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 `black` without extra requirements
+    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();
+
+    // Test with --show-with
+    uv_snapshot!(context.filters(), context.tool_list().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 [with: requests, black==24.2.0]
+    - flask
+
+    ----- stderr -----
+    "###);
+
+    // Test with both --show-with and --show-paths
+    uv_snapshot!(context.filters(), context.tool_list().arg("--show-with").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 [with: requests, black==24.2.0] ([TEMP_DIR]/tools/flask)
+    - flask ([TEMP_DIR]/bin/flask)
+
+    ----- stderr -----
+    "###);
+
+    // Test with both --show-with and --show-version-specifiers
+    uv_snapshot!(context.filters(), context.tool_list().arg("--show-with").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 [with: requests, black==24.2.0]
+    - flask
+
+    ----- stderr -----
+    "###);
+
+    // Test with all flags
+    uv_snapshot!(context.filters(), context.tool_list()
+    .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 [with: requests, black==24.2.0] ([TEMP_DIR]/tools/flask)
path: crates/uv/tests/it/tool_list.rs
user: login: zanieb
body: How does `with:` interact with `required:`? Can you add a test case for that?
created_at: 2025-05-06T12:54:29Z
author_association: MEMBER
diff_hunk: @@ -80,18 +81,41 @@ pub(crate) async fn list(
             String::new()
         };
 
+        let extra_requirements = if show_with {
+            let extra_requirements = tool
+                .requirements()
+                .iter()
+                .filter(|req| req.name != name)
+                .map(|req| {
+                    if !req.source.to_string().is_empty() {
path: crates/uv/src/commands/tool/list.rs
user: login: zanieb
body: Is the requirement source display ever empty?
created_at: 2025-05-06T13:01:23Z
author_association: MEMBER
diff_hunk: @@ -80,18 +81,41 @@ pub(crate) async fn list(
             String::new()
         };
 
+        let extra_requirements = if show_with {
+            let extra_requirements = tool
+                .requirements()
+                .iter()
+                .filter(|req| req.name != name)
+                .map(|req| {
+                    if !req.source.to_string().is_empty() {
+                        format!("{}{}", req.name, req.source)
+                    } else {
+                        req.name.to_string()
+                    }
+                })
+                .filter(|s| !s.is_empty())
+                .join(", ");
+            if extra_requirements.is_empty() {
+                String::new()
+            } else {
+                format!(" [with: {extra_requirements}]")
+            }
+        } else {
+            String::new()
+        };
path: crates/uv/src/commands/tool/list.rs
user: login: zanieb
body: I think you could rewrite this entire block as something like

```rust
        let extra_requirements = (show_with && !tool.requirements().is_empty())
            .then(|| {
                let requirements = tool
                    .requirements()
                    .iter()
                    // Exclude the package itself
                    .filter(|req| req.name != name)
                    .map(|req| format!("{}{}", req.name, req.source))
                    .join(", ");
                format!(" [with: {requirements}]")
            })
            .unwrap_or_default();
```
created_at: 2025-05-06T13:04:12Z
author_association: MEMBER
diff_hunk: @@ -337,3 +337,99 @@ fn tool_list_show_version_specifiers() {
     ----- stderr -----
     "###);
 }
+
+#[test]
+fn tool_list_show_with() {
+    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 `flask` with extra requirements
+    context
+        .tool_install()
+        .arg("flask")
+        .arg("--with")
+        .arg("requests")
+        .arg("--with")
+        .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 `black` without extra requirements
+    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();
+
+    // Test with --show-with
+    uv_snapshot!(context.filters(), context.tool_list().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 [with: requests, black==24.2.0]
+    - flask
+
+    ----- stderr -----
+    "###);
+
+    // Test with both --show-with and --show-paths
+    uv_snapshot!(context.filters(), context.tool_list().arg("--show-with").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 [with: requests, black==24.2.0] ([TEMP_DIR]/tools/flask)
+    - flask ([TEMP_DIR]/bin/flask)
+
+    ----- stderr -----
+    "###);
+
+    // Test with both --show-with and --show-version-specifiers
+    uv_snapshot!(context.filters(), context.tool_list().arg("--show-with").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 [with: requests, black==24.2.0]
+    - flask
+
+    ----- stderr -----
+    "###);
+
+    // Test with all flags
+    uv_snapshot!(context.filters(), context.tool_list()
+    .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 [with: requests, black==24.2.0] ([TEMP_DIR]/tools/flask)
path: crates/uv/tests/it/tool_list.rs
user: login: gaardhus
body: My bad, pretty sure that black test was supposed to do that, so I updated it to include an `--with requests` argument
created_at: 2025-05-06T13:12:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -80,18 +81,41 @@ pub(crate) async fn list(
             String::new()
         };
 
+        let extra_requirements = if show_with {
+            let extra_requirements = tool
+                .requirements()
+                .iter()
+                .filter(|req| req.name != name)
+                .map(|req| {
+                    if !req.source.to_string().is_empty() {
+                        format!("{}{}", req.name, req.source)
+                    } else {
+                        req.name.to_string()
+                    }
+                })
+                .filter(|s| !s.is_empty())
+                .join(", ");
+            if extra_requirements.is_empty() {
+                String::new()
+            } else {
+                format!(" [with: {extra_requirements}]")
+            }
+        } else {
+            String::new()
+        };
path: crates/uv/src/commands/tool/list.rs
user: login: gaardhus
body: Okay that broke some stuff, need to add a check that requirements exists, I guess since installing without any --with requirements still returns the original package, and hence returns an empty `[width: ]` string. Will add the original test without any --with requirements which I was supposed to test this back in the test suite.
created_at: 2025-05-06T13:44:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -80,18 +81,41 @@ pub(crate) async fn list(
             String::new()
         };
 
+        let extra_requirements = if show_with {
+            let extra_requirements = tool
+                .requirements()
+                .iter()
+                .filter(|req| req.name != name)
+                .map(|req| {
+                    if !req.source.to_string().is_empty() {
+                        format!("{}{}", req.name, req.source)
+                    } else {
+                        req.name.to_string()
+                    }
+                })
+                .filter(|s| !s.is_empty())
+                .join(", ");
+            if extra_requirements.is_empty() {
+                String::new()
+            } else {
+                format!(" [with: {extra_requirements}]")
+            }
+        } else {
+            String::new()
+        };
path: crates/uv/src/commands/tool/list.rs
user: login: gaardhus
body: I'm super new to rust, so sorry if there is something I don't ace.

Since the requirements array may be empty, I think we do need an if else clause here before inserting the values?

So currently working implementation would be 

```rs
        let with_requirements = (show_with && !tool.requirements().is_empty())
            .then(|| {
                let requirements = tool
                    .requirements()
                    .iter()
                    .filter(|req| req.name != name)
                    .map(|req| format!("{}{}", req.name, req.source))
                    .join(", ");
                if requirements.is_empty() {
                    String::new()
                } else {
                    format!(" [with: {requirements}]")
                }
            })
            .unwrap_or_default();
```

My initial implementation was based on the version_specifier parsing on the lines above. So if you prefer unwrap_or_default should I also change that chunk to mirror that, ie.

```rs
        let version_specifier = show_version_specifiers
            .then(|| {
                let specifiers = tool
                    .requirements()
                    .iter()
                    .filter(|req| req.name == name)
                    .map(|req| req.source.to_string())
                    .filter(|s| !s.is_empty())
                    .join(", ");
                if specifiers.is_empty() {
                    String::new()
                } else {
                    format!(" [required: {specifiers}]")
                }
            })
            .unwrap_or_default();
```
created_at: 2025-05-06T14:27:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -80,18 +81,41 @@ pub(crate) async fn list(
             String::new()
         };
 
+        let extra_requirements = if show_with {
+            let extra_requirements = tool
+                .requirements()
+                .iter()
+                .filter(|req| req.name != name)
+                .map(|req| {
+                    if !req.source.to_string().is_empty() {
path: crates/uv/src/commands/tool/list.rs
user: login: gaardhus
body: I just copied the filtering from the code block above, but removing any if them doesn't change the output or the status of the tests? So I guess either remove them, or if the are required ideally add test cases to capture that?
created_at: 2025-05-06T14:57:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -80,18 +81,41 @@ pub(crate) async fn list(
             String::new()
         };
 
+        let extra_requirements = if show_with {
+            let extra_requirements = tool
+                .requirements()
+                .iter()
+                .filter(|req| req.name != name)
+                .map(|req| {
+                    if !req.source.to_string().is_empty() {
+                        format!("{}{}", req.name, req.source)
+                    } else {
+                        req.name.to_string()
+                    }
+                })
+                .filter(|s| !s.is_empty())
+                .join(", ");
+            if extra_requirements.is_empty() {
+                String::new()
+            } else {
+                format!(" [with: {extra_requirements}]")
+            }
+        } else {
+            String::new()
+        };
path: crates/uv/src/commands/tool/list.rs
user: login: zanieb
body: You could just do `(show_with && tool.requirements().len() > 1)`, though it's a bit less elegant since it doesn't capture that after the filter.

The prettier way is like..


```rust
        let extra_requirements = show_with
            .then(|| {
                tool.requirements()
                    .iter()
                    // Exclude the package itself
                    .filter(|req| req.name != name)
                    .peekable()
            })
            // Omit the `[with: ...]` if there are no extra requirements
            .filter(|requirements| requirements.peek().is_some())
            .map(|requirements| {
                let requirements = requirements
                    .iter()
                    .map(|req| format!("{}{}", req.name, req.source))
                    .join(", ");
                format!(" [with: {requirements}]")
            })
            .unwrap_or_default();
```
created_at: 2025-05-06T15:02:12Z
author_association: MEMBER
diff_hunk: @@ -80,18 +81,41 @@ pub(crate) async fn list(
             String::new()
         };
 
+        let extra_requirements = if show_with {
+            let extra_requirements = tool
+                .requirements()
+                .iter()
+                .filter(|req| req.name != name)
+                .map(|req| {
+                    if !req.source.to_string().is_empty() {
+                        format!("{}{}", req.name, req.source)
+                    } else {
+                        req.name.to_string()
+                    }
+                })
+                .filter(|s| !s.is_empty())
+                .join(", ");
+            if extra_requirements.is_empty() {
+                String::new()
+            } else {
+                format!(" [with: {extra_requirements}]")
+            }
+        } else {
+            String::new()
+        };
path: crates/uv/src/commands/tool/list.rs
user: login: zanieb
body: You could just do `(show_with && tool.requirements().len() > 1)`, though it's a bit less elegant since overlaps with the logic encoded in the filter.

The prettier way is like..


```rust
        let extra_requirements = show_with
            .then(|| {
                tool.requirements()
                    .iter()
                    // Exclude the package itself
                    .filter(|req| req.name != name)
                    .peekable()
            })
            // Omit the `[with: ...]` if there are no extra requirements
            .filter(|requirements| requirements.peek().is_some())
            .map(|requirements| {
                let requirements = requirements
                    .iter()
                    .map(|req| format!("{}{}", req.name, req.source))
                    .join(", ");
                format!(" [with: {requirements}]")
            })
            .unwrap_or_default();
```
created_at: 2025-05-06T15:02:24Z
author_association: MEMBER
diff_hunk: @@ -80,18 +81,41 @@ pub(crate) async fn list(
             String::new()
         };
 
+        let extra_requirements = if show_with {
+            let extra_requirements = tool
+                .requirements()
+                .iter()
+                .filter(|req| req.name != name)
+                .map(|req| {
+                    if !req.source.to_string().is_empty() {
+                        format!("{}{}", req.name, req.source)
+                    } else {
+                        req.name.to_string()
+                    }
+                })
+                .filter(|s| !s.is_empty())
+                .join(", ");
+            if extra_requirements.is_empty() {
+                String::new()
+            } else {
+                format!(" [with: {extra_requirements}]")
+            }
+        } else {
+            String::new()
+        };
path: crates/uv/src/commands/tool/list.rs
user: login: zanieb
body: (The `show_version_specifiers` implementation isn't as clean as it could be, it was also externally contributed)
created_at: 2025-05-06T15:03:53Z
author_association: MEMBER
diff_hunk: @@ -80,18 +81,41 @@ pub(crate) async fn list(
             String::new()
         };
 
+        let extra_requirements = if show_with {
+            let extra_requirements = tool
+                .requirements()
+                .iter()
+                .filter(|req| req.name != name)
+                .map(|req| {
+                    if !req.source.to_string().is_empty() {
+                        format!("{}{}", req.name, req.source)
+                    } else {
+                        req.name.to_string()
+                    }
+                })
+                .filter(|s| !s.is_empty())
+                .join(", ");
+            if extra_requirements.is_empty() {
+                String::new()
+            } else {
+                format!(" [with: {extra_requirements}]")
+            }
+        } else {
+            String::new()
+        };
path: crates/uv/src/commands/tool/list.rs
user: login: gaardhus
body: Thank you for your suggestions and detailed review!

I couldn't make the peekable work, the compiler kept throwing errors about mutability.

So I tried reimplementing and unifying the two functions like this 

```rs
        let tool_requirements = (show_version_specifiers | show_with)
            .then(|| tool.requirements())
            .unwrap_or_default();

        let version_specifier = show_version_specifiers
            .then(|| {
                let specifiers = tool_requirements
                    .iter()
                    .filter(|req| req.name == name)
                    .map(|req| req.source.to_string())
                    .filter(|s| !s.is_empty())
                    .join(", ");
                (!specifiers.is_empty())
                    .then(|| format!(" [required: {specifiers}]"))
                    .unwrap_or_default()
            })
            .unwrap_or_default();

        let with_requirements = (show_with && tool_requirements.len() > 1)
            .then(|| {
                let requirements = tool_requirements
                    .iter()
                    .filter(|req| req.name != name)
                    .map(|req| format!("{}{}", req.name, req.source))
                    .join(", ");
                format!(" [with: {requirements}]")
            })
            .unwrap_or_default();
```
created_at: 2025-05-06T17:43:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -80,18 +81,41 @@ pub(crate) async fn list(
             String::new()
         };
 
+        let extra_requirements = if show_with {
+            let extra_requirements = tool
+                .requirements()
+                .iter()
+                .filter(|req| req.name != name)
+                .map(|req| {
+                    if !req.source.to_string().is_empty() {
path: crates/uv/src/commands/tool/list.rs
user: login: zanieb
body: I don't think it's possible for it to be empty from looking at the implementation 🤷‍♀️ not sure why it's that way.
created_at: 2025-05-06T17:51:47Z
author_association: MEMBER
diff_hunk: @@ -80,18 +81,41 @@ pub(crate) async fn list(
             String::new()
         };
 
+        let extra_requirements = if show_with {
+            let extra_requirements = tool
+                .requirements()
+                .iter()
+                .filter(|req| req.name != name)
+                .map(|req| {
+                    if !req.source.to_string().is_empty() {
+                        format!("{}{}", req.name, req.source)
+                    } else {
+                        req.name.to_string()
+                    }
+                })
+                .filter(|s| !s.is_empty())
+                .join(", ");
+            if extra_requirements.is_empty() {
+                String::new()
+            } else {
+                format!(" [with: {extra_requirements}]")
+            }
+        } else {
+            String::new()
+        };
path: crates/uv/src/commands/tool/list.rs
user: login: zanieb
body: Ah sorry about that, the mutable reference thing is annoying... I'm not sure if there's a fix for that (but I'll ask someone who knows more than me).
created_at: 2025-05-06T17:58:05Z
author_association: MEMBER
diff_hunk: @@ -80,18 +81,41 @@ pub(crate) async fn list(
             String::new()
         };
 
+        let extra_requirements = if show_with {
+            let extra_requirements = tool
+                .requirements()
+                .iter()
+                .filter(|req| req.name != name)
+                .map(|req| {
+                    if !req.source.to_string().is_empty() {
+                        format!("{}{}", req.name, req.source)
+                    } else {
+                        req.name.to_string()
+                    }
+                })
+                .filter(|s| !s.is_empty())
+                .join(", ");
+            if extra_requirements.is_empty() {
+                String::new()
+            } else {
+                format!(" [with: {extra_requirements}]")
+            }
+        } else {
+            String::new()
+        };
path: crates/uv/src/commands/tool/list.rs
user: login: zanieb
body: Ah `.take_if(|requirements| requirements.peek().is_some())` works instead of `.filter(...)`
created_at: 2025-05-06T17:59:17Z
author_association: MEMBER
diff_hunk: @@ -80,18 +81,41 @@ pub(crate) async fn list(
             String::new()
         };
 
+        let extra_requirements = if show_with {
+            let extra_requirements = tool
+                .requirements()
+                .iter()
+                .filter(|req| req.name != name)
+                .map(|req| {
+                    if !req.source.to_string().is_empty() {
+                        format!("{}{}", req.name, req.source)
+                    } else {
+                        req.name.to_string()
+                    }
+                })
+                .filter(|s| !s.is_empty())
+                .join(", ");
+            if extra_requirements.is_empty() {
+                String::new()
+            } else {
+                format!(" [with: {extra_requirements}]")
+            }
+        } else {
+            String::new()
+        };
path: crates/uv/src/commands/tool/list.rs
user: login: zanieb
body: (Rust's idioms around options take a while to learn, but they are nice once you get the hang of it)
created_at: 2025-05-06T18:03:59Z
author_association: MEMBER
diff_hunk: @@ -80,18 +81,41 @@ pub(crate) async fn list(
             String::new()
         };
 
+        let extra_requirements = if show_with {
+            let extra_requirements = tool
+                .requirements()
+                .iter()
+                .filter(|req| req.name != name)
+                .map(|req| {
+                    if !req.source.to_string().is_empty() {
+                        format!("{}{}", req.name, req.source)
+                    } else {
+                        req.name.to_string()
+                    }
+                })
+                .filter(|s| !s.is_empty())
+                .join(", ");
+            if extra_requirements.is_empty() {
+                String::new()
+            } else {
+                format!(" [with: {extra_requirements}]")
+            }
+        } else {
+            String::new()
+        };
path: crates/uv/src/commands/tool/list.rs
user: login: gaardhus
body: Then they become

```rs
        let version_specifier = show_version_specifiers
            .then(|| {
                tool.requirements()
                    .iter()
                    .filter(|req| req.name == name)
                    .map(|req| req.source.to_string())
                    .filter(|s| !s.is_empty())
                    .peekable()
            })
            .take_if(|specifiers| specifiers.peek().is_some())
            .map(|mut specifiers| {
                let specifiers = specifiers.join(", ");
                format!(" [required: {specifiers}]")
            })
            .unwrap_or_default();

        let with_requirements = show_with
            .then(|| {
                tool.requirements()
                    .iter()
                    .filter(|req| req.name != name)
                    .peekable()
            })
            .take_if(|requirements| requirements.peek().is_some())
            .map(|requirements| {
                let requirements = requirements
                    .map(|req| format!("{}{}", req.name, req.source))
                    .join(", ");
                format!(" [with: {requirements}]")
            })
            .unwrap_or_default();
```

if I'm not mistaken?
created_at: 2025-05-06T18:54:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -337,3 +337,118 @@ fn tool_list_show_version_specifiers() {
     ----- stderr -----
     "###);
 }
+
+#[test]
+fn tool_list_show_with() {
+    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 extra requirements
+    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 extra requirements
+    context
+        .tool_install()
+        .arg("flask")
+        .arg("--with")
+        .arg("requests")
+        .arg("--with")
+        .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 `ruff` with version specifier and extra requirements
+    context
+        .tool_install()
+        .arg("ruff==0.3.4")
+        .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-with
+    uv_snapshot!(context.filters(), context.tool_list().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 [with: requests, black==24.2.0]
+    - flask
+    ruff v0.3.4 [with: requests]
+    - ruff
+
+    ----- stderr -----
+    "###);
+
+    // Test with both --show-with and --show-paths
+    uv_snapshot!(context.filters(), context.tool_list().arg("--show-with").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 [with: requests, black==24.2.0] ([TEMP_DIR]/tools/flask)
+    - flask ([TEMP_DIR]/bin/flask)
+    ruff v0.3.4 [with: requests] ([TEMP_DIR]/tools/ruff)
+    - ruff ([TEMP_DIR]/bin/ruff)
+
+    ----- stderr -----
+    "###);
+
+    // Test with both --show-with and --show-version-specifiers
+    uv_snapshot!(context.filters(), context.tool_list().arg("--show-with").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 [with: requests, black==24.2.0]
+    - flask
+    ruff v0.3.4 [required: ==0.3.4] [with: requests]
path: crates/uv/tests/it/tool_list.rs
user: login: zanieb
body: Do you think these should be separate blocks? Should it be `[required: ..., with: ...]`?

There's no need for this stylistic nit to block this pull request, we can address this afterwards if we want.

cc @charliermarsh curious if you have a stance.
created_at: 2025-05-06T19:05:14Z
author_association: MEMBER
diff_hunk: @@ -4334,6 +4334,10 @@ pub struct ToolListArgs {
     #[arg(long)]
     pub show_version_specifiers: bool,
 
+    /// Whether to display the extra requirements(s) installed with each tool.
path: crates/uv-cli/src/lib.rs
user: login: zanieb
body: We might want to say "additional" here (as discussed elsewhere). If you want to update that language all at once, it can happen here or in a separate pull requests.
created_at: 2025-05-06T19:06:26Z
author_association: MEMBER
diff_hunk: @@ -4334,6 +4334,10 @@ pub struct ToolListArgs {
     #[arg(long)]
     pub show_version_specifiers: bool,
 
+    /// Whether to display the extra requirements(s) installed with each tool.
path: crates/uv-cli/src/lib.rs
user: login: zanieb
body: I think it's also fine to just say "requirements" without the floating (s)
created_at: 2025-05-06T19:06:45Z
author_association: MEMBER
diff_hunk: @@ -4334,6 +4334,10 @@ pub struct ToolListArgs {
     #[arg(long)]
     pub show_version_specifiers: bool,
 
+    /// Whether to display the extra requirements(s) installed with each tool.
path: crates/uv-cli/src/lib.rs
user: login: zanieb
body: ```suggestion
    /// Whether to display the additional requirements installed with each tool.
```

(will require generated reference update)
created_at: 2025-05-06T19:07:00Z
author_association: MEMBER

PR comments:
user: login: zanieb
created_at: 2025-05-02T13:14:50Z
body: Thanks for contributing! Is there an issue discussing this feature?
author_association: MEMBER
user: login: gaardhus
created_at: 2025-05-02T13:18:41Z
body: Tried looking but I couldn't find any; I needed the functionality my self so I just went ahead an implemented it.
author_association: CONTRIBUTOR
user: login: zanieb
created_at: 2025-05-02T13:24:25Z
body: Thanks for checking. Given that there wasn't prior discussion, we'll need to figure out what we want the user experience to look like here.

e.g., for:

> [extras: requests, typer==0.14]

Should we show the extras _after_ the `--with` dependencies? or add `with: `? It seems confusing as-is.

Another option... should we just render it as `fastapi[requests] v0.115.12`?

What's the motivation for making this opt-in? Should we always show these?

author_association: MEMBER
user: login: gaardhus
created_at: 2025-05-02T13:34:21Z
body: Sure thing!

> Thanks for checking. Given that there wasn't prior discussion, we'll need to figure out what we want the user experience to look like here.
> 
> e.g., for:
> 
> > [extras: requests, typer==0.14]
> 
> Should we show the extras _after_ the `--with` dependencies? or add `with: `? It seems confusing as-is.

Currently I thought the terminology was that you installed `extras` with `with` in the case of `uv tool install`, if that makes sense?

https://docs.astral.sh/uv/concepts/tools/#including-additional-dependencies

However, renaming my implementation to `--show-with` and `[with: requests]` I think is fine. 

> Another option... should we just render it as `fastapi[requests] v0.115.12`?
> 
> What's the motivation for making this opt-in? Should we always show these?

I made it optional since I mainly needed it for debugging I guess? So if I just need to know which tools I have installed and are available, I don't really need to know the specific requirements, (i.e. also why I guess the `--show-version-specifiers` is also an argument). Also, it might get super cluttered if you have a lot of specified extras.
author_association: CONTRIBUTOR
user: login: zanieb
created_at: 2025-05-02T13:40:25Z
body: Oh, sorry I totally misunderstood. We can't say `extras` here as that term is a bit overloaded, i.e., it means a set of optional dependency for a package (see https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#dependencies-optional-dependencies and https://packaging.python.org/en/latest/tutorials/installing-packages/#installing-extras). I should have read more carefully.

I think it's okay to do `[with: ...]` excluding version specifiers by default? `--show-version-specifiers` is indeed behind a flag because it adds a lot of visual noise, but `[with: ]` seems less likely to do that? My main concern would be users that do like... `--with-requirements <file>` and include a _lot_ of additional dependencies. I'm not sure how we want to render that, even if it's opt-in.

author_association: MEMBER
user: login: zanieb
created_at: 2025-05-02T13:41:05Z
body: (If we leave it opt-in, we need another flag name. Maybe just `--show-with` but that feels clunky to me for some reason)
author_association: MEMBER
user: login: gaardhus
created_at: 2025-05-02T13:46:39Z
body: > Oh, sorry I totally misunderstood. We can't say `extras` here as that term is a bit overloaded, i.e., it means a set of optional dependency for a package (see https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#dependencies-optional-dependencies and https://packaging.python.org/en/latest/tutorials/installing-packages/#installing-extras). I should have read more carefully.

Yeah, I was just about to say that: I see that `extra`(s) may not be that precise, since they are more directly tied with the actual dependencies of the package (https://docs.astral.sh/uv/pip/dependencies/#using-pyprojecttoml https://docs.astral.sh/uv/guides/integration/fastapi/#migrating-an-existing-fastapi-project).

> I think it's okay to do `[with: ...]` excluding version specifiers by default? `--show-version-specifiers` is indeed behind a flag because it adds a lot of visual noise, but `[with: ]` seems less likely to do that? My main concern would be users that do like... `--with-requirements <file>` and include a _lot_ of additional dependencies. I'm not sure how we want to render that, even if it's opt-in.

For my use cases I would still think it should be an argument rather than default behavior. Running `uv tool list` to get a very brief and minimal overview of the tools and their executeables is nice, and when I need more information (which will generally be for some form of debugging?) its nice to have the arguments.

> (If we leave it opt-in, we need another flag name. Maybe just `--show-with` but that feels clunky to me for some reason)

Agree, maybe that's also why I went with `--show-extras`. Could be `--show-with-requirements` or `--show-extra-requirements`?
author_association: CONTRIBUTOR
user: login: gaardhus
created_at: 2025-05-02T13:54:12Z
body: > > I think it's okay to do `[with: ...]` excluding version specifiers by default? `--show-version-specifiers` is indeed behind a flag because it adds a lot of visual noise, but `[with: ]` seems less likely to do that? My main concern would be users that do like... `--with-requirements <file>` and include a _lot_ of additional dependencies. I'm not sure how we want to render that, even if it's opt-in.
> 
> For my use cases I would still think it should be an argument rather than default behavior. Running `uv tool list` to get a very brief and minimal overview of the tools and their executeables is nice, and when I need more information (which will generally be for some form of debugging?) its nice to have the arguments.

Also, I have a hard time imagining the new argument to show less visual noise than `--show-version-specifiers` does?

> > (If we leave it opt-in, we need another flag name. Maybe just `--show-with` but that feels clunky to me for some reason)
> 
> Agree, maybe that's also why I went with `--show-extras`. Could be `--show-with-requirements` or `--show-extra-requirements`?

Or maybe the super verbose `--show-with-extra-requirements` 
author_association: CONTRIBUTOR
user: login: gaardhus
created_at: 2025-05-02T15:39:33Z
body: Just throwing in another solution: To merge the `--show-version-specifiers` with my argument into `--show-specifiers` or `--show-all-specifiers`
author_association: CONTRIBUTOR
user: login: zanieb
created_at: 2025-05-02T15:42:05Z
body: I don't think `--show-specifiers` makes sense for including these "additional" package names.

I _think_ `--show-with` makes the most sense for now. I think we can easily rename it in the future if we want.
author_association: MEMBER
user: login: gaardhus
created_at: 2025-05-02T15:51:00Z
body: Last suggestion would be to reword extra to additional, also in `uv tool install --help` 
```
      --with <WITH>
          Include the following additional requirements
```

and then for `uv tool list --help`
```
  --show-additional-requirements              Whether to display the additional requirements installed with
                             each tool
```

and maybe still `[with: ...]`  in the output of the actual command?

I don't feel strong about either, so up to you what I should implement.
author_association: CONTRIBUTOR