From 9c9473f2d00caa1b915792ecf04bf8ceb3cd1ec5 Mon Sep 17 00:00:00 2001 From: InSync Date: Wed, 11 Jun 2025 11:07:03 +0000 Subject: [PATCH 01/12] Support `tool list --output-format=json` --- crates/uv-cli/src/lib.rs | 21 ++++ crates/uv/src/commands/tool/list.rs | 165 ++++++++++++++++++++++++++++ crates/uv/src/lib.rs | 1 + crates/uv/src/settings.rs | 7 +- 4 files changed, 192 insertions(+), 2 deletions(-) diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index 63e87367c..ed17f78e5 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -58,6 +58,15 @@ pub enum ListFormat { Json, } +#[derive(Debug, Default, Clone, Copy, clap::ValueEnum)] +pub enum ToolListFormat { + /// Display the list of tools as plain text. + #[default] + Text, + /// Display the list of tools as JSON. + Json, +} + fn extra_name_with_clap_error(arg: &str) -> Result { ExtraName::from_str(arg).map_err(|_err| { anyhow!( @@ -4429,6 +4438,18 @@ pub struct ToolListArgs { #[arg(long, hide = true)] pub no_python_downloads: bool, + + /// The format in which the list of tools would be displayed. + #[arg( + long, + value_enum, + default_value_t = ToolListFormat::default(), + conflicts_with = "show_paths", + conflicts_with = "show_version_specifiers", + conflicts_with = "show_with", + conflicts_with = "show_extras" + )] + pub output_format: ToolListFormat, } #[derive(Args)] diff --git a/crates/uv/src/commands/tool/list.rs b/crates/uv/src/commands/tool/list.rs index 21b16b020..aee0293c7 100644 --- a/crates/uv/src/commands/tool/list.rs +++ b/crates/uv/src/commands/tool/list.rs @@ -4,8 +4,11 @@ use anyhow::Result; use itertools::Itertools; use owo_colors::OwoColorize; +use serde::Serialize; use uv_cache::Cache; +use uv_cli::ToolListFormat; use uv_fs::Simplified; +use uv_pep440::Version; use uv_tool::InstalledTools; use uv_warnings::warn_user; @@ -15,6 +18,31 @@ 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, + output_format: ToolListFormat, + cache: &Cache, + printer: Printer, +) -> Result { + match output_format { + ToolListFormat::Text => { + list_text( + show_paths, + show_version_specifiers, + show_with, + show_extras, + cache, + printer, + ) + .await + } + ToolListFormat::Json => list_json(cache, printer).await, + } +} + +async fn list_text( show_paths: bool, show_version_specifiers: bool, show_with: bool, @@ -146,3 +174,140 @@ pub(crate) async fn list( Ok(ExitStatus::Success) } + +#[derive(Serialize)] +#[serde(untagged)] +enum ToolListEntry { + Tool { + name: String, + version: Version, + version_specifiers: Vec, + extra_requirements: Vec, + with_requirements: Vec, + directory: String, + environment: EnvironmentInfo, + entrypoints: Vec, + }, + MalformedTool { + name: String, + }, + Error { + name: String, + error: String, + }, +} + +#[derive(Serialize)] +#[serde(untagged)] +enum EnvironmentInfo { + Environment { python: String, version: Version }, + NoEnvironment, + Error { error: String }, +} + +#[derive(Serialize)] +struct Entrypoint { + name: String, + path: String, +} + +async fn list_json(cache: &Cache, printer: Printer) -> Result { + let installed_tools = InstalledTools::from_settings()?; + + match installed_tools.lock().await { + Ok(_lock) => (), + Err(uv_tool::Error::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => { + writeln!(printer.stdout(), "[]")?; + return Ok(ExitStatus::Success); + } + Err(err) => return Err(err.into()), + }; + + let tools = installed_tools.tools()?; + + if tools.is_empty() { + writeln!(printer.stdout(), "[]")?; + return Ok(ExitStatus::Success); + } + + let tool_list = tools + .into_iter() + .sorted_by_cached_key(|(name, _)| name.clone()) + .map(|(name, tool)| match tool { + Err(_) => ToolListEntry::MalformedTool { + name: name.to_string(), + }, + Ok(tool) => { + let version = match installed_tools.version(&name, cache) { + Ok(version) => version, + Err(error) => { + return ToolListEntry::Error { + name: name.to_string(), + error: error.to_string(), + }; + } + }; + + let mut version_specifiers = vec![]; + let mut extra_requirements = vec![]; + let mut with_requirements = vec![]; + + tool.requirements().iter().for_each(|req| { + if req.name == name { + let specifier = req.source.to_string(); + + if !specifier.is_empty() { + version_specifiers.push(specifier); + } + + for extra in &req.extras { + extra_requirements.push(extra.to_string()); + } + } else { + with_requirements.push(format!("{}{}", req.name, req.source)); + } + }); + + let directory = installed_tools.tool_dir(&name).display().to_string(); + let environment = match installed_tools.get_environment(&name, cache) { + Ok(None) => EnvironmentInfo::NoEnvironment, + Err(error) => EnvironmentInfo::Error { + error: error.to_string(), + }, + Ok(Some(environment)) => { + let python_executable = environment.python_executable(); + let interpreter = environment.interpreter(); + + EnvironmentInfo::Environment { + python: python_executable.display().to_string(), + version: interpreter.python_version().clone(), + } + } + }; + + let entrypoints = tool + .entrypoints() + .iter() + .map(|entrypoint| Entrypoint { + name: entrypoint.name.to_string(), + path: entrypoint.install_path.display().to_string(), + }) + .collect::>(); + + ToolListEntry::Tool { + name: name.to_string(), + version, + version_specifiers, + extra_requirements, + with_requirements, + directory, + environment, + entrypoints, + } + } + }) + .collect::>(); + + writeln!(printer.stdout(), "{}", serde_json::to_string(&tool_list)?)?; + return Ok(ExitStatus::Success); +} diff --git a/crates/uv/src/lib.rs b/crates/uv/src/lib.rs index b7b1a7859..7ffc38450 100644 --- a/crates/uv/src/lib.rs +++ b/crates/uv/src/lib.rs @@ -1290,6 +1290,7 @@ async fn run(mut cli: Cli) -> Result { args.show_version_specifiers, args.show_with, args.show_extras, + args.output_format, &cache, printer, ) diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs index b5eb2f5d0..d6b4f571d 100644 --- a/crates/uv/src/settings.rs +++ b/crates/uv/src/settings.rs @@ -11,8 +11,8 @@ use uv_cli::{ PipCheckArgs, PipCompileArgs, PipFreezeArgs, PipInstallArgs, PipListArgs, PipShowArgs, PipSyncArgs, PipTreeArgs, PipUninstallArgs, PythonFindArgs, PythonInstallArgs, PythonListArgs, PythonListFormat, PythonPinArgs, PythonUninstallArgs, RemoveArgs, RunArgs, SyncArgs, - ToolDirArgs, ToolInstallArgs, ToolListArgs, ToolRunArgs, ToolUninstallArgs, TreeArgs, VenvArgs, - VersionArgs, VersionBump, VersionFormat, + ToolDirArgs, ToolInstallArgs, ToolListArgs, ToolListFormat, ToolRunArgs, ToolUninstallArgs, + TreeArgs, VenvArgs, VersionArgs, VersionBump, VersionFormat, }; use uv_cli::{ AuthorFrom, BuildArgs, ExportArgs, PublishArgs, PythonDirArgs, ResolverInstallerArgs, @@ -783,6 +783,7 @@ pub(crate) struct ToolListSettings { pub(crate) show_version_specifiers: bool, pub(crate) show_with: bool, pub(crate) show_extras: bool, + pub(crate) output_format: ToolListFormat, } impl ToolListSettings { @@ -796,6 +797,7 @@ impl ToolListSettings { show_extras, python_preference: _, no_python_downloads: _, + output_format, } = args; Self { @@ -803,6 +805,7 @@ impl ToolListSettings { show_version_specifiers, show_with, show_extras, + output_format, } } } From 1b46ca72ad04a60fc64cc1489b22dd0ecfaac76e Mon Sep 17 00:00:00 2001 From: InSync Date: Wed, 11 Jun 2025 12:13:24 +0000 Subject: [PATCH 02/12] Update CLI reference --- docs/reference/cli.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/reference/cli.md b/docs/reference/cli.md index aef894368..17b687eb8 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -2287,7 +2287,12 @@ uv tool list [OPTIONS]

For example, spinners or progress bars.

May also be set with the UV_NO_PROGRESS environment variable.

--offline

Disable network access.

When disabled, uv will only use locally cached data and locally available files.

-

May also be set with the UV_OFFLINE environment variable.

--project project

Run the command within the given project directory.

+

May also be set with the UV_OFFLINE environment variable.

--output-format output-format

The format in which the list of tools would be displayed

+

[default: text]

Possible values:

+
    +
  • text: Display the list of tools as plain text
  • +
  • json: Display the list of tools as JSON
  • +
--project project

Run the command within the given project directory.

All pyproject.toml, uv.toml, and .python-version files will be discovered by walking up the directory tree from the project root, as will the project's virtual environment (.venv).

Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.

See --directory to change the working directory entirely.

From 10d51d8b107908077ba248143b5363678cabf828 Mon Sep 17 00:00:00 2001 From: InSync Date: Wed, 11 Jun 2025 14:19:20 +0000 Subject: [PATCH 03/12] Clippy --- crates/uv/src/commands/tool/list.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/uv/src/commands/tool/list.rs b/crates/uv/src/commands/tool/list.rs index aee0293c7..27613732b 100644 --- a/crates/uv/src/commands/tool/list.rs +++ b/crates/uv/src/commands/tool/list.rs @@ -42,6 +42,7 @@ pub(crate) async fn list( } } +#[allow(clippy::fn_params_excessive_bools)] async fn list_text( show_paths: bool, show_version_specifiers: bool, @@ -221,7 +222,7 @@ async fn list_json(cache: &Cache, printer: Printer) -> Result { return Ok(ExitStatus::Success); } Err(err) => return Err(err.into()), - }; + } let tools = installed_tools.tools()?; @@ -309,5 +310,5 @@ async fn list_json(cache: &Cache, printer: Printer) -> Result { .collect::>(); writeln!(printer.stdout(), "{}", serde_json::to_string(&tool_list)?)?; - return Ok(ExitStatus::Success); + Ok(ExitStatus::Success) } From b5eb9735324e8ed6891810ef37b8fdf86dbe4fc8 Mon Sep 17 00:00:00 2001 From: InSync Date: Wed, 11 Jun 2025 14:35:33 +0000 Subject: [PATCH 04/12] Add a test --- crates/uv/tests/it/tool_list.rs | 39 +++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/crates/uv/tests/it/tool_list.rs b/crates/uv/tests/it/tool_list.rs index 93dd5756e..2f70c5160 100644 --- a/crates/uv/tests/it/tool_list.rs +++ b/crates/uv/tests/it/tool_list.rs @@ -563,3 +563,42 @@ fn tool_list_show_extras() { ----- stderr ----- "###); } + +#[test] +fn tool_list_output_format_json() { + 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("--output-format=json") + .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 ----- + [{"name":"black","version":"24.2.0","version_specifiers":["==24.2.0"],"extra_requirements":[],"with_requirements":[],"directory":"[TEMP_DIR]/tools/black","environment":{"python":"[TEMP_DIR]/tools/black/bin/python3","version":"3.12.[X]"},"entrypoints":[{"name":"black","path":"[TEMP_DIR]/bin/black"},{"name":"blackd","path":"[TEMP_DIR]/bin/blackd"}]},{"name":"flask","version":"3.0.2","version_specifiers":[],"extra_requirements":["async","dotenv"],"with_requirements":["requests"],"directory":"[TEMP_DIR]/tools/flask","environment":{"python":"[TEMP_DIR]/tools/flask/bin/python3","version":"3.12.[X]"},"entrypoints":[{"name":"flask","path":"[TEMP_DIR]/bin/flask"}]}] + + ----- stderr ----- + "###); +} From bc017e8be636f12ff688668edf7f05a064237ab7 Mon Sep 17 00:00:00 2001 From: InSync Date: Wed, 11 Jun 2025 15:00:43 +0000 Subject: [PATCH 05/12] Make test pass on Windows --- crates/uv/tests/it/common/mod.rs | 3 ++- crates/uv/tests/it/tool_list.rs | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/uv/tests/it/common/mod.rs b/crates/uv/tests/it/common/mod.rs index 67e1a6126..d967fcc0b 100644 --- a/crates/uv/tests/it/common/mod.rs +++ b/crates/uv/tests/it/common/mod.rs @@ -1144,7 +1144,8 @@ impl TestContext { regex::escape(&path.as_ref().simplified_display().to_string()) // Make separators platform agnostic because on Windows we will display // paths with Unix-style separators sometimes - .replace(r"\\", r"(\\|\/)") + // (Double-backslashes is for JSON-ified Windows paths.) + .replace(r"\\", r"(\\{1,2}|\/)") ) } diff --git a/crates/uv/tests/it/tool_list.rs b/crates/uv/tests/it/tool_list.rs index 2f70c5160..574302316 100644 --- a/crates/uv/tests/it/tool_list.rs +++ b/crates/uv/tests/it/tool_list.rs @@ -590,7 +590,6 @@ fn tool_list_output_format_json() { .assert() .success(); - // Test with --show-extras only uv_snapshot!(context.filters(), context.tool_list().arg("--output-format=json") .env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str()) .env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str()), @r###" From 802501722898a27facb8198cc4edf0163b7fd5a4 Mon Sep 17 00:00:00 2001 From: InSync Date: Wed, 11 Jun 2025 15:01:18 +0000 Subject: [PATCH 06/12] Run `list_format_json()` on Windows too now that the filter has been changed --- crates/uv/tests/it/pip_list.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/uv/tests/it/pip_list.rs b/crates/uv/tests/it/pip_list.rs index ec1f288e6..11d4b5bd5 100644 --- a/crates/uv/tests/it/pip_list.rs +++ b/crates/uv/tests/it/pip_list.rs @@ -483,7 +483,6 @@ fn list_exclude() { #[test] #[cfg(feature = "pypi")] -#[cfg(not(windows))] fn list_format_json() { let context = TestContext::new("3.12"); From 49a13135df4746e81932beec64342028a654d169 Mon Sep 17 00:00:00 2001 From: InSync Date: Wed, 11 Jun 2025 15:20:05 +0000 Subject: [PATCH 07/12] Replace path separators correctly --- crates/uv/tests/it/common/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/uv/tests/it/common/mod.rs b/crates/uv/tests/it/common/mod.rs index d967fcc0b..6d655be2e 100644 --- a/crates/uv/tests/it/common/mod.rs +++ b/crates/uv/tests/it/common/mod.rs @@ -62,7 +62,7 @@ pub const INSTA_FILTERS: &[(&str, &str)] = &[ (r"tv_sec: \d+", "tv_sec: [TIME]"), (r"tv_nsec: \d+", "tv_nsec: [TIME]"), // Rewrite Windows output to Unix output - (r"\\([\w\d]|\.)", "/$1"), + (r"\\{1,2}([\w\d]|\.)", "/$1"), (r"uv\.exe", "uv"), // uv version display ( From fe00daa79d5acfe6673a1c445d7920955b746978 Mon Sep 17 00:00:00 2001 From: InSync Date: Wed, 11 Jun 2025 15:47:06 +0000 Subject: [PATCH 08/12] Fix --- crates/uv/tests/it/common/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/uv/tests/it/common/mod.rs b/crates/uv/tests/it/common/mod.rs index 6d655be2e..bee073135 100644 --- a/crates/uv/tests/it/common/mod.rs +++ b/crates/uv/tests/it/common/mod.rs @@ -1140,7 +1140,7 @@ impl TestContext { fn path_pattern(path: impl AsRef) -> String { format!( // Trim the trailing separator for cross-platform directories filters - r"{}\\?/?", + r"{}\\{{0,2}}/?", regex::escape(&path.as_ref().simplified_display().to_string()) // Make separators platform agnostic because on Windows we will display // paths with Unix-style separators sometimes From b2e205ed89aca8f656bf6db328e4422cd0ddae46 Mon Sep 17 00:00:00 2001 From: InSync Date: Wed, 11 Jun 2025 16:44:05 +0000 Subject: [PATCH 09/12] Filter `bin`/`Scripts` --- crates/uv/tests/it/tool_list.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/uv/tests/it/tool_list.rs b/crates/uv/tests/it/tool_list.rs index 574302316..ad075f6e6 100644 --- a/crates/uv/tests/it/tool_list.rs +++ b/crates/uv/tests/it/tool_list.rs @@ -566,7 +566,9 @@ fn tool_list_show_extras() { #[test] fn tool_list_output_format_json() { - let context = TestContext::new("3.12").with_filtered_exe_suffix(); + let context = TestContext::new("3.12") + .with_filtered_exe_suffix() + .with_filtered_virtualenv_bin(); let tool_dir = context.temp_dir.child("tools"); let bin_dir = context.temp_dir.child("bin"); @@ -596,7 +598,7 @@ fn tool_list_output_format_json() { success: true exit_code: 0 ----- stdout ----- - [{"name":"black","version":"24.2.0","version_specifiers":["==24.2.0"],"extra_requirements":[],"with_requirements":[],"directory":"[TEMP_DIR]/tools/black","environment":{"python":"[TEMP_DIR]/tools/black/bin/python3","version":"3.12.[X]"},"entrypoints":[{"name":"black","path":"[TEMP_DIR]/bin/black"},{"name":"blackd","path":"[TEMP_DIR]/bin/blackd"}]},{"name":"flask","version":"3.0.2","version_specifiers":[],"extra_requirements":["async","dotenv"],"with_requirements":["requests"],"directory":"[TEMP_DIR]/tools/flask","environment":{"python":"[TEMP_DIR]/tools/flask/bin/python3","version":"3.12.[X]"},"entrypoints":[{"name":"flask","path":"[TEMP_DIR]/bin/flask"}]}] + [{"name":"black","version":"24.2.0","version_specifiers":["==24.2.0"],"extra_requirements":[],"with_requirements":[],"directory":"[TEMP_DIR]/tools/black","environment":{"python":"[TEMP_DIR]/tools/black/[BIN]/python3","version":"3.12.[X]"},"entrypoints":[{"name":"black","path":"[TEMP_DIR]/[BIN]/black"},{"name":"blackd","path":"[TEMP_DIR]/[BIN]/blackd"}]},{"name":"flask","version":"3.0.2","version_specifiers":[],"extra_requirements":["async","dotenv"],"with_requirements":["requests"],"directory":"[TEMP_DIR]/tools/flask","environment":{"python":"[TEMP_DIR]/tools/flask/[BIN]/python3","version":"3.12.[X]"},"entrypoints":[{"name":"flask","path":"[TEMP_DIR]/[BIN]/flask"}]}] ----- stderr ----- "###); From ca6c8b3c782967948279e8d063d3ccffc64115b8 Mon Sep 17 00:00:00 2001 From: InSync Date: Wed, 11 Jun 2025 17:09:07 +0000 Subject: [PATCH 10/12] Fix `[BIN]` --- crates/uv/tests/it/common/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/uv/tests/it/common/mod.rs b/crates/uv/tests/it/common/mod.rs index bee073135..832aa255b 100644 --- a/crates/uv/tests/it/common/mod.rs +++ b/crates/uv/tests/it/common/mod.rs @@ -219,7 +219,7 @@ impl TestContext { #[must_use] pub fn with_filtered_virtualenv_bin(mut self) -> Self { self.filters.push(( - format!(r"[\\/]{}", venv_bin_path(PathBuf::new()).to_string_lossy()), + format!(r"(?:\\{{1,2}}|/){}", venv_bin_path(PathBuf::new()).to_string_lossy()), "/[BIN]".to_string(), )); self From b6f4b167d95479b94cbea01f042aeaacec6470fa Mon Sep 17 00:00:00 2001 From: InSync Date: Thu, 12 Jun 2025 14:10:56 +0000 Subject: [PATCH 11/12] Change entrypoint paths to use double backslashes on Windows --- crates/uv/src/commands/tool/list.rs | 14 +++++++++++--- crates/uv/tests/it/common/mod.rs | 5 ++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/crates/uv/src/commands/tool/list.rs b/crates/uv/src/commands/tool/list.rs index 27613732b..90eb48d5a 100644 --- a/crates/uv/src/commands/tool/list.rs +++ b/crates/uv/src/commands/tool/list.rs @@ -289,9 +289,17 @@ async fn list_json(cache: &Cache, printer: Printer) -> Result { let entrypoints = tool .entrypoints() .iter() - .map(|entrypoint| Entrypoint { - name: entrypoint.name.to_string(), - path: entrypoint.install_path.display().to_string(), + .map(|entrypoint| { + let name = entrypoint.name.to_string(); + let path = entrypoint.install_path.display().to_string(); + + let path = if cfg!(windows) { + path.replace('/', "\\") + } else { + path + }; + + Entrypoint { name, path } }) .collect::>(); diff --git a/crates/uv/tests/it/common/mod.rs b/crates/uv/tests/it/common/mod.rs index 832aa255b..378f2a1d0 100644 --- a/crates/uv/tests/it/common/mod.rs +++ b/crates/uv/tests/it/common/mod.rs @@ -219,7 +219,10 @@ impl TestContext { #[must_use] pub fn with_filtered_virtualenv_bin(mut self) -> Self { self.filters.push(( - format!(r"(?:\\{{1,2}}|/){}", venv_bin_path(PathBuf::new()).to_string_lossy()), + format!( + r"(?:\\{{1,2}}|/){}", + venv_bin_path(PathBuf::new()).to_string_lossy() + ), "/[BIN]".to_string(), )); self From 2b786d1b364655224c7848ca80a5b4483d339cb6 Mon Sep 17 00:00:00 2001 From: InSync Date: Thu, 12 Jun 2025 14:32:35 +0000 Subject: [PATCH 12/12] Fix --- crates/uv/tests/it/tool_list.rs | 35 ++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/crates/uv/tests/it/tool_list.rs b/crates/uv/tests/it/tool_list.rs index ad075f6e6..a2895c754 100644 --- a/crates/uv/tests/it/tool_list.rs +++ b/crates/uv/tests/it/tool_list.rs @@ -566,9 +566,7 @@ fn tool_list_show_extras() { #[test] fn tool_list_output_format_json() { - let context = TestContext::new("3.12") - .with_filtered_exe_suffix() - .with_filtered_virtualenv_bin(); + 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"); @@ -592,14 +590,27 @@ fn tool_list_output_format_json() { .assert() .success(); - uv_snapshot!(context.filters(), context.tool_list().arg("--output-format=json") - .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 ----- - [{"name":"black","version":"24.2.0","version_specifiers":["==24.2.0"],"extra_requirements":[],"with_requirements":[],"directory":"[TEMP_DIR]/tools/black","environment":{"python":"[TEMP_DIR]/tools/black/[BIN]/python3","version":"3.12.[X]"},"entrypoints":[{"name":"black","path":"[TEMP_DIR]/[BIN]/black"},{"name":"blackd","path":"[TEMP_DIR]/[BIN]/blackd"}]},{"name":"flask","version":"3.0.2","version_specifiers":[],"extra_requirements":["async","dotenv"],"with_requirements":["requests"],"directory":"[TEMP_DIR]/tools/flask","environment":{"python":"[TEMP_DIR]/tools/flask/[BIN]/python3","version":"3.12.[X]"},"entrypoints":[{"name":"flask","path":"[TEMP_DIR]/[BIN]/flask"}]}] + if cfg!(windows) { + uv_snapshot!(context.filters(), context.tool_list().arg("--output-format=json") + .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 ----- + [{"name":"black","version":"24.2.0","version_specifiers":["==24.2.0"],"extra_requirements":[],"with_requirements":[],"directory":"[TEMP_DIR]/tools/black","environment":{"python":"[TEMP_DIR]/tools/black/Scripts/python","version":"3.12.[X]"},"entrypoints":[{"name":"black","path":"[TEMP_DIR]/bin/black"},{"name":"blackd","path":"[TEMP_DIR]/bin/blackd"}]},{"name":"flask","version":"3.0.2","version_specifiers":[],"extra_requirements":["async","dotenv"],"with_requirements":["requests"],"directory":"[TEMP_DIR]/tools/flask","environment":{"python":"[TEMP_DIR]/tools/flask/Scripts/python","version":"3.12.[X]"},"entrypoints":[{"name":"flask","path":"[TEMP_DIR]/bin/flask"}]}] - ----- stderr ----- - "###); + ----- stderr ----- + "###); + } else { + uv_snapshot!(context.filters(), context.tool_list().arg("--output-format=json") + .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 ----- + [{"name":"black","version":"24.2.0","version_specifiers":["==24.2.0"],"extra_requirements":[],"with_requirements":[],"directory":"[TEMP_DIR]/tools/black","environment":{"python":"[TEMP_DIR]/tools/black/bin/python3","version":"3.12.[X]"},"entrypoints":[{"name":"black","path":"[TEMP_DIR]/bin/black"},{"name":"blackd","path":"[TEMP_DIR]/bin/blackd"}]},{"name":"flask","version":"3.0.2","version_specifiers":[],"extra_requirements":["async","dotenv"],"with_requirements":["requests"],"directory":"[TEMP_DIR]/tools/flask","environment":{"python":"[TEMP_DIR]/tools/flask/bin/python3","version":"3.12.[X]"},"entrypoints":[{"name":"flask","path":"[TEMP_DIR]/bin/flask"}]}] + + ----- stderr ----- + "###); + } }