Skip to content

Commit

Permalink
Respect relative paths in uv build sources (#8237)
Browse files Browse the repository at this point in the history
## Summary

Right now, `uv build` will fail if a package depends on a local source
in `build-system.requires`.
  • Loading branch information
charliermarsh authored Oct 16, 2024
1 parent b4dca66 commit 999b3f0
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 3 deletions.
9 changes: 7 additions & 2 deletions crates/uv-build-frontend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ impl SourceBuild {
pub async fn setup(
source: &Path,
subdirectory: Option<&Path>,
install_path: &Path,
fallback_package_name: Option<&PackageName>,
fallback_package_version: Option<&Version>,
interpreter: &Interpreter,
Expand Down Expand Up @@ -273,6 +274,7 @@ impl SourceBuild {
// Check if we have a PEP 517 build backend.
let (pep517_backend, project) = Self::extract_pep517_backend(
&source_tree,
install_path,
fallback_package_name,
locations,
source_strategy,
Expand Down Expand Up @@ -368,6 +370,7 @@ impl SourceBuild {
create_pep517_build_environment(
&runner,
&source_tree,
install_path,
&venv,
&pep517_backend,
build_context,
Expand Down Expand Up @@ -436,6 +439,7 @@ impl SourceBuild {
/// Extract the PEP 517 backend from the `pyproject.toml` or `setup.py` file.
async fn extract_pep517_backend(
source_tree: &Path,
install_path: &Path,
package_name: Option<&PackageName>,
locations: &IndexLocations,
source_strategy: SourceStrategy,
Expand Down Expand Up @@ -469,7 +473,7 @@ impl SourceBuild {
};
let requires_dist = RequiresDist::from_project_maybe_workspace(
requires_dist,
source_tree,
install_path,
locations,
source_strategy,
LowerBound::Allow,
Expand Down Expand Up @@ -803,6 +807,7 @@ fn escape_path_for_python(path: &Path) -> String {
async fn create_pep517_build_environment(
runner: &PythonRunner,
source_tree: &Path,
install_path: &Path,
venv: &PythonEnvironment,
pep517_backend: &Pep517Backend,
build_context: &impl BuildContext,
Expand Down Expand Up @@ -921,7 +926,7 @@ async fn create_pep517_build_environment(
};
let requires_dist = RequiresDist::from_project_maybe_workspace(
requires_dist,
source_tree,
install_path,
locations,
source_strategy,
LowerBound::Allow,
Expand Down
2 changes: 2 additions & 0 deletions crates/uv-dispatch/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ impl<'a> BuildContext for BuildDispatch<'a> {
&'data self,
source: &'data Path,
subdirectory: Option<&'data Path>,
install_path: &'data Path,
version_id: Option<String>,
dist: Option<&'data SourceDist>,
sources: SourceStrategy,
Expand Down Expand Up @@ -352,6 +353,7 @@ impl<'a> BuildContext for BuildDispatch<'a> {
let builder = SourceBuild::setup(
source,
subdirectory,
install_path,
dist_name,
dist_version,
self.interpreter,
Expand Down
2 changes: 2 additions & 0 deletions crates/uv-distribution/src/source/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1712,6 +1712,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
.setup_build(
source_root,
subdirectory,
source_root,
Some(source.to_string()),
source.as_dist(),
source_strategy,
Expand Down Expand Up @@ -1756,6 +1757,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
.setup_build(
source_root,
subdirectory,
source_root,
Some(source.to_string()),
source.as_dist(),
source_strategy,
Expand Down
1 change: 1 addition & 0 deletions crates/uv-types/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ pub trait BuildContext {
&'a self,
source: &'a Path,
subdirectory: Option<&'a Path>,
install_path: &'a Path,
version_id: Option<String>,
dist: Option<&'a SourceDist>,
sources: SourceStrategy,
Expand Down
9 changes: 8 additions & 1 deletion crates/uv/src/commands/build_frontend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -535,9 +535,9 @@ async fn build_package(
};

// Prepare some common arguments for the build.
let dist = None;
let subdirectory = None;
let version_id = source.path().file_name().and_then(|name| name.to_str());
let dist = None;

let build_output = match printer {
Printer::Default | Printer::NoProgress | Printer::Verbose => {
Expand All @@ -563,6 +563,7 @@ async fn build_package(
.setup_build(
source.path(),
subdirectory,
source.path(),
version_id.map(ToString::to_string),
dist,
sources,
Expand Down Expand Up @@ -601,6 +602,7 @@ async fn build_package(
.setup_build(
&extracted,
subdirectory,
source.path(),
version_id.map(ToString::to_string),
dist,
sources,
Expand All @@ -623,6 +625,7 @@ async fn build_package(
.setup_build(
source.path(),
subdirectory,
source.path(),
version_id.map(ToString::to_string),
dist,
sources,
Expand All @@ -645,6 +648,7 @@ async fn build_package(
.setup_build(
source.path(),
subdirectory,
source.path(),
version_id.map(ToString::to_string),
dist,
sources,
Expand All @@ -666,6 +670,7 @@ async fn build_package(
.setup_build(
source.path(),
subdirectory,
source.path(),
version_id.map(ToString::to_string),
dist,
sources,
Expand All @@ -684,6 +689,7 @@ async fn build_package(
.setup_build(
source.path(),
subdirectory,
source.path(),
version_id.map(ToString::to_string),
dist,
sources,
Expand Down Expand Up @@ -724,6 +730,7 @@ async fn build_package(
.setup_build(
&extracted,
subdirectory,
source.path(),
version_id.map(ToString::to_string),
dist,
sources,
Expand Down
154 changes: 154 additions & 0 deletions crates/uv/tests/it/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::common::{uv_snapshot, TestContext};
use anyhow::Result;
use assert_fs::prelude::*;
use fs_err::File;
use indoc::indoc;
use insta::assert_snapshot;
use predicates::prelude::predicate;
use zip::ZipArchive;
Expand Down Expand Up @@ -1766,6 +1767,159 @@ fn build_no_build_logs() -> Result<()> {
Ok(())
}

#[test]
fn tool_uv_sources() -> Result<()> {
let context = TestContext::new("3.12");
let filters = context
.filters()
.into_iter()
.chain([
(r"exit code: 1", "exit status: 1"),
(r"bdist\.[^/\\\s]+-[^/\\\s]+", "bdist.linux-x86_64"),
(r"\\\.", ""),
])
.collect::<Vec<_>>();

let build = context.temp_dir.child("backend");
build.child("pyproject.toml").write_str(
r#"
[project]
name = "backend"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["typing-extensions>=3.10"]
[build-system]
requires = ["setuptools>=42"]
build-backend = "setuptools.build_meta"
"#,
)?;

build
.child("src")
.child("backend")
.child("__init__.py")
.write_str(indoc! { r#"
def hello() -> str:
return "Hello, world!"
"#})?;
build.child("README.md").touch()?;

let project = context.temp_dir.child("project");

project.child("pyproject.toml").write_str(
r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["iniconfig>1"]
[build-system]
requires = ["setuptools>=42", "backend==0.1.0"]
build-backend = "setuptools.build_meta"
[tool.uv.sources]
backend = { path = "../backend" }
"#,
)?;

project.child("setup.py").write_str(indoc! {r"
from setuptools import setup
from backend import hello
hello()
setup()
",
})?;

uv_snapshot!(filters, context.build().current_dir(project.path()), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Building source distribution...
running egg_info
creating project.egg-info
writing project.egg-info/PKG-INFO
writing dependency_links to project.egg-info/dependency_links.txt
writing requirements to project.egg-info/requires.txt
writing top-level names to project.egg-info/top_level.txt
writing manifest file 'project.egg-info/SOURCES.txt'
reading manifest file 'project.egg-info/SOURCES.txt'
writing manifest file 'project.egg-info/SOURCES.txt'
running sdist
running egg_info
writing project.egg-info/PKG-INFO
writing dependency_links to project.egg-info/dependency_links.txt
writing requirements to project.egg-info/requires.txt
writing top-level names to project.egg-info/top_level.txt
reading manifest file 'project.egg-info/SOURCES.txt'
writing manifest file 'project.egg-info/SOURCES.txt'
warning: sdist: standard file not found: should have one of README, README.rst, README.txt, README.md
running check
creating project-0.1.0
creating project-0.1.0/project.egg-info
copying files to project-0.1.0...
copying pyproject.toml -> project-0.1.0
copying setup.py -> project-0.1.0
copying project.egg-info/PKG-INFO -> project-0.1.0/project.egg-info
copying project.egg-info/SOURCES.txt -> project-0.1.0/project.egg-info
copying project.egg-info/dependency_links.txt -> project-0.1.0/project.egg-info
copying project.egg-info/requires.txt -> project-0.1.0/project.egg-info
copying project.egg-info/top_level.txt -> project-0.1.0/project.egg-info
copying project.egg-info/SOURCES.txt -> project-0.1.0/project.egg-info
Writing project-0.1.0/setup.cfg
Creating tar archive
removing 'project-0.1.0' (and everything under it)
Building wheel from source distribution...
running egg_info
writing project.egg-info/PKG-INFO
writing dependency_links to project.egg-info/dependency_links.txt
writing requirements to project.egg-info/requires.txt
writing top-level names to project.egg-info/top_level.txt
reading manifest file 'project.egg-info/SOURCES.txt'
writing manifest file 'project.egg-info/SOURCES.txt'
running bdist_wheel
running build
installing to build/bdist.linux-x86_64/wheel
running install
running install_egg_info
running egg_info
writing project.egg-info/PKG-INFO
writing dependency_links to project.egg-info/dependency_links.txt
writing requirements to project.egg-info/requires.txt
writing top-level names to project.egg-info/top_level.txt
reading manifest file 'project.egg-info/SOURCES.txt'
writing manifest file 'project.egg-info/SOURCES.txt'
Copying project.egg-info to build/bdist.linux-x86_64/wheel/project-0.1.0-py3.12.egg-info
running install_scripts
creating build/bdist.linux-x86_64/wheel/project-0.1.0.dist-info/WHEEL
creating '[TEMP_DIR]/project/dist/[TMP]/wheel' to it
adding 'project-0.1.0.dist-info/METADATA'
adding 'project-0.1.0.dist-info/WHEEL'
adding 'project-0.1.0.dist-info/top_level.txt'
adding 'project-0.1.0.dist-info/RECORD'
removing build/bdist.linux-x86_64/wheel
Successfully built dist/project-0.1.0.tar.gz and dist/project-0.1.0-py3-none-any.whl
"###);

project
.child("dist")
.child("project-0.1.0.tar.gz")
.assert(predicate::path::is_file());
project
.child("dist")
.child("project-0.1.0-py3-none-any.whl")
.assert(predicate::path::is_file());

Ok(())
}

/// Check that we have a working git boundary for builds from source dist to wheel in `dist/`.
#[test]
fn git_boundary_in_dist_build() -> Result<()> {
Expand Down

0 comments on commit 999b3f0

Please sign in to comment.