99import zipfile
1010from pathlib import Path , PurePosixPath
1111
12- from _checks import (
13- CANONICAL_AUTHOR ,
14- CANONICAL_PROJECT_URLS ,
15- CheckError ,
16- normalize_version ,
17- parse_metadata ,
18- read_project_version ,
19- sha256_file ,
20- )
12+ try :
13+ from ._checks import (
14+ CANONICAL_AUTHOR ,
15+ CANONICAL_PROJECT_URLS ,
16+ PROJECT_ROOT ,
17+ PUBLIC_README_INSTALL_COMMAND ,
18+ CheckError ,
19+ metadata_description ,
20+ normalize_version ,
21+ parse_metadata ,
22+ public_readme_has_install_command ,
23+ public_readme_release_violations ,
24+ read_project_version ,
25+ sha256_file ,
26+ )
27+ except ImportError : # Direct execution from the repository root.
28+ from _checks import (
29+ CANONICAL_AUTHOR ,
30+ CANONICAL_PROJECT_URLS ,
31+ PROJECT_ROOT ,
32+ PUBLIC_README_INSTALL_COMMAND ,
33+ CheckError ,
34+ metadata_description ,
35+ normalize_version ,
36+ parse_metadata ,
37+ public_readme_has_install_command ,
38+ public_readme_release_violations ,
39+ read_project_version ,
40+ sha256_file ,
41+ )
2142
2243REQUIRED_PACKAGE_FILES = {
2344 "cometapi/__init__.py" ,
@@ -88,7 +109,12 @@ def _safe_path(name: str, source: Path) -> PurePosixPath:
88109 return path
89110
90111
91- def _check_metadata (raw : bytes , source : str , expected_version : str ) -> None :
112+ def check_metadata (
113+ raw : bytes ,
114+ source : str ,
115+ expected_version : str ,
116+ expected_description : str ,
117+ ) -> None :
92118 metadata = parse_metadata (raw , source )
93119 actual_version = normalize_version (str (metadata ["Version" ]))
94120 if actual_version != expected_version :
@@ -114,9 +140,23 @@ def _check_metadata(raw: bytes, source: str, expected_version: str) -> None:
114140 for label , expected in CANONICAL_PROJECT_URLS .items ():
115141 if project_urls .get (label ) != expected :
116142 raise CheckError (f"{ source } : expected Project-URL { label } , { expected } " )
143+ description = metadata_description (metadata , source )
144+ if description != expected_description :
145+ raise CheckError (f"{ source } : long description does not exactly match source README.md" )
146+ violations = public_readme_release_violations (description )
147+ if violations :
148+ raise CheckError (
149+ f"{ source } : long description contains publication-specific release text: "
150+ + ", " .join (sorted (set (violations )))
151+ )
152+ if not public_readme_has_install_command (description ):
153+ raise CheckError (
154+ f"{ source } : long description must contain the unpinned stable install command "
155+ f"{ PUBLIC_README_INSTALL_COMMAND !r} "
156+ )
117157
118158
119- def _check_wheel (path : Path , expected_version : str ) -> None :
159+ def _check_wheel (path : Path , expected_version : str , expected_description : str ) -> None :
120160 expected_fragment = f"cometapi-{ expected_version } -"
121161 if expected_fragment not in path .name :
122162 raise CheckError (f"{ path .name } : filename does not contain { expected_fragment !r} " )
@@ -142,16 +182,19 @@ def _check_wheel(path: Path, expected_version: str) -> None:
142182 metadata_names = [name for name in names if name .endswith (".dist-info/METADATA" )]
143183 if len (metadata_names ) != 1 :
144184 raise CheckError (f"{ path .name } : expected exactly one .dist-info/METADATA" )
145- _check_metadata (
146- archive .read (metadata_names [0 ]), f"{ path .name } :{ metadata_names [0 ]} " , expected_version
185+ check_metadata (
186+ archive .read (metadata_names [0 ]),
187+ f"{ path .name } :{ metadata_names [0 ]} " ,
188+ expected_version ,
189+ expected_description ,
147190 )
148191 for source_name in ("cometapi/__init__.py" , "cometapi/client.py" ):
149192 text = archive .read (source_name ).decode ("utf-8" )
150193 if re .search (r"\b(?:CometClient|AsyncCometClient)\b" , text ):
151194 raise CheckError (f"{ path .name } :{ source_name } : legacy public client name remains" )
152195
153196
154- def _check_sdist (path : Path , expected_version : str ) -> None :
197+ def _check_sdist (path : Path , expected_version : str , expected_description : str ) -> None :
155198 expected_root = f"cometapi-{ expected_version } "
156199 if path .name != f"{ expected_root } .tar.gz" :
157200 raise CheckError (f"{ path .name } : expected sdist filename { expected_root } .tar.gz" )
@@ -182,7 +225,12 @@ def _check_sdist(path: Path, expected_version: str) -> None:
182225 stream = archive .extractfile (metadata_members [0 ])
183226 if stream is None :
184227 raise CheckError (f"{ path .name } : cannot read PKG-INFO" )
185- _check_metadata (stream .read (), f"{ path .name } :PKG-INFO" , expected_version )
228+ check_metadata (
229+ stream .read (),
230+ f"{ path .name } :PKG-INFO" ,
231+ expected_version ,
232+ expected_description ,
233+ )
186234
187235
188236def _artifacts (arguments : list [str ]) -> list [Path ]:
@@ -206,12 +254,16 @@ def main() -> int:
206254 parser .add_argument ("--expected-version" , default = read_project_version ())
207255 args = parser .parse_args ()
208256 expected_version = normalize_version (args .expected_version )
257+ try :
258+ expected_description = (PROJECT_ROOT / "README.md" ).read_text (encoding = "utf-8" )
259+ except (OSError , UnicodeError ) as exc :
260+ raise CheckError (f"cannot read source README.md: { exc } " ) from exc
209261 paths = _artifacts (args .artifacts )
210262 for path in paths :
211263 if path .suffix == ".whl" :
212- _check_wheel (path , expected_version )
264+ _check_wheel (path , expected_version , expected_description )
213265 else :
214- _check_sdist (path , expected_version )
266+ _check_sdist (path , expected_version , expected_description )
215267 print (f"{ sha256_file (path )} { path } " )
216268 print (f"artifact checks passed for cometapi { expected_version } " )
217269 return 0
0 commit comments