15
15
16
16
* Put an AUTH_INFO variable containing "username:api_key" in your environment.
17
17
18
- * Call this script as "python add-to-pydotorg .py RELEASE".
18
+ * Call this script as "python add_to_pydotorg .py RELEASE".
19
19
20
20
Each call will remove all previous file objects, so you can call the script
21
21
multiple times.
30
30
import subprocess
31
31
import sys
32
32
from os import path
33
+ from typing import Any , Generator
33
34
34
35
import requests
35
36
36
37
37
38
# Copied from release.py
38
- def error (* msgs ) :
39
+ def error (* msgs : Any ) -> None :
39
40
print ("**ERROR**" , file = sys .stderr )
40
41
for msg in msgs :
41
42
print (msg , file = sys .stderr )
42
43
sys .exit (1 )
43
44
44
45
45
46
# 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 :
47
50
if shell :
48
51
cmd = " " .join (cmd )
49
52
if not silent :
@@ -89,7 +92,9 @@ def run_cmd(cmd, silent=False, shell=True, **kwargs):
89
92
}
90
93
91
94
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 ]]]:
93
98
v = minor_version_tuple (release )
94
99
rx = re .compile
95
100
# value is (file "name", OS id, download button, file "description").
@@ -157,54 +162,59 @@ def get_file_descriptions(release):
157
162
]
158
163
159
164
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 :
167
166
return base_version (release ).replace ("." , "" ) + (
168
167
"-" + release [len (base_version (release )) :]
169
168
if release [len (base_version (release )) :]
170
169
else ""
171
170
)
172
171
173
172
174
- def sigfile_for (release , rfile ) :
173
+ def sigfile_for (release : str , rfile : str ) -> str :
175
174
return download_root + f"{ release } /{ rfile } .asc"
176
175
177
176
178
- def md5sum_for (release , rfile ) :
177
+ def md5sum_for (release : str , rfile : str ) -> str :
179
178
return hashlib .md5 (
180
179
open (ftp_root + base_version (release ) + "/" + rfile , "rb" ).read ()
181
180
).hexdigest ()
182
181
183
182
184
- def filesize_for (release , rfile ) :
183
+ def filesize_for (release : str , rfile : str ) -> int :
185
184
return path .getsize (ftp_root + base_version (release ) + "/" + rfile )
186
185
187
186
188
- def make_slug (text ) :
187
+ def make_slug (text : str ) -> str :
189
188
return re .sub ("[^a-zA-Z0-9_-]" , "" , text .replace (" " , "-" ))
190
189
191
190
192
- def base_version (release ) :
191
+ def base_version (release : str ) -> str :
193
192
m = tag_cre .match (release )
193
+ assert m is not None , f"Invalid release: { release } "
194
194
return "." .join (m .groups ()[:3 ])
195
195
196
196
197
- def minor_version (release ) :
197
+ def minor_version (release : str ) -> str :
198
198
m = tag_cre .match (release )
199
+ assert m is not None , f"Invalid release: { release } "
199
200
return "." .join (m .groups ()[:2 ])
200
201
201
202
202
- def minor_version_tuple (release ) :
203
+ def minor_version_tuple (release : str ) -> tuple [ int , int ] :
203
204
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 ]:
208
218
"""Return a dictionary with all needed fields for a ReleaseFile object."""
209
219
d = {
210
220
"name" : file_desc ,
@@ -243,7 +253,7 @@ def build_file_dict(release, rfile, rel_pk, file_desc, os_pk, add_download, add_
243
253
return d
244
254
245
255
246
- def list_files (release ) :
256
+ def list_files (release : str ) -> Generator [ tuple [ str , str , int , bool , str ], None , None ] :
247
257
"""List all of the release's download files."""
248
258
reldir = base_version (release )
249
259
for rfile in os .listdir (path .join (ftp_root , reldir )):
@@ -279,7 +289,7 @@ def list_files(release):
279
289
continue
280
290
281
291
282
- def query_object (objtype , ** params ) :
292
+ def query_object (objtype : str , ** params : Any ) -> int :
283
293
"""Find an API object by query parameters."""
284
294
uri = base_url + f"downloads/{ objtype } /"
285
295
uri += "?" + "&" .join (f"{ k } ={ v } " for k , v in params .items ())
@@ -290,7 +300,7 @@ def query_object(objtype, **params):
290
300
return int (obj ["resource_uri" ].strip ("/" ).split ("/" )[- 1 ])
291
301
292
302
293
- def post_object (objtype , datadict ) :
303
+ def post_object (objtype : str , datadict : dict [ str , Any ]) -> int :
294
304
"""Create a new API object."""
295
305
resp = requests .post (
296
306
base_url + "downloads/" + objtype + "/" ,
@@ -311,13 +321,15 @@ def post_object(objtype, datadict):
311
321
return pk
312
322
313
323
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 :
315
327
filenames = [
316
328
ftp_root + f"{ base_version (release )} /{ rfile } "
317
329
for rfile , file_desc , os_pk , add_download , add_desc in release_files
318
330
]
319
331
320
- def has_sigstore_signature (filename ) :
332
+ def has_sigstore_signature (filename : str ) -> bool :
321
333
return os .path .exists (filename + ".sigstore" ) or (
322
334
os .path .exists (filename + ".sig" ) and os .path .exists (filename + ".crt" )
323
335
)
@@ -378,7 +390,7 @@ def has_sigstore_signature(filename):
378
390
)
379
391
380
392
381
- def main ():
393
+ def main () -> None :
382
394
rel = sys .argv [1 ]
383
395
print ("Querying python.org for release" , rel )
384
396
rel_pk = query_object ("release" , name = "Python+" + rel )
@@ -412,5 +424,5 @@ def main():
412
424
print (f"Done - { n } files added" )
413
425
414
426
415
- if not sys .flags .interactive :
427
+ if __name__ == "__main__" and not sys .flags .interactive :
416
428
main ()
0 commit comments