File indexing completed on 2026-10-27 08:41:17
0001 """scripts/check_dist.py: wheel and sdist contents, size, and MANIFEST.in rules."""
0002 import importlib.util
0003 import io
0004 import os
0005 import tarfile
0006 import zipfile
0007
0008 import pytest
0009
0010 PROJECT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
0011 SCRIPT = os.path.join(PROJECT_DIR, "scripts", "check_dist.py")
0012
0013
0014 @pytest.fixture(scope="module")
0015 def check_dist():
0016 spec = importlib.util.spec_from_file_location("check_dist", SCRIPT)
0017 module = importlib.util.module_from_spec(spec)
0018 spec.loader.exec_module(module)
0019 return module
0020
0021
0022 def make_wheel(path, names):
0023 """A wheel holding `names`; LICENSE goes where setuptools puts license-files."""
0024 with zipfile.ZipFile(path, "w") as archive:
0025 for name in names:
0026 if name == "LICENSE":
0027 name = "pyrobird-1.0.dist-info/licenses/LICENSE"
0028 archive.writestr(name, "x")
0029 return str(path)
0030
0031
0032 def make_sdist(path, names, top="pyrobird-1.0"):
0033 with tarfile.open(path, "w:gz") as archive:
0034 for name in names:
0035 data = b"x"
0036 info = tarfile.TarInfo(f"{top}/{name}")
0037 info.size = len(data)
0038 archive.addfile(info, io.BytesIO(data))
0039 return str(path)
0040
0041
0042 def test_complete_archives_pass(check_dist, tmp_path):
0043 wheel = make_wheel(tmp_path / "pyrobird-1.0-py3-none-any.whl", check_dist.REQUIRED_FILES)
0044 sdist = make_sdist(tmp_path / "pyrobird-1.0.tar.gz", check_dist.REQUIRED_FILES)
0045 assert check_dist.check_archive(wheel) == []
0046 assert check_dist.check_archive(sdist) == []
0047 assert check_dist.main([str(tmp_path)]) == 0
0048
0049
0050 def test_missing_sample_fails(check_dist, tmp_path):
0051 sample = "pyrobird/server/static/assets/data/example-cherenkov.firebird.json"
0052 names = [name for name in check_dist.REQUIRED_FILES if name != sample]
0053 wheel = make_wheel(tmp_path / "pyrobird-1.0-py3-none-any.whl", names)
0054 problems = check_dist.check_archive(wheel)
0055 assert problems == [f"pyrobird-1.0-py3-none-any.whl lacks {sample}"]
0056 assert check_dist.main([wheel]) == 1
0057
0058
0059 @pytest.mark.parametrize("missing", ["LICENSE", "pyrobird/server/static/3rdpartylicenses.txt"])
0060 def test_missing_license_files_fail(check_dist, tmp_path, missing):
0061 names = [name for name in check_dist.REQUIRED_FILES if name != missing]
0062 wheel = make_wheel(tmp_path / "pyrobird-1.0-py3-none-any.whl", names)
0063 sdist = make_sdist(tmp_path / "pyrobird-1.0.tar.gz", names)
0064 assert check_dist.check_archive(wheel) == [f"pyrobird-1.0-py3-none-any.whl lacks {missing}"]
0065 assert check_dist.check_archive(sdist) == [f"pyrobird-1.0.tar.gz lacks {missing}"]
0066
0067
0068 def test_wheel_license_is_read_from_dist_info(check_dist, tmp_path):
0069 wheel = make_wheel(tmp_path / "pyrobird-1.0-py3-none-any.whl", ["LICENSE", "pyrobird/__init__.py"])
0070 with zipfile.ZipFile(wheel) as archive:
0071 assert "LICENSE" not in archive.namelist()
0072 assert check_dist.archive_members(wheel) == {"LICENSE", "pyrobird/__init__.py"}
0073
0074
0075 def test_oversized_archive_fails(check_dist, tmp_path):
0076 wheel = make_wheel(tmp_path / "pyrobird-1.0-py3-none-any.whl", check_dist.REQUIRED_FILES)
0077 problems = check_dist.check_archive(wheel, max_bytes=10)
0078 assert len(problems) == 1 and "the limit is 10 bytes" in problems[0]
0079
0080
0081 def test_no_archive_fails(check_dist, tmp_path):
0082 assert check_dist.main([str(tmp_path)]) == 1
0083
0084
0085 def test_manifest_rules(check_dist, tmp_path):
0086 manifest = tmp_path / "MANIFEST.in"
0087 manifest.write_text(
0088 "recursive-include pyrobird/server/static *\n"
0089 "recursive-exclude pyrobird/server/static/assets/data *.firebird.json\n")
0090 hits = check_dist.manifest_exclusions(str(manifest))
0091 assert [path for path, _ in hits] == ["pyrobird/server/static/assets/data/example-cherenkov.firebird.json"]
0092
0093
0094 def test_project_manifest_keeps_required_files(check_dist):
0095 """The MANIFEST.in that ships with pyrobird drops none of the required files."""
0096 assert check_dist.manifest_exclusions(os.path.join(PROJECT_DIR, "MANIFEST.in")) == []
0097 assert check_dist.main(["--manifest-only"]) == 0