Add --show-version to uv python find (#12376)

@jtfmumm mentioned a desire for this. I'm not sure how we should do
this. I kind of want to change this to something like...

```
$ uv python find
CPython 3.13 @ <path>
$ uv python find --only-path
<path>
$ uv python find --short
<path>
$ uv python find --only-version 
3.13
```

The change in defaults would be breaking though.
This commit is contained in:
Zanie Blue 2025-04-03 08:34:45 -05:00 committed by GitHub
parent a6c621d4a5
commit be3d5dfa84
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 90 additions and 21 deletions

View file

@ -4785,6 +4785,10 @@ pub struct PythonFindArgs {
conflicts_with = "no_system"
)]
pub script: Option<PathBuf>,
/// Show the Python version that would be used instead of the path to the interpreter.
#[arg(long)]
pub show_version: bool,
}
#[derive(Args)]

View file

@ -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<String>,
show_version: bool,
no_project: bool,
no_config: bool,
system: bool,
python_preference: PythonPreference,
cache: &Cache,
printer: Printer,
) -> Result<ExitStatus> {
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<ExitStatus> {
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)
}

View file

@ -1340,6 +1340,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
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<ExitStatus> {
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
}

View file

@ -972,6 +972,7 @@ impl PythonUninstallSettings {
#[derive(Debug, Clone)]
pub(crate) struct PythonFindSettings {
pub(crate) request: Option<String>,
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<FilesystemOptions>) -> 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(),
}

View file

@ -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 -----
");
}

View file

@ -5096,6 +5096,8 @@ uv python find [OPTIONS] [REQUEST]
</dd><dt id="uv-python-find--script"><a href="#uv-python-find--script"><code>--script</code></a> <i>script</i></dt><dd><p>Find the environment for a Python script, rather than the current project</p>
</dd><dt id="uv-python-find--show-version"><a href="#uv-python-find--show-version"><code>--show-version</code></a></dt><dd><p>Show the Python version that would be used instead of the path to the interpreter</p>
</dd><dt id="uv-python-find--system"><a href="#uv-python-find--system"><code>--system</code></a></dt><dd><p>Only find system Python interpreters.</p>
<p>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.</p>