From e9f309736d88438c947855d87c47fd4800bd8026 Mon Sep 17 00:00:00 2001 From: messense Date: Sat, 11 Jan 2025 11:41:57 +0800 Subject: [PATCH 1/2] Use `uv` automatically when running `maturin develop` inside a uv-created venv --- src/develop.rs | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/src/develop.rs b/src/develop.rs index 2f500eb45..9e09770b9 100644 --- a/src/develop.rs +++ b/src/develop.rs @@ -162,6 +162,18 @@ fn find_uv_python(python_path: &Path) -> Result<(PathBuf, Vec<&'static str>)> { } } +/// Check if a virtualenv is created by uv by reading pyvenv.cfg +fn is_uv_venv(venv_dir: &Path) -> bool { + let pyvenv_cfg = venv_dir.join("pyvenv.cfg"); + if !pyvenv_cfg.exists() { + return false; + } + match fs::read_to_string(&pyvenv_cfg) { + Ok(content) => content.contains("\nuv = "), + Err(_) => false, + } +} + /// Install the crate as module in the current virtualenv #[derive(Debug, clap::Parser)] pub struct DevelopOptions { @@ -312,7 +324,7 @@ fn configure_as_editable( python: &Path, install_backend: &InstallBackend, ) -> Result<()> { - println!("✏️ Setting installed package as editable"); + println!("✏️ Setting installed package as editable"); install_backend.check_supports_show_files(python)?; let mut cmd = install_backend.make_command(python); let cmd = cmd.args(["show", "--files", &build_context.metadata24.name]); @@ -418,10 +430,24 @@ pub fn develop(develop_options: DevelopOptions, venv_dir: &Path) -> Result<()> { || anyhow!("Expected `python` to be a python interpreter inside a virtualenv ಠ_ಠ"), )?; - let install_backend = if uv { - let (uv_path, uv_args) = find_uv_python(&interpreter.executable) - .or_else(|_| find_uv_bin()) - .context("Failed to find uv")?; + let uv_venv = is_uv_venv(venv_dir); + let uv_info = if uv || uv_venv { + match find_uv_python(&interpreter.executable).or_else(|_| find_uv_bin()) { + Ok(uv_info) => Some(Ok(uv_info)), + Err(e) => { + if uv { + Some(Err(e)) + } else { + // Ignore error and try pip instead if it's a uv venv but `--uv` is not specified + None + } + } + } + } else { + None + }; + let install_backend = if let Some(uv_info) = uv_info { + let (uv_path, uv_args) = uv_info?; InstallBackend::Uv { path: uv_path, args: uv_args, From f4bcfa3eba2883d8bb62bee4da5de85078a221fe Mon Sep 17 00:00:00 2001 From: messense Date: Sat, 11 Jan 2025 12:28:32 +0800 Subject: [PATCH 2/2] Pass `VIRTUAL_ENV` to `pip install`/`uv pip install` --- src/develop.rs | 53 ++++++++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/src/develop.rs b/src/develop.rs index 9e09770b9..8f441f39b 100644 --- a/src/develop.rs +++ b/src/develop.rs @@ -125,24 +125,6 @@ fn find_uv_bin() -> Result<(PathBuf, Vec<&'static str>)> { } } -fn check_pip_exists(python_path: &Path, pip_path: Option<&PathBuf>) -> Result<()> { - let output = if let Some(pip_path) = pip_path { - Command::new(pip_path).args(["--version"]).output()? - } else { - Command::new(python_path) - .args(["-m", "pip", "--version"]) - .output()? - }; - if output.status.success() { - let version_str = - str::from_utf8(&output.stdout).context("`pip --version` didn't return utf8 output")?; - debug!(version = %version_str, "Found pip"); - Ok(()) - } else { - bail!("`pip --version` failed with status: {}", output.status); - } -} - /// Detect the Python uv package fn find_uv_python(python_path: &Path) -> Result<(PathBuf, Vec<&'static str>)> { let output = Command::new(python_path) @@ -162,6 +144,24 @@ fn find_uv_python(python_path: &Path) -> Result<(PathBuf, Vec<&'static str>)> { } } +fn check_pip_exists(python_path: &Path, pip_path: Option<&PathBuf>) -> Result<()> { + let output = if let Some(pip_path) = pip_path { + Command::new(pip_path).args(["--version"]).output()? + } else { + Command::new(python_path) + .args(["-m", "pip", "--version"]) + .output()? + }; + if output.status.success() { + let version_str = + str::from_utf8(&output.stdout).context("`pip --version` didn't return utf8 output")?; + debug!(version = %version_str, "Found pip"); + Ok(()) + } else { + bail!("`pip --version` failed with status: {}", output.status); + } +} + /// Check if a virtualenv is created by uv by reading pyvenv.cfg fn is_uv_venv(venv_dir: &Path) -> bool { let pyvenv_cfg = venv_dir.join("pyvenv.cfg"); @@ -224,7 +224,8 @@ pub struct DevelopOptions { fn install_dependencies( build_context: &BuildContext, extras: &[String], - interpreter: &PythonInterpreter, + python: &Path, + venv_dir: &Path, install_backend: &InstallBackend, ) -> Result<()> { if !build_context.metadata24.requires_dist.is_empty() { @@ -256,12 +257,17 @@ fn install_dependencies( pkg.to_string() })); let status = install_backend - .make_command(&interpreter.executable) + .make_command(python) .args(&args) + .env("VIRTUAL_ENV", venv_dir) .status() - .context("Failed to run pip install")?; + .with_context(|| format!("Failed to run {} install", install_backend.name()))?; if !status.success() { - bail!(r#"pip install finished with "{}""#, status) + bail!( + r#"{} install finished with "{}""#, + install_backend.name(), + status + ) } } Ok(()) @@ -279,6 +285,7 @@ fn install_wheel( let output = cmd .args(["install", "--no-deps", "--force-reinstall"]) .arg(dunce::simplified(wheel_filename)) + .env("VIRTUAL_ENV", venv_dir) .output() .context(format!( "{} install failed (ran {:?} with {:?})", @@ -460,7 +467,7 @@ pub fn develop(develop_options: DevelopOptions, venv_dir: &Path) -> Result<()> { } }; - install_dependencies(&build_context, &extras, &interpreter, &install_backend)?; + install_dependencies(&build_context, &extras, &python, venv_dir, &install_backend)?; let wheels = build_context.build_wheels()?; if !skip_install {