From 14dcee9b3f0a8fe0bcb45fc3b7f59b56b19c5bee Mon Sep 17 00:00:00 2001 From: konstin Date: Tue, 15 Oct 2024 10:42:56 +0200 Subject: [PATCH] Publish: Warn about unnormalized filenames. The spec requires normalizing the name and the version in distribution filenames (https://packaging.python.org/en/latest/specifications/binary-distribution-format/#escaping-and-unicode). Missing normalization caused #8030, this PR adds a warning for it. --- crates/uv-publish/src/lib.rs | 6 ++++++ crates/uv/tests/it/publish.rs | 40 +++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/crates/uv-publish/src/lib.rs b/crates/uv-publish/src/lib.rs index f832079ab181..64b92c60b11c 100644 --- a/crates/uv-publish/src/lib.rs +++ b/crates/uv-publish/src/lib.rs @@ -230,6 +230,12 @@ pub fn files_for_publishing( } let dist_filename = DistFilename::try_from_normalized_filename(&filename) .ok_or_else(|| PublishError::InvalidFilename(dist.clone()))?; + if dist_filename.to_string() != filename { + warn_user!( + "Invalid filename: Expected `{dist_filename}`, found `{filename}`. \ + This is a problem with the build backend." + ); + } files.push((dist, filename, dist_filename)); } } diff --git a/crates/uv/tests/it/publish.rs b/crates/uv/tests/it/publish.rs index 94039ba75188..17bf2ea60dd6 100644 --- a/crates/uv/tests/it/publish.rs +++ b/crates/uv/tests/it/publish.rs @@ -1,4 +1,5 @@ use crate::common::{uv_snapshot, TestContext}; +use assert_fs::fixture::{FileTouch, PathChild}; #[test] fn username_password_no_longer_supported() { @@ -51,3 +52,42 @@ fn invalid_token() { "### ); } + +/// Check that we warn about unnormalized filenames. +#[test] +fn invalid_validation_error() { + let context = TestContext::new("3.12"); + + let dist = context.temp_dir.child("dist"); + // Unescaped dot + dist.child("aviary.gsm8k-0.7.6-py3-none-any.whl") + .touch() + .unwrap(); + // Unescaped dot + dist.child("aviary.gsm8k-0.7.6.tar.gz").touch().unwrap(); + // Complex but valid + dist.child("maturin-1.7.4-py3.py2-none-manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64.whl").touch().unwrap(); + + uv_snapshot!(context.filters(), context.publish() + .arg("--token") + .arg("dummy") + .arg("--publish-url") + .arg("https://test.pypi.org/legacy/") + .current_dir(&context.temp_dir), @r###" + success: false + exit_code: 2 + ----- stdout ----- + + ----- stderr ----- + warning: `uv publish` is experimental and may change without warning + warning: Invalid filename: Expected `aviary_gsm8k-0.7.6-py3-none-any.whl`, found `aviary.gsm8k-0.7.6-py3-none-any.whl`. This is a problem with the build backend. + warning: Invalid filename: Expected `aviary_gsm8k-0.7.6.tar.gz`, found `aviary.gsm8k-0.7.6.tar.gz`. This is a problem with the build backend. + Publishing 3 files https://test.pypi.org/legacy/ + Uploading aviary_gsm8k-0.7.6-py3-none-any.whl ([SIZE]) + error: Failed to publish: `dist/aviary.gsm8k-0.7.6-py3-none-any.whl` + Caused by: Failed to read metadata + Caused by: Failed to read from zip file + Caused by: unable to locate the end of central directory record + "### + ); +}