Skip to content

Commit 2784856

Browse files
Allow for unnormalized names in the METADATA file (#16547) (#16548)
## Summary Deserialize project name into both a String and a ProjectName, this way we can keep using the normalized name elsewhere while respecting the original name from the `pyproject.toml` file This PR addresses issue #16547 ## Test Plan I added a new test for this, and I ran the test suite in the `metadata.rs` file. --------- Co-authored-by: Charlie Marsh <[email protected]>
1 parent 101d0e2 commit 2784856

File tree

1 file changed

+46
-4
lines changed

1 file changed

+46
-4
lines changed

crates/uv-build-backend/src/metadata.rs

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::path::{Path, PathBuf};
66
use std::str::FromStr;
77

88
use itertools::Itertools;
9-
use serde::Deserialize;
9+
use serde::{Deserialize, Deserializer};
1010
use tracing::{debug, trace, warn};
1111
use version_ranges::Ranges;
1212
use walkdir::WalkDir;
@@ -105,6 +105,26 @@ pub fn check_direct_build(source_tree: &Path, name: impl Display) -> bool {
105105
}
106106
}
107107

108+
/// A package name as provided in a `pyproject.toml`.
109+
#[derive(Debug, Clone)]
110+
struct VerbatimPackageName {
111+
/// The package name as given in the `pyproject.toml`.
112+
given: String,
113+
/// The normalized package name.
114+
normalized: PackageName,
115+
}
116+
117+
impl<'de> Deserialize<'de> for VerbatimPackageName {
118+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
119+
where
120+
D: Deserializer<'de>,
121+
{
122+
let given = String::deserialize(deserializer)?;
123+
let normalized = PackageName::from_str(&given).map_err(serde::de::Error::custom)?;
124+
Ok(Self { given, normalized })
125+
}
126+
}
127+
108128
/// A `pyproject.toml` as specified in PEP 517.
109129
#[derive(Deserialize, Debug, Clone)]
110130
#[serde(
@@ -123,7 +143,7 @@ pub struct PyProjectToml {
123143

124144
impl PyProjectToml {
125145
pub(crate) fn name(&self) -> &PackageName {
126-
&self.project.name
146+
&self.project.name.normalized
127147
}
128148

129149
pub(crate) fn version(&self) -> &Version {
@@ -456,7 +476,7 @@ impl PyProjectToml {
456476

457477
Ok(Metadata23 {
458478
metadata_version: metadata_version.to_string(),
459-
name: self.project.name.to_string(),
479+
name: self.project.name.given.clone(),
460480
version: self.project.version.to_string(),
461481
// Not supported.
462482
platforms: vec![],
@@ -579,7 +599,7 @@ impl PyProjectToml {
579599
#[serde(rename_all = "kebab-case")]
580600
struct Project {
581601
/// The name of the project.
582-
name: PackageName,
602+
name: VerbatimPackageName,
583603
/// The version of the project.
584604
version: Version,
585605
/// The summary description of the project in one line.
@@ -856,6 +876,28 @@ mod tests {
856876
formatted
857877
}
858878

879+
#[test]
880+
fn uppercase_package_name() {
881+
let contents = r#"
882+
[project]
883+
name = "Hello-World"
884+
version = "0.1.0"
885+
886+
[build-system]
887+
requires = ["uv_build>=0.4.15,<0.5.0"]
888+
build-backend = "uv_build"
889+
"#;
890+
let pyproject_toml = PyProjectToml::parse(contents).unwrap();
891+
let temp_dir = TempDir::new().unwrap();
892+
893+
let metadata = pyproject_toml.to_metadata(temp_dir.path()).unwrap();
894+
assert_snapshot!(metadata.core_metadata_format(), @r"
895+
Metadata-Version: 2.3
896+
Name: Hello-World
897+
Version: 0.1.0
898+
");
899+
}
900+
859901
#[test]
860902
fn valid() {
861903
let temp_dir = TempDir::new().unwrap();

0 commit comments

Comments
 (0)