From 419abc6f9df4544caa0ee7f5d8885629d0a673be Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Mon, 23 Mar 2026 10:46:28 -0400 Subject: [PATCH] Treat 'Dynamic' values as case-insensitive --- .../src/metadata/metadata_resolver.rs | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/crates/uv-pypi-types/src/metadata/metadata_resolver.rs b/crates/uv-pypi-types/src/metadata/metadata_resolver.rs index daebbda6b82b4..912008e6c7a6f 100644 --- a/crates/uv-pypi-types/src/metadata/metadata_resolver.rs +++ b/crates/uv-pypi-types/src/metadata/metadata_resolver.rs @@ -79,7 +79,7 @@ impl ResolutionMetadata { .collect::>(); let dynamic = headers .get_all_values("Dynamic") - .any(|field| field == "Version"); + .any(|field| field.eq_ignore_ascii_case("Version")); Ok(Self { name, @@ -112,12 +112,15 @@ impl ResolutionMetadata { // If any of the fields we need are marked as dynamic, we can't use the `PKG-INFO` file. let mut dynamic = false; for field in headers.get_all_values("Dynamic") { - match field.as_str() { - "Requires-Python" => return Err(MetadataError::DynamicField("Requires-Python")), - "Requires-Dist" => return Err(MetadataError::DynamicField("Requires-Dist")), - "Provides-Extra" => return Err(MetadataError::DynamicField("Provides-Extra")), - "Version" => dynamic = true, - _ => (), + let field = field.as_str(); + if field.eq_ignore_ascii_case("Requires-Python") { + return Err(MetadataError::DynamicField("Requires-Python")); + } else if field.eq_ignore_ascii_case("Requires-Dist") { + return Err(MetadataError::DynamicField("Requires-Dist")); + } else if field.eq_ignore_ascii_case("Provides-Extra") { + return Err(MetadataError::DynamicField("Provides-Extra")); + } else if field.eq_ignore_ascii_case("Version") { + dynamic = true; } } @@ -334,6 +337,25 @@ mod tests { let meta = ResolutionMetadata::parse_pkg_info(s.as_bytes()).unwrap_err(); assert!(matches!(meta, MetadataError::DynamicField("Requires-Dist"))); + // Dynamic field values should be matched case-insensitively. + let s = "Metadata-Version: 2.3\nName: asdf\nVersion: 1.0\nDynamic: requires-dist"; + let meta = ResolutionMetadata::parse_pkg_info(s.as_bytes()).unwrap_err(); + assert!(matches!(meta, MetadataError::DynamicField("Requires-Dist"))); + + let s = "Metadata-Version: 2.3\nName: asdf\nVersion: 1.0\nDynamic: requires-python"; + let meta = ResolutionMetadata::parse_pkg_info(s.as_bytes()).unwrap_err(); + assert!(matches!( + meta, + MetadataError::DynamicField("Requires-Python") + )); + + let s = "Metadata-Version: 2.3\nName: asdf\nVersion: 1.0\nDynamic: provides-extra"; + let meta = ResolutionMetadata::parse_pkg_info(s.as_bytes()).unwrap_err(); + assert!(matches!( + meta, + MetadataError::DynamicField("Provides-Extra") + )); + let s = "Metadata-Version: 2.3\nName: asdf\nVersion: 1.0\nRequires-Dist: foo"; let meta = ResolutionMetadata::parse_pkg_info(s.as_bytes()).unwrap(); assert_eq!(meta.name, PackageName::from_str("asdf").unwrap());