From 3d303a4915a6eed5fcdb7d8009e2bccb725bd071 Mon Sep 17 00:00:00 2001 From: feder-cr <85809106+feder-cr@users.noreply.github.com> Date: Sat, 16 May 2026 10:39:40 -0700 Subject: [PATCH] =?UTF-8?q?tests:=20add=20wheel=20regression=20=E2=80=94?= =?UTF-8?q?=20fail=20if=20wheel=20has=20duplicate=20zip=20entries?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_build.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 tests/test_build.py diff --git a/tests/test_build.py b/tests/test_build.py new file mode 100644 index 0000000..4dd1bf9 --- /dev/null +++ b/tests/test_build.py @@ -0,0 +1,42 @@ +"""Regression: the produced wheel must not contain duplicate zip entries. + +The old pyproject.toml had a ``[tool.hatch.build.targets.wheel.force-include]`` +section that re-included `data/` and `_fpforge/data/` already covered by +``packages = ["src/invisible_playwright"]``. Hatchling wrote every JSON twice +into the zip; PyPI rejects wheels with duplicate names. +""" +from __future__ import annotations + +import subprocess +import sys +import zipfile +from collections import Counter +from pathlib import Path + +import pytest + + +@pytest.mark.slow +def test_built_wheel_has_no_duplicate_entries(tmp_path): + """Build the wheel in a clean dir and assert no duplicate zip names.""" + root = Path(__file__).resolve().parent.parent + out = tmp_path / "dist" + r = subprocess.run( + [sys.executable, "-m", "build", "--wheel", "--outdir", str(out)], + cwd=root, + capture_output=True, + text=True, + ) + assert r.returncode == 0, f"build failed:\n{r.stderr}" + + wheels = list(out.glob("*.whl")) + assert len(wheels) == 1, f"expected exactly one wheel, got {wheels}" + + with zipfile.ZipFile(wheels[0]) as zf: + names = zf.namelist() + dupes = {n: c for n, c in Counter(names).items() if c > 1} + + assert not dupes, f"wheel has duplicate entries (PyPI will reject): {dupes}" + # Sanity: the Bayesian data files must still be packaged. + json_files = [n for n in names if n.endswith(".json")] + assert json_files, "no .json data files in wheel — packaging broken"