diff --git a/Cargo.lock b/Cargo.lock index 6c4862001d75..d164edd22a27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4301,6 +4301,7 @@ dependencies = [ "insta", "itertools 0.12.1", "once_cell", + "pep440_rs", "pep508_rs", "pypi-types", "pyproject-toml", diff --git a/crates/uv-build/Cargo.toml b/crates/uv-build/Cargo.toml index 9ee5b7e270e6..796f97c553f5 100644 --- a/crates/uv-build/Cargo.toml +++ b/crates/uv-build/Cargo.toml @@ -15,6 +15,7 @@ workspace = true [dependencies] distribution-types = { path = "../distribution-types" } +pep440_rs = { path = "../pep440-rs" } pep508_rs = { path = "../pep508-rs" } pypi-types = { path = "../pypi-types" } uv-fs = { path = "../uv-fs" } diff --git a/crates/uv-build/src/lib.rs b/crates/uv-build/src/lib.rs index e1696a9dbeaf..969938714404 100644 --- a/crates/uv-build/src/lib.rs +++ b/crates/uv-build/src/lib.rs @@ -15,7 +15,6 @@ use fs_err as fs; use indoc::formatdoc; use itertools::Itertools; use once_cell::sync::Lazy; -use pyproject_toml::Project; use regex::Regex; use rustc_hash::FxHashMap; use serde::de::{value, SeqAccess, Visitor}; @@ -27,6 +26,7 @@ use tokio::sync::Mutex; use tracing::{debug, info_span, instrument, Instrument}; use distribution_types::Resolution; +use pep440_rs::{Version, VersionSpecifiers}; use pep508_rs::Requirement; use uv_fs::Simplified; use uv_interpreter::{Interpreter, PythonEnvironment}; @@ -193,7 +193,7 @@ impl Error { } } -/// A pyproject.toml as specified in PEP 517 +/// A pyproject.toml as specified in PEP 517. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] pub struct PyProjectToml { @@ -203,6 +203,18 @@ pub struct PyProjectToml { pub project: Option, } +/// The `[project]` section of a pyproject.toml as specified in PEP 621. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +#[serde(rename_all = "kebab-case")] +pub struct Project { + /// The name of the project + pub name: String, + /// The version of the project as supported by PEP 440 + pub version: Option, + /// The Python version requirements of the project + pub requires_python: Option, +} + /// The `[build-system]` section of a pyproject.toml as specified in PEP 517. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] diff --git a/crates/uv/tests/pip_compile.rs b/crates/uv/tests/pip_compile.rs index 403a3e0ee924..28b40f219ce9 100644 --- a/crates/uv/tests/pip_compile.rs +++ b/crates/uv/tests/pip_compile.rs @@ -5150,3 +5150,39 @@ requires-python = "<=3.8" Ok(()) } + +/// Build an editable package with Hatchling's {root:uri} feature. +#[test] +fn compile_root_uri() -> Result<()> { + let context = TestContext::new("3.12"); + + let requirements_in = context.temp_dir.child("requirements.in"); + requirements_in.write_str("-e ${ROOT_PATH}")?; + + // In addition to the standard filters, remove the temporary directory from the snapshot. + let filters: Vec<_> = [(r"file://.*/", "file://[TEMP_DIR]/")] + .into_iter() + .chain(INSTA_FILTERS.to_vec()) + .collect(); + + let root_path = current_dir()?.join("../../scripts/editable-installs/root_editable"); + uv_snapshot!(filters, context.compile() + .arg("requirements.in") + .env("ROOT_PATH", root_path.as_os_str()), @r###" + success: true + exit_code: 0 + ----- stdout ----- + # This file was autogenerated by uv via the following command: + # uv pip compile --cache-dir [CACHE_DIR] --exclude-newer 2023-11-18T12:00:00Z requirements.in + -e ${ROOT_PATH} + black @ file://[TEMP_DIR]/black_editable + # via root-editable + + ----- stderr ----- + Built 1 editable in [TIME] + Resolved 2 packages in [TIME] + "### + ); + + Ok(()) +} diff --git a/scripts/editable-installs/root_editable/README.md b/scripts/editable-installs/root_editable/README.md new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/scripts/editable-installs/root_editable/pyproject.toml b/scripts/editable-installs/root_editable/pyproject.toml new file mode 100644 index 000000000000..ae9a26171a94 --- /dev/null +++ b/scripts/editable-installs/root_editable/pyproject.toml @@ -0,0 +1,22 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "root-editable" +description = 'A simple editable package with a {root:uri} dependency.' +readme = "README.md" +requires-python = ">=3.7" +license = "MIT" +keywords = [] +authors = [ + { name = "Astral Software Inc.", email = "hey@astral.sh" }, +] +classifiers = [] +dependencies = [ + "black @ {root:uri}/../black_editable" +] +version = "0.1.0" + +[tool.hatch.metadata] +allow-direct-references = true diff --git a/scripts/editable-installs/root_editable/root_editable/__init__.py b/scripts/editable-installs/root_editable/root_editable/__init__.py new file mode 100644 index 000000000000..b9bfa6f12339 --- /dev/null +++ b/scripts/editable-installs/root_editable/root_editable/__init__.py @@ -0,0 +1,2 @@ +def func(): + pass