From 50997bcb41a0acc01265890691fe6a7e78d03427 Mon Sep 17 00:00:00 2001 From: Tim de Jager Date: Mon, 26 Aug 2024 16:41:27 +0200 Subject: [PATCH] Allow per dependency build isolation for setup.py projects as well (#6517) ## Summary This changes the behavior a bit of the per-dependency build-isolation override. That, if the dist name is known, it is passed into the `SourceBuild::Setup` function. This allows for this override to work for projects without a `pyproject.toml`, like `detectron2`, using the specified requirement name. Previously only the `pyproject.toml` name could be used, which these projects are lacking. An example of a use-case is given in the *Test Plan* section. Additionally, the `no_build_isolation_package` has been adding to `InstallerSettingsRef` and used in `sync` and other commands, as this was not done yet. This is useful if you want to **non**-isolate a single package, even ones without a proper `pyproject.toml` ## Test Plan With the following pyproject.toml. ```toml [project] name = "detectron-uv" version = "0.1.0" description = "Add your description here" readme = "README.md" requires-python = ">=3.12" dependencies = [ "detectron2", "setuptools", "torch", ] [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [tool.uv.sources] detectron2 = { git = "https://github.com/facebookresearch/detectron2", rev = "bcfd464d0c810f0442d91a349c0f6df945467143" } [tool.uv] no-build-isolation-package = ["detectron2"] ``` The package `detectron2` is now correctly **non**-isolated. Before, because the logic depended on getting the name from the `pyproject.toml`, which is lacking in detectron2 you would get the message, that the source could not be built. This was because it would still be *isolated* in that case. With these changes you can now install using (given that you are inside a workspace with a venv): ``` uv pip install torch setuptools uv sync ``` This would previously fail with something like: ``` error: Failed to prepare distributions Caused by: Failed to fetch wheel: detectron2 @ git+https://github.com/facebookresearch/detectron2@bcfd464d0c810f0442d91a349c0f6df945467143 Caused by: Build backend failed to determine extra requires with `build_wheel()` with exit status: 1 --- stdout: --- stderr: Traceback (most recent call last): File "", line 14, in File "/Users/tdejager/Library/Caches/uv/builds-v0/.tmptloDcZ/lib/python3.12/site-packages/setuptools/build_meta.py", line 332, in get_requires_for_build_wheel return self._get_build_requires(config_settings, requirements=[]) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/tdejager/Library/Caches/uv/builds-v0/.tmptloDcZ/lib/python3.12/site-packages/setuptools/build_meta.py", line 302, in _get_build_requires self.run_setup() File "/Users/tdejager/Library/Caches/uv/builds-v0/.tmptloDcZ/lib/python3.12/site-packages/setuptools/build_meta.py", line 502, in run_setup super().run_setup(setup_script=setup_script) File "/Users/tdejager/Library/Caches/uv/builds-v0/.tmptloDcZ/lib/python3.12/site-packages/setuptools/build_meta.py", line 318, in run_setup exec(code, locals()) File "", line 10, in ModuleNotFoundError: No module named 'torch' --- Caused by: This error likely indicates that detectron2 @ git+https://github.com/facebookresearch/detectron2@bcfd464d0c810f0442d91a349c0f6df945467143 depends on torch, but doesn't declare it as a build dependency. If detectron2 @ git+https://github.com/facebookresearch/detectron2@bcfd464d0c810f0442d91a349c0f6df945467143 is a first-party package, consider adding torch to its `build-system.requires`. Otherwise, `uv pip install torch` into the environment and re-run with `--no-build-isolation`. ``` **Edit**: Some wording, used isolated where it should be **non**-isolated. --- crates/uv-build/src/lib.rs | 9 +++++---- crates/uv-dev/src/build.rs | 1 + crates/uv-dispatch/src/lib.rs | 4 +++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/crates/uv-build/src/lib.rs b/crates/uv-build/src/lib.rs index 3c0f1b469a4b..479a4b35d5f8 100644 --- a/crates/uv-build/src/lib.rs +++ b/crates/uv-build/src/lib.rs @@ -398,6 +398,7 @@ impl SourceBuild { pub async fn setup( source: &Path, subdirectory: Option<&Path>, + fallback_package_name: Option<&PackageName>, interpreter: &Interpreter, build_context: &impl BuildContext, source_build_context: SourceBuildContext, @@ -422,10 +423,10 @@ impl SourceBuild { let (pep517_backend, project) = Self::extract_pep517_backend(&source_tree, &default_backend).map_err(|err| *err)?; - let package_name = project.clone().map(|p| p.name); + let package_name = project.as_ref().map(|p| &p.name).or(fallback_package_name); // Create a virtual environment, or install into the shared environment if requested. - let venv = if let Some(venv) = build_isolation.shared_environment(package_name.as_ref()) { + let venv = if let Some(venv) = build_isolation.shared_environment(package_name) { venv.clone() } else { uv_virtualenv::create_venv( @@ -440,7 +441,7 @@ impl SourceBuild { // Setup the build environment. If build isolation is disabled, we assume the build // environment is already setup. - if build_isolation.is_isolated(package_name.as_ref()) { + if build_isolation.is_isolated(package_name) { let resolved_requirements = Self::get_resolved_requirements( build_context, source_build_context, @@ -490,7 +491,7 @@ impl SourceBuild { // Create the PEP 517 build environment. If build isolation is disabled, we assume the build // environment is already setup. let runner = PythonRunner::new(concurrent_builds); - if build_isolation.is_isolated(package_name.as_ref()) { + if build_isolation.is_isolated(package_name) { create_pep517_build_environment( &runner, &source_tree, diff --git a/crates/uv-dev/src/build.rs b/crates/uv-dev/src/build.rs index 0b7a3584f7fb..8170c2080d93 100644 --- a/crates/uv-dev/src/build.rs +++ b/crates/uv-dev/src/build.rs @@ -98,6 +98,7 @@ pub(crate) async fn build(args: BuildArgs) -> Result { let builder = SourceBuild::setup( &args.sdist, args.subdirectory.as_deref(), + None, python.interpreter(), &build_dispatch, SourceBuildContext::default(), diff --git a/crates/uv-dispatch/src/lib.rs b/crates/uv-dispatch/src/lib.rs index 9b813452303c..4a95d4554653 100644 --- a/crates/uv-dispatch/src/lib.rs +++ b/crates/uv-dispatch/src/lib.rs @@ -298,11 +298,12 @@ impl<'a> BuildContext for BuildDispatch<'a> { dist: Option<&'data SourceDist>, build_kind: BuildKind, ) -> Result { + let dist_name = dist.map(distribution_types::Name::name); // Note we can only prevent builds by name for packages with names // unless all builds are disabled. if self .build_options - .no_build_requirement(dist.map(distribution_types::Name::name)) + .no_build_requirement(dist_name) // We always allow editable builds && !matches!(build_kind, BuildKind::Editable) { @@ -318,6 +319,7 @@ impl<'a> BuildContext for BuildDispatch<'a> { let builder = SourceBuild::setup( source, subdirectory, + dist_name, self.interpreter, self, self.source_build_context.clone(),