11import requests
2+ from requests .adapters import HTTPAdapter
3+ from requests .packages .urllib3 .util .retry import Retry
24import json
35import base64
46import hashlib
57import os
68
79
10+ def create_session_with_retries ():
11+ session = requests .Session ()
12+ retry_strategy = Retry (
13+ total = 5 ,
14+ backoff_factor = 1 ,
15+ status_forcelist = list (range (500 , 600 )), # All 5xx errors
16+ allowed_methods = ["GET" , "POST" , "PUT" , "DELETE" , "HEAD" , "OPTIONS" , "TRACE" ],
17+ )
18+ adapter = HTTPAdapter (max_retries = retry_strategy )
19+ session .mount ("http://" , adapter )
20+ session .mount ("https://" , adapter )
21+ return session
22+
23+
824def source (version ):
925 return f"https://www.python.org/ftp/python/{ version } /Python-{ version } .tgz"
1026
@@ -26,7 +42,7 @@ def get_versions():
2642 return d
2743
2844
29- def get_all_releases (response , versions ):
45+ def get_all_releases (response , versions , session ):
3046 for entry in response .json ():
3147 cycle = entry ["cycle" ]
3248 latest_version = entry ["latest" ]
@@ -59,7 +75,7 @@ def get_all_releases(response, versions):
5975 else :
6076 url = source (version )
6177 print (f"Downloading { url } " )
62- response = requests .get (url )
78+ response = session .get (url )
6379 response .raise_for_status ()
6480 versions ["releases" ][version ] = {
6581 "hash" : calculate_sha256 (response .content ),
@@ -68,7 +84,7 @@ def get_all_releases(response, versions):
6884 return versions
6985
7086
71- def get_activestate_releases (response , versions ):
87+ def get_activestate_releases (response , versions , session ):
7288 for entry in response .json ():
7389 version = entry ["tag_name" ].lstrip ("v" )
7490 cycle = "." .join (version .split ("." )[:2 ])
@@ -84,7 +100,7 @@ def get_activestate_releases(response, versions):
84100 else :
85101 url = activestate_source (version )
86102 print (f"Downloading { url } " )
87- response = requests .get (url )
103+ response = session .get (url )
88104 response .raise_for_status ()
89105 versions ["releases" ][version ] = {
90106 "hash" : calculate_sha256 (response .content ),
@@ -99,23 +115,24 @@ def calculate_sha256(contents):
99115
100116if __name__ == "__main__" :
101117 versions = get_versions ()
118+ session = create_session_with_retries ()
102119
103120 # TODO: pypy: https://downloads.python.org/pypy/versions.json
104- response = requests .get ("https://endoflife.date/api/python.json" )
121+ response = session .get ("https://endoflife.date/api/python.json" )
105122
106- versions = get_all_releases (response , versions )
123+ versions = get_all_releases (response , versions , session )
107124
108125 headers = {}
109126 if gh_token := os .getenv ("GH_TOKEN" ):
110127 headers ["Authorization" ] = f"Bearer { gh_token } "
111128
112- activestate_response = requests .get (
129+ activestate_response = session .get (
113130 "https://api.github.com/repos/ActiveState/cpython/releases" , headers = headers
114131 )
115132
116133 activestate_response .raise_for_status ()
117134
118- versions = get_activestate_releases (activestate_response , versions )
135+ versions = get_activestate_releases (activestate_response , versions , session )
119136
120137 with open ("versions.json" , "w" ) as f :
121138 json .dump (versions , f , indent = 4 )
0 commit comments