1import argparse 2import re 3import sys 4import tomllib 5from pathlib import Path 6 7 8class ValidationError(Exception): 9 pass 10 11 12def check(github_ref: str | None) -> None: 13 pyproject = Path(__file__).parent.parent / "pyproject.toml" 14 if not pyproject.exists(): 15 raise ValidationError("pyproject.toml not found") 16 with pyproject.open("rb") as f: 17 data = tomllib.load(f) 18 pyproject_version = data["project"]["version"] 19 20 if github_ref is not None and github_ref.startswith("refs/tags/"): 21 version = github_ref.removeprefix("refs/tags/") 22 if version != pyproject_version: 23 raise ValidationError( 24 f"Version mismatch: GitHub ref is {version}, " 25 f"but pyproject.toml is {pyproject_version}" 26 ) 27 28 requires_python = data["project"]["requires-python"] 29 assert sys.version_info[0] == 3, "Rewrite this script when Python 4 comes out" 30 match = re.fullmatch(r">=3\.(\d+)", requires_python) 31 if not match: 32 raise ValidationError(f"Invalid requires-python: {requires_python!r}") 33 lowest_minor = int(match.group(1)) 34 35 description = data["project"]["description"] 36 if not description.endswith(f"3.{lowest_minor}+"): 37 raise ValidationError(f"Description should mention Python 3.{lowest_minor}+") 38 39 classifiers = set(data["project"]["classifiers"]) 40 for should_be_supported in range(lowest_minor, sys.version_info[1] + 1): 41 if ( 42 f"Programming Language :: Python :: 3.{should_be_supported}" 43 not in classifiers 44 ): 45 raise ValidationError( 46 f"Missing classifier for Python 3.{should_be_supported}" 47 ) 48 49 50if __name__ == "__main__": 51 parser = argparse.ArgumentParser("Script to check the package metadata") 52 parser.add_argument( 53 "github_ref", type=str, help="The current GitHub ref", nargs="?" 54 ) 55 args = parser.parse_args() 56 try: 57 check(args.github_ref) 58 except ValidationError as e: 59 print(e) 60 sys.exit(1) 61