1
0
mirror of https://github.com/j178/prek.git synced 2026-04-03 17:34:03 +02:00

Try default uv managed python first, fallback to download (#291)

* .

* Try default uv managed python first, fallback to download

* Fix
This commit is contained in:
Jo
2025-08-01 12:07:33 +08:00
committed by GitHub
parent c935594e56
commit c28ca26c47
4 changed files with 100 additions and 24 deletions

View File

@@ -93,7 +93,7 @@ jobs:
uses: astral-sh/setup-uv@v6
- name: "Install Python"
run: uv python install
run: uv python install --no-bin
- name: "Cargo test"
run: |
@@ -125,7 +125,7 @@ jobs:
uses: astral-sh/setup-uv@v6
- name: "Install Python"
run: uv python install
run: uv python install --no-bin
- name: "Cargo test"
run: |
@@ -160,7 +160,7 @@ jobs:
cache-local-path: ${{ env.DEV_DRIVE }}/uv-cache
- name: "Install Python"
run: uv python install
run: uv python install --no-bin
- name: "Cargo test"
run: |

View File

@@ -25,7 +25,6 @@ impl EnvVars {
// Other environment variables
pub const UV_NO_CACHE: &'static str = "UV_NO_CACHE";
pub const UV_PYTHON_INSTALL_DIR: &'static str = "UV_PYTHON_INSTALL_DIR";
pub const UV_PYTHON_DOWNLOADS: &'static str = "UV_PYTHON_DOWNLOADS";
}
impl EnvVars {

View File

@@ -16,6 +16,7 @@ use crate::store::{Store, ToolBucket};
use crate::languages::python::PythonRequest;
use crate::languages::version::LanguageRequest;
use crate::process;
use constants::env_vars::EnvVars;
#[derive(Debug, Copy, Clone)]
@@ -51,23 +52,9 @@ impl LanguageImpl for Python {
};
// Create venv (auto download Python if needed)
let mut cmd = uv.cmd("create venv");
cmd.arg("venv")
.arg(&info.env_path)
.arg("--python-preference")
.arg("managed")
.arg("--no-project")
.arg("--no-config")
.env(EnvVars::UV_PYTHON_DOWNLOADS, "true")
.env(
EnvVars::UV_PYTHON_INSTALL_DIR,
store.tools_path(ToolBucket::Python),
);
if let Some(python) = python_request {
cmd.arg("--python").arg(python);
}
cmd.check(true).output().await?;
Self::create_venv_with_retry(&uv, store, &info, python_request.as_ref())
.await
.context("Failed to create Python virtual environment")?;
// Install dependencies
if let Some(repo_path) = hook.repo_path() {
@@ -189,6 +176,96 @@ impl LanguageImpl for Python {
}
}
impl Python {
async fn create_venv_with_retry(
uv: &Uv,
store: &Store,
info: &InstallInfo,
python_request: Option<&String>,
) -> Result<(), Error> {
// Try creating venv without downloads first
match Self::create_venv_command(uv, store, info, python_request, false, false)
.check(true)
.output()
.await
{
Ok(_) => {
debug!("Venv created successfully with no downloads");
Ok(())
}
Err(e @ process::Error::Status { .. }) => {
// Check if we can retry with downloads
if Self::can_retry_with_downloads(&e) {
debug!("Retrying venv creation with managed Python downloads");
Self::create_venv_command(uv, store, info, python_request, true, true)
.check(true)
.output()
.await?;
return Ok(());
}
// If we can't retry, return the original error
Err(e.into())
}
Err(e) => {
debug!("Failed to create venv: {}", e);
Err(e.into())
}
}
}
fn create_venv_command(
uv: &Uv,
store: &Store,
info: &InstallInfo,
python_request: Option<&String>,
set_install_dir: bool,
allow_downloads: bool,
) -> Cmd {
let mut cmd = uv.cmd("create venv");
cmd.arg("venv")
.arg(&info.env_path)
.arg("--python-preference")
.arg("managed")
.arg("--no-project")
.arg("--no-config");
if set_install_dir {
cmd.env(
EnvVars::UV_PYTHON_INSTALL_DIR,
store.tools_path(ToolBucket::Python),
);
}
if allow_downloads {
cmd.arg("--allow-python-downloads");
} else {
cmd.arg("--no-python-downloads");
}
if let Some(python) = python_request {
cmd.arg("--python").arg(python);
}
cmd
}
fn can_retry_with_downloads(error: &process::Error) -> bool {
let process::Error::Status {
error:
process::StatusError {
output: Some(output),
..
},
..
} = error
else {
return false;
};
let stderr = String::from_utf8_lossy(&output.stderr);
stderr.contains("A managed Python download is available")
}
}
fn bin_dir(venv: &Path) -> PathBuf {
if cfg!(windows) {
venv.join("Scripts")

View File

@@ -4,8 +4,7 @@ use assert_fs::fixture::PathChild;
use crate::common::{TestContext, cmd_snapshot};
/// Test `language_version` parsing.
/// Python 3.12.11 and 3.13.5 are installed in the CI environment, when running tests uv can find them
/// as system Python.
/// Python 3.12.11 and 3.13.5 are installed in the CI environment, when running tests uv can find them.
/// Other versions may need to be downloaded while running the tests.
#[test]
fn language_version() -> anyhow::Result<()> {
@@ -144,7 +143,8 @@ fn can_not_download() {
----- stdout -----
----- stderr -----
error: command `create venv` exited with an error:
error: Failed to create Python virtual environment
caused by: command `create venv` exited with an error:
[status]
exit status: 2