diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index 7ca64ca27..68d8a4d0d 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -4785,6 +4785,10 @@ pub struct PythonFindArgs { conflicts_with = "no_system" )] pub script: Option, + + /// Show the Python version that would be used instead of the path to the interpreter. + #[arg(long)] + pub show_version: bool, } #[derive(Args)] diff --git a/crates/uv/src/commands/python/find.rs b/crates/uv/src/commands/python/find.rs index 26e8e8a88..ce853c701 100644 --- a/crates/uv/src/commands/python/find.rs +++ b/crates/uv/src/commands/python/find.rs @@ -1,4 +1,3 @@ -use anstream::println; use anyhow::Result; use std::fmt::Write; use std::path::Path; @@ -21,14 +20,17 @@ use crate::printer::Printer; use crate::settings::NetworkSettings; /// Find a Python interpreter. +#[allow(clippy::fn_params_excessive_bools)] pub(crate) async fn find( project_dir: &Path, request: Option, + show_version: bool, no_project: bool, no_config: bool, system: bool, python_preference: PythonPreference, cache: &Cache, + printer: Printer, ) -> Result { let environment_preference = if system { EnvironmentPreference::OnlySystem @@ -88,16 +90,26 @@ pub(crate) async fn find( } }; - println!( - "{}", - std::path::absolute(python.interpreter().sys_executable())?.simplified_display() - ); + if show_version { + writeln!( + printer.stdout(), + "{}", + python.interpreter().python_version() + )?; + } else { + writeln!( + printer.stdout(), + "{}", + std::path::absolute(python.interpreter().sys_executable())?.simplified_display() + )?; + } Ok(ExitStatus::Success) } pub(crate) async fn find_script( script: Pep723ItemRef<'_>, + show_version: bool, network_settings: &NetworkSettings, python_preference: PythonPreference, python_downloads: PythonDownloads, @@ -105,7 +117,7 @@ pub(crate) async fn find_script( cache: &Cache, printer: Printer, ) -> Result { - match ScriptInterpreter::discover( + let interpreter = match ScriptInterpreter::discover( script, None, network_settings, @@ -121,22 +133,21 @@ pub(crate) async fn find_script( { Err(error) => { writeln!(printer.stderr(), "{error}")?; - - Ok(ExitStatus::Failure) + return Ok(ExitStatus::Failure); } + Ok(ScriptInterpreter::Interpreter(interpreter)) => interpreter, + Ok(ScriptInterpreter::Environment(environment)) => environment.into_interpreter(), + }; - Ok(ScriptInterpreter::Interpreter(interpreter)) => { - let path = interpreter.sys_executable(); - println!("{}", std::path::absolute(path)?.simplified_display()); - - Ok(ExitStatus::Success) - } - - Ok(ScriptInterpreter::Environment(environment)) => { - let path = environment.interpreter().sys_executable(); - println!("{}", std::path::absolute(path)?.simplified_display()); - - Ok(ExitStatus::Success) - } + if show_version { + writeln!(printer.stdout(), "{}", interpreter.python_version())?; + } else { + writeln!( + printer.stdout(), + "{}", + std::path::absolute(interpreter.sys_executable())?.simplified_display() + )?; } + + Ok(ExitStatus::Success) } diff --git a/crates/uv/src/lib.rs b/crates/uv/src/lib.rs index 6e654a160..651ef10c8 100644 --- a/crates/uv/src/lib.rs +++ b/crates/uv/src/lib.rs @@ -1340,6 +1340,7 @@ async fn run(mut cli: Cli) -> Result { if let Some(Pep723Item::Script(script)) = script { commands::python_find_script( Pep723ItemRef::Script(&script), + args.show_version, &globals.network_settings, globals.python_preference, globals.python_downloads, @@ -1352,11 +1353,13 @@ async fn run(mut cli: Cli) -> Result { commands::python_find( &project_dir, args.request, + args.show_version, args.no_project, cli.top_level.no_config, args.system, globals.python_preference, &cache, + printer, ) .await } diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs index 666beda8d..4a67a8bdc 100644 --- a/crates/uv/src/settings.rs +++ b/crates/uv/src/settings.rs @@ -972,6 +972,7 @@ impl PythonUninstallSettings { #[derive(Debug, Clone)] pub(crate) struct PythonFindSettings { pub(crate) request: Option, + pub(crate) show_version: bool, pub(crate) no_project: bool, pub(crate) system: bool, } @@ -982,6 +983,7 @@ impl PythonFindSettings { pub(crate) fn resolve(args: PythonFindArgs, _filesystem: Option) -> Self { let PythonFindArgs { request, + show_version, no_project, system, no_system, @@ -990,6 +992,7 @@ impl PythonFindSettings { Self { request, + show_version, no_project, system: flag(system, no_system).unwrap_or_default(), } diff --git a/crates/uv/tests/it/python_find.rs b/crates/uv/tests/it/python_find.rs index 6e74e9e8f..90fabed2c 100644 --- a/crates/uv/tests/it/python_find.rs +++ b/crates/uv/tests/it/python_find.rs @@ -844,3 +844,49 @@ fn python_find_script_no_such_version() { No interpreter found for Python >=3.14 in [PYTHON SOURCES] "); } + +#[test] +fn python_find_show_version() { + let context: TestContext = + TestContext::new_with_versions(&["3.11", "3.12"]).with_filtered_python_sources(); + + // No interpreters found + uv_snapshot!(context.filters(), context.python_find().env(EnvVars::UV_TEST_PYTHON_PATH, "").arg("--show-version"), @r" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + error: No interpreter found in [PYTHON SOURCES] + "); + + // Show the first version found + uv_snapshot!(context.filters(), context.python_find().arg("--show-version"), @r" + success: true + exit_code: 0 + ----- stdout ----- + 3.11.[X] + + ----- stderr ----- + "); + + // Request Python 3.12 + uv_snapshot!(context.filters(), context.python_find().arg("--show-version").arg("3.12"), @r" + success: true + exit_code: 0 + ----- stdout ----- + 3.12.[X] + + ----- stderr ----- + "); + + // Request Python 3.11 + uv_snapshot!(context.filters(), context.python_find().arg("--show-version").arg("3.11"), @r" + success: true + exit_code: 0 + ----- stdout ----- + 3.11.[X] + + ----- stderr ----- + "); +} diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 497b432ba..95f0ebde9 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -5096,6 +5096,8 @@ uv python find [OPTIONS] [REQUEST]
--script script

Find the environment for a Python script, rather than the current project

+
--show-version

Show the Python version that would be used instead of the path to the interpreter

+
--system

Only find system Python interpreters.

By default, uv will report the first Python interpreter it would use, including those in an active virtual environment or a virtual environment in the current working directory or any parent directory.