mirror of https://github.com/astral-sh/uv
Add support for Hatch's `{root:uri}` paths in editable installs (#2492)
## Summary
If a package uses Hatch's `root.uri` feature, we currently error:
```toml
dependencies = [
"black @ {root:uri}/../black_editable"
]
```
Even though we're using PEP 517 hooks to get the metadata, which
_should_ support this. The problem is that we load the full
`PyProjectToml`, which means we parse the requirements, which means we
reject what looks like a relative URL in dependencies.
Instead, we should only enforce a limited subset of `pyproject.toml`
(arguably none).
Closes https://github.com/astral-sh/uv/issues/2475.
This commit is contained in:
parent
5a95f50619
commit
db5898bd67
|
|
@ -4301,6 +4301,7 @@ dependencies = [
|
||||||
"insta",
|
"insta",
|
||||||
"itertools 0.12.1",
|
"itertools 0.12.1",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
"pep440_rs",
|
||||||
"pep508_rs",
|
"pep508_rs",
|
||||||
"pypi-types",
|
"pypi-types",
|
||||||
"pyproject-toml",
|
"pyproject-toml",
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
distribution-types = { path = "../distribution-types" }
|
distribution-types = { path = "../distribution-types" }
|
||||||
|
pep440_rs = { path = "../pep440-rs" }
|
||||||
pep508_rs = { path = "../pep508-rs" }
|
pep508_rs = { path = "../pep508-rs" }
|
||||||
pypi-types = { path = "../pypi-types" }
|
pypi-types = { path = "../pypi-types" }
|
||||||
uv-fs = { path = "../uv-fs" }
|
uv-fs = { path = "../uv-fs" }
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ use fs_err as fs;
|
||||||
use indoc::formatdoc;
|
use indoc::formatdoc;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use pyproject_toml::Project;
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use serde::de::{value, SeqAccess, Visitor};
|
use serde::de::{value, SeqAccess, Visitor};
|
||||||
|
|
@ -27,6 +26,7 @@ use tokio::sync::Mutex;
|
||||||
use tracing::{debug, info_span, instrument, Instrument};
|
use tracing::{debug, info_span, instrument, Instrument};
|
||||||
|
|
||||||
use distribution_types::Resolution;
|
use distribution_types::Resolution;
|
||||||
|
use pep440_rs::{Version, VersionSpecifiers};
|
||||||
use pep508_rs::Requirement;
|
use pep508_rs::Requirement;
|
||||||
use uv_fs::Simplified;
|
use uv_fs::Simplified;
|
||||||
use uv_interpreter::{Interpreter, PythonEnvironment};
|
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)]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
pub struct PyProjectToml {
|
pub struct PyProjectToml {
|
||||||
|
|
@ -203,6 +203,18 @@ pub struct PyProjectToml {
|
||||||
pub project: Option<Project>,
|
pub project: Option<Project>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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<Version>,
|
||||||
|
/// The Python version requirements of the project
|
||||||
|
pub requires_python: Option<VersionSpecifiers>,
|
||||||
|
}
|
||||||
|
|
||||||
/// The `[build-system]` section of a pyproject.toml as specified in PEP 517.
|
/// The `[build-system]` section of a pyproject.toml as specified in PEP 517.
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
|
|
|
||||||
|
|
@ -5150,3 +5150,39 @@ requires-python = "<=3.8"
|
||||||
|
|
||||||
Ok(())
|
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(())
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
def func():
|
||||||
|
pass
|
||||||
Loading…
Reference in New Issue