1515
1616* Put an AUTH_INFO variable containing "username:api_key" in your environment.
1717
18- * Call this script as "python add-to-pydotorg .py RELEASE".
18+ * Call this script as "python add_to_pydotorg .py RELEASE".
1919
2020 Each call will remove all previous file objects, so you can call the script
2121 multiple times.
3030import subprocess
3131import sys
3232from os import path
33+ from typing import Any , Generator
3334
3435import requests
3536
3637
3738# Copied from release.py
38- def error (* msgs ) :
39+ def error (* msgs : Any ) -> None :
3940 print ("**ERROR**" , file = sys .stderr )
4041 for msg in msgs :
4142 print (msg , file = sys .stderr )
4243 sys .exit (1 )
4344
4445
4546# Copied from release.py
46- def run_cmd (cmd , silent = False , shell = True , ** kwargs ):
47+ def run_cmd (
48+ cmd : list [str ] | str , silent : bool = False , shell : bool = False , ** kwargs : Any
49+ ) -> None :
4750 if shell :
4851 cmd = " " .join (cmd )
4952 if not silent :
@@ -89,7 +92,9 @@ def run_cmd(cmd, silent=False, shell=True, **kwargs):
8992}
9093
9194
92- def get_file_descriptions (release ):
95+ def get_file_descriptions (
96+ release : str ,
97+ ) -> list [tuple [re .Pattern [str ], tuple [str , int , bool , str ]]]:
9398 v = minor_version_tuple (release )
9499 rx = re .compile
95100 # value is (file "name", OS id, download button, file "description").
@@ -157,54 +162,59 @@ def get_file_descriptions(release):
157162 ]
158163
159164
160- def changelog_for (release ):
161- new_url = f"http://docs.python.org/release/{ release } /whatsnew/changelog.html"
162- if requests .head (new_url ).status_code != 200 :
163- return f"http://hg.python.org/cpython/file/v{ release } /Misc/NEWS"
164-
165-
166- def slug_for (release ):
165+ def slug_for (release : str ) -> str :
167166 return base_version (release ).replace ("." , "" ) + (
168167 "-" + release [len (base_version (release )) :]
169168 if release [len (base_version (release )) :]
170169 else ""
171170 )
172171
173172
174- def sigfile_for (release , rfile ) :
173+ def sigfile_for (release : str , rfile : str ) -> str :
175174 return download_root + f"{ release } /{ rfile } .asc"
176175
177176
178- def md5sum_for (release , rfile ) :
177+ def md5sum_for (release : str , rfile : str ) -> str :
179178 return hashlib .md5 (
180179 open (ftp_root + base_version (release ) + "/" + rfile , "rb" ).read ()
181180 ).hexdigest ()
182181
183182
184- def filesize_for (release , rfile ) :
183+ def filesize_for (release : str , rfile : str ) -> int :
185184 return path .getsize (ftp_root + base_version (release ) + "/" + rfile )
186185
187186
188- def make_slug (text ) :
187+ def make_slug (text : str ) -> str :
189188 return re .sub ("[^a-zA-Z0-9_-]" , "" , text .replace (" " , "-" ))
190189
191190
192- def base_version (release ) :
191+ def base_version (release : str ) -> str :
193192 m = tag_cre .match (release )
193+ assert m is not None , f"Invalid release: { release } "
194194 return "." .join (m .groups ()[:3 ])
195195
196196
197- def minor_version (release ) :
197+ def minor_version (release : str ) -> str :
198198 m = tag_cre .match (release )
199+ assert m is not None , f"Invalid release: { release } "
199200 return "." .join (m .groups ()[:2 ])
200201
201202
202- def minor_version_tuple (release ) :
203+ def minor_version_tuple (release : str ) -> tuple [ int , int ] :
203204 m = tag_cre .match (release )
204- return (int (m .groups ()[0 ]), int (m .groups ()[1 ]))
205-
206-
207- def build_file_dict (release , rfile , rel_pk , file_desc , os_pk , add_download , add_desc ):
205+ assert m is not None , f"Invalid release: { release } "
206+ return int (m .groups ()[0 ]), int (m .groups ()[1 ])
207+
208+
209+ def build_file_dict (
210+ release : str ,
211+ rfile : str ,
212+ rel_pk : int ,
213+ file_desc : str ,
214+ os_pk : int ,
215+ add_download : bool ,
216+ add_desc : str ,
217+ ) -> dict [str , Any ]:
208218 """Return a dictionary with all needed fields for a ReleaseFile object."""
209219 d = {
210220 "name" : file_desc ,
@@ -243,7 +253,7 @@ def build_file_dict(release, rfile, rel_pk, file_desc, os_pk, add_download, add_
243253 return d
244254
245255
246- def list_files (release ) :
256+ def list_files (release : str ) -> Generator [ tuple [ str , str , int , bool , str ], None , None ] :
247257 """List all of the release's download files."""
248258 reldir = base_version (release )
249259 for rfile in os .listdir (path .join (ftp_root , reldir )):
@@ -279,7 +289,7 @@ def list_files(release):
279289 continue
280290
281291
282- def query_object (objtype , ** params ) :
292+ def query_object (objtype : str , ** params : Any ) -> int :
283293 """Find an API object by query parameters."""
284294 uri = base_url + f"downloads/{ objtype } /"
285295 uri += "?" + "&" .join (f"{ k } ={ v } " for k , v in params .items ())
@@ -290,7 +300,7 @@ def query_object(objtype, **params):
290300 return int (obj ["resource_uri" ].strip ("/" ).split ("/" )[- 1 ])
291301
292302
293- def post_object (objtype , datadict ) :
303+ def post_object (objtype : str , datadict : dict [ str , Any ]) -> int :
294304 """Create a new API object."""
295305 resp = requests .post (
296306 base_url + "downloads/" + objtype + "/" ,
@@ -311,13 +321,15 @@ def post_object(objtype, datadict):
311321 return pk
312322
313323
314- def sign_release_files_with_sigstore (release , release_files ):
324+ def sign_release_files_with_sigstore (
325+ release : str , release_files : list [tuple [str , str , int , bool , str ]]
326+ ) -> None :
315327 filenames = [
316328 ftp_root + f"{ base_version (release )} /{ rfile } "
317329 for rfile , file_desc , os_pk , add_download , add_desc in release_files
318330 ]
319331
320- def has_sigstore_signature (filename ) :
332+ def has_sigstore_signature (filename : str ) -> bool :
321333 return os .path .exists (filename + ".sigstore" ) or (
322334 os .path .exists (filename + ".sig" ) and os .path .exists (filename + ".crt" )
323335 )
@@ -378,7 +390,7 @@ def has_sigstore_signature(filename):
378390 )
379391
380392
381- def main ():
393+ def main () -> None :
382394 rel = sys .argv [1 ]
383395 print ("Querying python.org for release" , rel )
384396 rel_pk = query_object ("release" , name = "Python+" + rel )
@@ -412,5 +424,5 @@ def main():
412424 print (f"Done - { n } files added" )
413425
414426
415- if not sys .flags .interactive :
427+ if __name__ == "__main__" and not sys .flags .interactive :
416428 main ()
0 commit comments