Skip to content

Commit

Permalink
Build backend: Add source tree -> source dist -> wheel tests
Browse files Browse the repository at this point in the history
  • Loading branch information
konstin committed Nov 14, 2024
1 parent 02a7bb4 commit c23023c
Show file tree
Hide file tree
Showing 19 changed files with 301 additions and 55 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

62 changes: 30 additions & 32 deletions crates/uv-build-backend/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,26 @@ fn test_wheel() {
#[test]
fn test_record() {
let record = vec![RecordEntry {
path: "uv_backend/__init__.py".to_string(),
path: "built_by_uv/__init__.py".to_string(),
hash: "89f869e53a3a0061a52c0233e6442d4d72de80a8a2d3406d9ea0bfd397ed7865".to_string(),
size: 37,
}];

let mut writer = Vec::new();
write_record(&mut writer, "uv_backend-0.1.0", record).unwrap();
write_record(&mut writer, "built_by_uv-0.1.0", record).unwrap();
assert_snapshot!(String::from_utf8(writer).unwrap(), @r"
uv_backend/__init__.py,sha256=89f869e53a3a0061a52c0233e6442d4d72de80a8a2d3406d9ea0bfd397ed7865,37
uv_backend-0.1.0/RECORD,,
built_by_uv/__init__.py,sha256=89f869e53a3a0061a52c0233e6442d4d72de80a8a2d3406d9ea0bfd397ed7865,37
built_by_uv-0.1.0/RECORD,,
");
}

/// Check that we write deterministic wheels.
#[test]
fn test_determinism() {
let temp1 = TempDir::new().unwrap();
let uv_backend = Path::new("../../scripts/packages/uv_backend");
let built_by_uv = Path::new("../../scripts/packages/built-by-uv");
build_wheel(
uv_backend,
built_by_uv,
temp1.path(),
None,
WheelSettings::default(),
Expand All @@ -57,22 +57,22 @@ fn test_determinism() {

// Touch the file to check that we don't serialize the last modified date.
fs_err::write(
uv_backend.join("src/uv_backend/__init__.py"),
built_by_uv.join("src/built_by_uv/__init__.py"),
"def greet():\n print(\"Hello 👋\")\n",
)
.unwrap();

let temp2 = TempDir::new().unwrap();
build_wheel(
uv_backend,
built_by_uv,
temp2.path(),
None,
WheelSettings::default(),
"1.0.0+test",
)
.unwrap();

let wheel_filename = "uv_backend-0.1.0-py3-none-any.whl";
let wheel_filename = "built_by_uv-0.1.0-py3-none-any.whl";
assert_eq!(
fs_err::read(temp1.path().join(wheel_filename)).unwrap(),
fs_err::read(temp2.path().join(wheel_filename)).unwrap()
Expand All @@ -83,8 +83,8 @@ fn test_determinism() {
#[test]
fn test_prepare_metadata() {
let metadata_dir = TempDir::new().unwrap();
let uv_backend = Path::new("../../scripts/packages/uv_backend");
metadata(uv_backend, metadata_dir.path(), "1.0.0+test").unwrap();
let built_by_uv = Path::new("../../scripts/packages/built-by-uv");
metadata(built_by_uv, metadata_dir.path(), "1.0.0+test").unwrap();

let mut files: Vec<_> = WalkDir::new(metadata_dir.path())
.into_iter()
Expand All @@ -101,38 +101,36 @@ fn test_prepare_metadata() {
.collect();
files.sort();
assert_snapshot!(files.join("\n"), @r"
uv_backend-0.1.0.dist-info
uv_backend-0.1.0.dist-info/METADATA
uv_backend-0.1.0.dist-info/RECORD
uv_backend-0.1.0.dist-info/WHEEL
built_by_uv-0.1.0.dist-info
built_by_uv-0.1.0.dist-info/METADATA
built_by_uv-0.1.0.dist-info/RECORD
built_by_uv-0.1.0.dist-info/WHEEL
");

let metadata_file = metadata_dir
.path()
.join("uv_backend-0.1.0.dist-info/METADATA");
.join("built_by_uv-0.1.0.dist-info/METADATA");
assert_snapshot!(fs_err::read_to_string(metadata_file).unwrap(), @r###"
Metadata-Version: 2.3
Name: uv-backend
Version: 0.1.0
Summary: Add your description here
Requires-Python: >=3.12
Description-Content-Type: text/markdown
# uv_backend
A simple package to be built with the uv build backend.
"###);
Metadata-Version: 2.3
Name: built-by-uv
Version: 0.1.0
Summary: A package to be built with the uv build backend that uses all features exposed by the build backend
Requires-Dist: anyio>=4,<5
Requires-Python: >=3.12
"###);

let record_file = metadata_dir
.path()
.join("uv_backend-0.1.0.dist-info/RECORD");
.join("built_by_uv-0.1.0.dist-info/RECORD");
assert_snapshot!(fs_err::read_to_string(record_file).unwrap(), @r###"
uv_backend-0.1.0.dist-info/WHEEL,sha256=3da1bfa0e8fd1b6cc246aa0b2b44a35815596c600cb485c39a6f8c106c3d5a8d,83
uv_backend-0.1.0.dist-info/METADATA,sha256=e4a0d390317d7182f65ea978254c71ed283e0a4242150cf1c99a694b113ff68d,224
uv_backend-0.1.0.dist-info/RECORD,,
built_by_uv-0.1.0.dist-info/WHEEL,sha256=3da1bfa0e8fd1b6cc246aa0b2b44a35815596c600cb485c39a6f8c106c3d5a8d,83
built_by_uv-0.1.0.dist-info/METADATA,sha256=ec36b5ae8830bdd248e90aaf581483ffb057f9a2d0f41e19e585531e7d07c9dc,215
built_by_uv-0.1.0.dist-info/RECORD,,
"###);

let wheel_file = metadata_dir.path().join("uv_backend-0.1.0.dist-info/WHEEL");
let wheel_file = metadata_dir
.path()
.join("built_by_uv-0.1.0.dist-info/WHEEL");
assert_snapshot!(fs_err::read_to_string(wheel_file).unwrap(), @r###"
Wheel-Version: 1.0
Generator: uv 1.0.0+test
Expand Down
2 changes: 2 additions & 0 deletions crates/uv/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,15 @@ base64 = { version = "0.22.1" }
byteorder = { version = "1.5.0" }
etcetera = { workspace = true }
filetime = { version = "0.2.25" }
flate2 = { workspace = true }
ignore = { version = "0.4.23" }
indoc = { version = "2.0.5" }
insta = { version = "1.40.0", features = ["filters", "json"] }
predicates = { version = "3.1.2" }
regex = { workspace = true }
reqwest = { workspace = true, features = ["blocking"], default-features = false }
similar = { version = "2.6.0" }
tar = { workspace = true }
tempfile = { workspace = true }
zip = { workspace = true }

Expand Down
102 changes: 96 additions & 6 deletions crates/uv/tests/it/build_backend.rs
Original file line number Diff line number Diff line change
@@ -1,51 +1,141 @@
use crate::common::{uv_snapshot, TestContext};
use anyhow::Result;
use assert_cmd::assert::OutputAssertExt;
use flate2::bufread::GzDecoder;
use fs_err::File;
use indoc::indoc;
use std::env;
use std::io::BufReader;
use std::path::Path;
use tempfile::TempDir;
use uv_static::EnvVars;

const BUILT_BY_UV_TEST_SCRIPT: &str = indoc! {r#"
from built_by_uv import greet
from built_by_uv.arithmetic.circle import area
print(greet())
print(f"Area of a circle with r=2: {area(2)}")
"#};

/// Test that build backend works if we invoke it directly.
///
/// We can't test end-to-end here including the PEP 517 bridge code since we don't have a uv wheel.
#[test]
fn uv_backend_direct() -> Result<()> {
fn built_by_uv_direct_wheel() -> Result<()> {
let context = TestContext::new("3.12");
let uv_backend = Path::new("../../scripts/packages/uv_backend");
let built_by_uv = Path::new("../../scripts/packages/built-by-uv");

let temp_dir = TempDir::new()?;

uv_snapshot!(context
.build_backend()
.arg("build-wheel")
.arg(temp_dir.path())
.current_dir(uv_backend), @r###"
.current_dir(built_by_uv), @r###"
success: true
exit_code: 0
----- stdout -----
built_by_uv-0.1.0-py3-none-any.whl
----- stderr -----
"###);

context
.pip_install()
.arg(temp_dir.path().join("built_by_uv-0.1.0-py3-none-any.whl"))
.assert()
.success();

uv_snapshot!(context
.run()
.arg("python")
.arg("-c")
.arg(BUILT_BY_UV_TEST_SCRIPT)
// Python on windows
.env(EnvVars::PYTHONUTF8, "1"), @r###"
success: true
exit_code: 0
----- stdout -----
Hello 👋
Area of a circle with r=2: 12.56636
----- stderr -----
"###);

Ok(())
}

/// Test that source tree -> source dist -> wheel works.
///
/// We can't test end-to-end here including the PEP 517 bridge code since we don't have a uv wheel,
/// so we call the build backend directly.
#[test]
fn built_by_uv_direct() -> Result<()> {
let context = TestContext::new("3.12");
let built_by_uv = Path::new("../../scripts/packages/built-by-uv");

let sdist_dir = TempDir::new()?;

uv_snapshot!(context
.build_backend()
.arg("build-sdist")
.arg(sdist_dir.path())
.current_dir(built_by_uv), @r###"
success: true
exit_code: 0
----- stdout -----
uv_backend-0.1.0-py3-none-any.whl
built_by_uv-0.1.0.tar.gz
----- stderr -----
"###);

let sdist_tree = TempDir::new()?;

let sdist_reader = BufReader::new(File::open(
sdist_dir.path().join("built_by_uv-0.1.0.tar.gz"),
)?);
tar::Archive::new(GzDecoder::new(sdist_reader)).unpack(sdist_tree.path())?;

drop(sdist_dir);

let wheel_dir = TempDir::new()?;

uv_snapshot!(context
.build_backend()
.arg("build-wheel")
.arg(wheel_dir.path())
.current_dir(sdist_tree.path().join("built-by-uv-0.1.0")), @r###"
success: true
exit_code: 0
----- stdout -----
built_by_uv-0.1.0-py3-none-any.whl
----- stderr -----
"###);

drop(sdist_tree);

context
.pip_install()
.arg(temp_dir.path().join("uv_backend-0.1.0-py3-none-any.whl"))
.arg(wheel_dir.path().join("built_by_uv-0.1.0-py3-none-any.whl"))
.assert()
.success();

drop(wheel_dir);

uv_snapshot!(context
.run()
.arg("python")
.arg("-c")
.arg("import uv_backend\nuv_backend.greet()")
.arg(BUILT_BY_UV_TEST_SCRIPT)
// Python on windows
.env(EnvVars::PYTHONUTF8, "1"), @r###"
success: true
exit_code: 0
----- stdout -----
Hello 👋
Area of a circle with r=2: 12.56636
----- stderr -----
"###);
Expand Down
2 changes: 2 additions & 0 deletions scripts/packages/built-by-uv/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/dist/
/build-root/
3 changes: 3 additions & 0 deletions scripts/packages/built-by-uv/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# built_by_uv

A package to be built with the uv build backend that uses all features exposed by the build backend.
1 change: 1 addition & 0 deletions scripts/packages/built-by-uv/data-dir/dont-include-me.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
We don't want this file in the source dist or wheel.
11 changes: 11 additions & 0 deletions scripts/packages/built-by-uv/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[project]
name = "built-by-uv"
version = "0.1.0"
description = "A package to be built with the uv build backend that uses all features exposed by the build backend"
#rreadme = "README.md"
requires-python = ">=3.12"
dependencies = ["anyio>=4,<5"]

[build-system]
requires = ["uv>=0.4.15,<5"]
build-backend = "uv"
2 changes: 2 additions & 0 deletions scripts/packages/built-by-uv/src/built_by_uv/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def greet() -> str:
return "Hello 👋"
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .circle import area as circle_area

__all__ = ["circle_area"]
12 changes: 12 additions & 0 deletions scripts/packages/built-by-uv/src/built_by_uv/arithmetic/circle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from functools import lru_cache
from pathlib import Path


@lru_cache(maxsize=1)
def pi() -> float:
return float(Path(__file__).parent.joinpath("pi.txt").read_text().strip())


def area(radius: float) -> float:
"""Use a non-Python file (`pi.txt`)."""
return radius**2 * pi()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.14159
23 changes: 23 additions & 0 deletions scripts/packages/built-by-uv/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash
# Test source tree -> source dist -> wheel and run pytest after.
# We can't test this through the build backend setting directly since we want
# to use the debug build of uv, so we use the internal API instead.

set -e

cargo build
uv venv -p 3.12 -q
mkdir -p dist
rm -f dist/*
../../../target/debug/uv build-backend build-sdist dist/
rm -rf build-root
mkdir build-root
cd build-root
tar -tvf ../dist/built_by_uv-0.1.0.tar.gz
tar xf ../dist/built_by_uv-0.1.0.tar.gz
cd built-by-uv-0.1.0
../../../../../target/debug/uv build-backend build-wheel ../../dist
unzip -l ../../dist/built_by_uv-0.1.0-py3-none-any.whl
cd ../..
uv pip install -q pytest dist/built_by_uv-0.1.0-py3-none-any.whl
pytest
11 changes: 11 additions & 0 deletions scripts/packages/built-by-uv/tests/test_package.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import pytest
from built_by_uv import greet
from built_by_uv.arithmetic.circle import area


def test_circle():
assert area(2) == pytest.approx(12.56636)


def test_greet():
assert greet() == "Hello 👋"
Loading

0 comments on commit c23023c

Please sign in to comment.