From f2ff218621f7105fe06d68d8dfe8e3d27a19a130 Mon Sep 17 00:00:00 2001 From: Ahmed Ilyas Date: Fri, 14 Mar 2025 02:27:51 +0100 Subject: [PATCH] build-backend: Allow overriding module names for editable builds (#12137) ## Summary This PR enables module name overrides for editable installs. Builds upon https://github.com/astral-sh/uv/pull/11884. The `tool.uv.build-backend.module-name` option is now respected during editable build processes. ## Test Plan Added a test. --------- Co-authored-by: Charlie Marsh --- crates/uv-build-backend/src/wheel.rs | 12 +++++- crates/uv/tests/it/build_backend.rs | 63 ++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/crates/uv-build-backend/src/wheel.rs b/crates/uv-build-backend/src/wheel.rs index f14cdc526..cdfcbb4d8 100644 --- a/crates/uv-build-backend/src/wheel.rs +++ b/crates/uv-build-backend/src/wheel.rs @@ -282,7 +282,17 @@ pub fn build_editable( return Err(Error::AbsoluteModuleRoot(settings.module_root.clone())); } let src_root = source_tree.join(settings.module_root); - let module_root = src_root.join(pyproject_toml.name().as_dist_info_name().as_ref()); + + let module_name = if let Some(module_name) = settings.module_name { + module_name + } else { + // Should never error, the rules for package names (in dist-info formatting) are stricter + // than those for identifiers + Identifier::from_str(pyproject_toml.name().as_dist_info_name().as_ref())? + }; + debug!("Module name: `{:?}`", module_name); + + let module_root = src_root.join(module_name.as_ref()); if !module_root.join("__init__.py").is_file() { return Err(Error::MissingModule(module_root)); } diff --git a/crates/uv/tests/it/build_backend.rs b/crates/uv/tests/it/build_backend.rs index 731bcdfaf..d5e455c3e 100644 --- a/crates/uv/tests/it/build_backend.rs +++ b/crates/uv/tests/it/build_backend.rs @@ -368,3 +368,66 @@ fn rename_module() -> Result<()> { Ok(()) } + +/// Test `tool.uv.build-backend.module-name` for editable builds. +#[test] +fn rename_module_editable_build() -> Result<()> { + let context = TestContext::new("3.12"); + let temp_dir = TempDir::new()?; + + context + .temp_dir + .child("pyproject.toml") + .write_str(indoc! {r#" + [project] + name = "foo" + version = "1.0.0" + + [tool.uv.build-backend] + module-name = "bar" + + [build-system] + requires = ["uv_build>=0.5,<0.7"] + build-backend = "uv_build" + "#})?; + + context + .temp_dir + .child("src/bar/__init__.py") + .write_str(r#"print("Hi from bar")"#)?; + + uv_snapshot!(context + .build_backend() + .arg("build-editable") + .arg(temp_dir.path()) + .env("UV_PREVIEW", "1"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + foo-1.0.0-py3-none-any.whl + + ----- stderr ----- + "###); + + context + .pip_install() + .arg(temp_dir.path().join("foo-1.0.0-py3-none-any.whl")) + .assert() + .success(); + + // Importing the module with the `module-name` name succeeds. + uv_snapshot!(Command::new(context.interpreter()) + .arg("-c") + .arg("import bar") + // Python on windows + .env(EnvVars::PYTHONUTF8, "1"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + Hi from bar + + ----- stderr ----- + "###); + + Ok(()) +}