From f3624f2e949a4e6633b5fdb4b1b24137fc3a4598 Mon Sep 17 00:00:00 2001 From: Dylan Pulver Date: Wed, 2 Sep 2026 14:41:37 +0300 Subject: [PATCH] Validate the build tag passed to `wheel pack --build-number` `wheel tags --build` runs the value through `parse_build_tag`, but `wheel pack --build-number` splices it straight into the file name. A build tag that does not start with a digit, or that contains `-`, then produces a name that `packaging.utils.parse_wheel_filename` rejects and that `WHEEL_INFO_RE` silently mis-parses. Reuse the existing validator for `--build-number`. --- docs/news.rst | 3 +++ src/wheel/_commands/__init__.py | 4 +++- tests/commands/test_pack.py | 31 +++++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/docs/news.rst b/docs/news.rst index 52e86e6d..df277259 100644 --- a/docs/news.rst +++ b/docs/news.rst @@ -3,6 +3,9 @@ Release Notes **UNRELEASED** +- Fixed ``wheel pack --build-number`` accepting build tags that are invalid in a + wheel file name (not starting with a digit, or containing ``-``), the same + validation ``wheel tags --build`` already performs - Fixed the macOS platform-tag warning always using the plural "these files" wording, even when only a single library required a higher deployment target (`#697 `_) diff --git a/src/wheel/_commands/__init__.py b/src/wheel/_commands/__init__.py index 7931c786..0ebddc06 100644 --- a/src/wheel/_commands/__init__.py +++ b/src/wheel/_commands/__init__.py @@ -102,7 +102,9 @@ def parser() -> argparse.ArgumentParser: help="Directory to store the wheel (default %(default)s)", ) repack_parser.add_argument( - "--build-number", help="Build tag to use in the wheel name" + "--build-number", + type=parse_build_tag, + help="Build tag to use in the wheel name", ) repack_parser.add_argument( "--local-version", help="Local version identifier to add or replace" diff --git a/tests/commands/test_pack.py b/tests/commands/test_pack.py index e25bbeb3..cbbf3112 100644 --- a/tests/commands/test_pack.py +++ b/tests/commands/test_pack.py @@ -7,6 +7,7 @@ from email.message import Message from email.parser import BytesParser from io import StringIO +from subprocess import CalledProcessError from zipfile import Path, ZipFile import pytest @@ -224,3 +225,33 @@ def test_pack_local_version_rejects_invalid( assert returncode == 1 assert "!invalid" in stderr.getvalue() + + +@pytest.mark.parametrize( + "build_tag, error", + [ + pytest.param("foo", "build tag must begin with a digit", id="digitstart"), + pytest.param("1-f", "invalid character ('-') in build tag", id="hyphen"), + ], +) +def test_pack_invalid_build_tag( + tmp_path_factory: TempPathFactory, tmp_path: Path, build_tag: str, error: str +) -> None: + unpack_dir = tmp_path_factory.mktemp("wheeldir") + with ZipFile(TESTWHEEL_PATH) as zf: + zf.extractall(unpack_dir) + + with pytest.raises(CalledProcessError) as exc_info: + run_command( + "pack", + "--dest", + tmp_path, + unpack_dir, + "--build-number", + build_tag, + catch_systemexit=False, + ) + + exc = exc_info.value + assert exc.returncode == 2 + assert f"error: argument --build-number: {error}" in exc.stderr