Hint at missing project.name (#6803)

We got user reports where users were confused about why they can't use
`[project.urls]` in `pyproject.toml` (i think that's from poetry?). This
PR adds a hint that (according to PEP 621), you need to set
`project.name` when using any `project` fields. (PEP 621 also requires
`project.version` xor `dynamic = ["version"]`, but we check that later.)

The intermediate parsing layer to tell apart syntax errors from schema
errors doesn't incur a performance penalty according to epage
(https://github.com/toml-rs/toml/issues/778#issuecomment-2310369253).

Closes #6419
Closes #6760
This commit is contained in:
konsti 2024-09-14 22:03:47 +02:00 committed by GitHub
parent 3d62154849
commit 4aad89cf06
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 132 additions and 13 deletions

View file

@ -29,6 +29,7 @@ rkyv = { workspace = true }
serde = { workspace = true }
thiserror = { workspace = true }
toml = { workspace = true }
toml_edit = { workspace = true }
tracing = { workspace = true }
url = { workspace = true }

View file

@ -6,6 +6,7 @@ use std::str::FromStr;
use indexmap::IndexMap;
use itertools::Itertools;
use mailparse::{MailHeaderMap, MailParseError};
use serde::de::IntoDeserializer;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use tracing::warn;
@ -44,8 +45,12 @@ pub struct Metadata23 {
pub enum MetadataError {
#[error(transparent)]
MailParse(#[from] MailParseError),
#[error("Invalid `pyproject.toml`")]
InvalidPyprojectTomlSyntax(#[source] toml_edit::TomlError),
#[error("`pyproject.toml` is using the `[project]` table, but the required `project.name` is not set.")]
InvalidPyprojectTomlMissingName(#[source] toml_edit::de::Error),
#[error(transparent)]
Toml(#[from] toml::de::Error),
InvalidPyprojectTomlSchema(toml_edit::de::Error),
#[error("metadata field {0} not found")]
FieldNotFound(&'static str),
#[error("invalid version: {0}")]
@ -196,7 +201,7 @@ impl Metadata23 {
/// Extract the metadata from a `pyproject.toml` file, as specified in PEP 621.
pub fn parse_pyproject_toml(contents: &str) -> Result<Self, MetadataError> {
let pyproject_toml: PyProjectToml = toml::from_str(contents)?;
let pyproject_toml = PyProjectToml::from_toml(contents)?;
let project = pyproject_toml
.project
@ -279,6 +284,23 @@ struct PyProjectToml {
tool: Option<Tool>,
}
impl PyProjectToml {
fn from_toml(toml: &str) -> Result<Self, MetadataError> {
let pyproject_toml: toml_edit::ImDocument<_> = toml_edit::ImDocument::from_str(toml)
.map_err(MetadataError::InvalidPyprojectTomlSyntax)?;
let pyproject_toml: Self = PyProjectToml::deserialize(pyproject_toml.into_deserializer())
.map_err(|err| {
// TODO(konsti): A typed error would be nicer, this can break on toml upgrades.
if err.message().contains("missing field `name`") {
MetadataError::InvalidPyprojectTomlMissingName(err)
} else {
MetadataError::InvalidPyprojectTomlSchema(err)
}
})?;
Ok(pyproject_toml)
}
}
/// PEP 621 project metadata.
///
/// This is a subset of the full metadata specification, and only includes the fields that are
@ -435,7 +457,7 @@ pub struct RequiresDist {
impl RequiresDist {
/// Extract the [`RequiresDist`] from a `pyproject.toml` file, as specified in PEP 621.
pub fn parse_pyproject_toml(contents: &str) -> Result<Self, MetadataError> {
let pyproject_toml: PyProjectToml = toml::from_str(contents)?;
let pyproject_toml = PyProjectToml::from_toml(contents)?;
let project = pyproject_toml
.project