Skip to content

Commit 1e381e7

Browse files
committed
Update python versions as part of update_dependencies
1 parent 40ddede commit 1e381e7

File tree

3 files changed

+239
-2
lines changed

3 files changed

+239
-2
lines changed

.github/workflows/update-dependencies.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
python-version: 3.9
1515
architecture: x64
1616
- name: Install dependencies
17-
run: python -m pip install requests pip-tools
17+
run: python -m pip install requests pip-tools packaging>=20.8
1818
- name: Run update
1919
run: python ./bin/update_dependencies.py
2020
- name: Create Pull Request

bin/update_dependencies.py

+237-1
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
import shutil
66
import subprocess
77
import sys
8-
from collections import namedtuple
8+
from collections import namedtuple, defaultdict
99

10+
import packaging.version
1011
import requests
1112

1213
os.chdir(os.path.dirname(__file__))
@@ -117,3 +118,238 @@
117118

118119
with open('cibuildwheel/resources/pinned_docker_images.cfg', 'w') as f:
119120
config.write(f)
121+
122+
123+
# update Python on windows
124+
# CPython uses nugget
125+
# c.f. https://docs.microsoft.com/en-us/nuget/api/overview
126+
response = requests.get('https://api.nuget.org/v3/index.json')
127+
response.raise_for_status()
128+
api_info = response.json()
129+
for resource in api_info['resources']:
130+
if resource['@type'] == 'PackageBaseAddress/3.0.0':
131+
endpoint = resource['@id']
132+
cp_versions = {'64': [], '32': [] }
133+
for id, package in [('64', 'python'), ('32', 'pythonx86')]:
134+
response = requests.get(f'{endpoint}{package}/index.json')
135+
response.raise_for_status()
136+
cp_info = response.json()
137+
for version_str in cp_info['versions']:
138+
version = packaging.version.parse(version_str)
139+
if version.is_devrelease:
140+
continue
141+
cp_versions[id].append(version)
142+
cp_versions[id].sort()
143+
# PyPy is downloaded from https://downloads.python.org/pypy
144+
response = requests.get('https://downloads.python.org/pypy/versions.json')
145+
response.raise_for_status()
146+
pp_realeases = response.json()
147+
pp_versions = defaultdict(list)
148+
for pp_realease in pp_realeases:
149+
if pp_realease['pypy_version'] == 'nightly':
150+
continue
151+
version = packaging.version.parse(pp_realease['pypy_version'])
152+
python_version = packaging.version.parse(pp_realease['python_version'])
153+
python_version = f'{python_version.major}.{python_version.minor}'
154+
url = None
155+
for file in pp_realease['files']:
156+
if f"{file['platform']}-{file['arch']}" == 'win32-x86':
157+
url = file['download_url']
158+
break
159+
if url:
160+
pp_versions[python_version].append((version, url))
161+
162+
# load windows.py
163+
with open('cibuildwheel/windows.py', 'rt') as f:
164+
lines = f.readlines()
165+
# hugly search pattern, package configuration shall probably done otherwise if we want to do this
166+
for index, line in enumerate(lines):
167+
if 'PythonConfiguration' in line and 'url=None' in line and "identifier='cp3" in line:
168+
if "arch='32'" in line:
169+
id='32'
170+
else:
171+
id='64'
172+
start = line.index("version='") + 9
173+
end = line.index("'", start)
174+
current_version = packaging.version.parse(line[start:end])
175+
new_version = current_version
176+
max_version = packaging.version.parse(f'{current_version.major}.{current_version.minor + 1}')
177+
allow_prerelease = False
178+
if current_version.is_prerelease:
179+
release_version = packaging.version.parse(f'{current_version.major}.{current_version.minor}')
180+
if release_version in cp_versions[id]:
181+
new_version = release_version
182+
else:
183+
allow_prerelease = True
184+
max_version = release_version
185+
186+
for version in cp_versions[id]:
187+
if version.is_prerelease and not allow_prerelease:
188+
continue
189+
if version > new_version and version < max_version:
190+
new_version = version
191+
lines[index] = line[:start] + str(new_version) + line[end:]
192+
elif 'PythonConfiguration' in line and "identifier='pp" in line:
193+
start = line.index("version='") + 9
194+
end = line.index("'", start)
195+
id = line[start:end]
196+
start = line.index("url='") + 5
197+
end = line.index("'", start)
198+
current_url = line[start:end]
199+
_, current_version_str, _ = current_url.split('/')[-1].split('-')
200+
current_version = packaging.version.parse(current_version_str)
201+
new_version = current_version
202+
new_url = current_url
203+
max_version = packaging.version.parse(f'{current_version.major}.{current_version.minor + 1}')
204+
allow_prerelease = False
205+
if current_version.is_prerelease:
206+
release_version = packaging.version.parse(f'{current_version.major}.{current_version.minor}')
207+
found_release = False
208+
for version, url in pp_versions[id]:
209+
if release_version == version:
210+
new_version = release_version
211+
new_url = url
212+
found_release = True
213+
break
214+
if not found_release:
215+
allow_prerelease = True
216+
max_version = release_version
217+
218+
for version, url in pp_versions[id]:
219+
if version.is_prerelease and not allow_prerelease:
220+
continue
221+
if version > new_version and version < max_version:
222+
new_url = url
223+
new_version = version
224+
lines[index] = line[:start] + new_url + line[end:]
225+
226+
with open('cibuildwheel/windows.py', 'wt') as f:
227+
f.writelines(lines)
228+
229+
230+
# update Python on macOS
231+
# Cpython
232+
# c.f. https://github.com/python/pythondotorg/issues/1352
233+
response = requests.get('https://www.python.org/api/v2/downloads/release/?version=3&is_published=true')
234+
response.raise_for_status()
235+
release_info = response.json()
236+
cp_versions = {}
237+
for release in release_info:
238+
if not release['is_published']:
239+
continue
240+
parts = release['name'].split()
241+
if parts[0].lower() != 'python':
242+
continue
243+
assert len(parts) == 2
244+
version = packaging.version.parse(parts[1])
245+
cp_versions[release['resource_uri']] = [version]
246+
247+
response = requests.get('https://www.python.org/api/v2/downloads/release_file/?os=2')
248+
response.raise_for_status()
249+
file_info = response.json()
250+
251+
for file in file_info:
252+
key = file['release']
253+
if key not in cp_versions.keys():
254+
continue
255+
cp_versions[key].append(file['url'])
256+
257+
# PyPy is downloaded from https://downloads.python.org/pypy
258+
response = requests.get('https://downloads.python.org/pypy/versions.json')
259+
response.raise_for_status()
260+
pp_realeases = response.json()
261+
pp_versions = defaultdict(list)
262+
for pp_realease in pp_realeases:
263+
if pp_realease['pypy_version'] == 'nightly':
264+
continue
265+
version = packaging.version.parse(pp_realease['pypy_version'])
266+
python_version = packaging.version.parse(pp_realease['python_version'])
267+
python_version = f'{python_version.major}.{python_version.minor}'
268+
url = None
269+
for file in pp_realease['files']:
270+
if f"{file['platform']}-{file['arch']}" == 'darwin-x64':
271+
url = file['download_url']
272+
break
273+
if url:
274+
pp_versions[python_version].append((version, url))
275+
276+
# load macos.py
277+
with open('cibuildwheel/macos.py', 'rt') as f:
278+
lines = f.readlines()
279+
# hugly search pattern, package configuration shall probably done otherwise if we want to do this
280+
for index, line in enumerate(lines):
281+
if 'PythonConfiguration' in line and "identifier='cp3" in line:
282+
start = line.index("url='") + 5
283+
end = line.index("'", start)
284+
current_url = line[start:end]
285+
_, current_version_str, installer_kind = current_url.split('/')[-1].split('-')
286+
current_version = packaging.version.parse(current_version_str)
287+
new_version = current_version
288+
new_url = current_url
289+
max_version = packaging.version.parse(f'{current_version.major}.{current_version.minor + 1}')
290+
allow_prerelease = False
291+
if current_version.is_prerelease:
292+
release_version = packaging.version.parse(f'{current_version.major}.{current_version.minor}')
293+
found_release = False
294+
for version in cp_versions.values():
295+
if release_version == version[0]:
296+
# find installer
297+
found_url = False
298+
for url in version[1:]:
299+
if url.endswith(installer_kind):
300+
new_url = url
301+
found_url = True
302+
break
303+
if found_url:
304+
new_version = release_version
305+
found_release = True
306+
break
307+
if not found_release:
308+
allow_prerelease = True
309+
max_version = release_version
310+
311+
for version in cp_versions.values():
312+
if version[0].is_prerelease and not allow_prerelease:
313+
continue
314+
if version[0] > new_version and version[0] < max_version:
315+
# check installer kind
316+
for url in version[1:]:
317+
if url.endswith(installer_kind):
318+
new_url = url
319+
new_version = version[0]
320+
lines[index] = line[:start] + new_url + line[end:]
321+
elif 'PythonConfiguration' in line and "identifier='pp" in line:
322+
start = line.index("version='") + 9
323+
end = line.index("'", start)
324+
id = line[start:end]
325+
start = line.index("url='") + 5
326+
end = line.index("'", start)
327+
current_url = line[start:end]
328+
_, current_version_str, _ = current_url.split('/')[-1].split('-')
329+
current_version = packaging.version.parse(current_version_str)
330+
new_version = current_version
331+
new_url = current_url
332+
max_version = packaging.version.parse(f'{current_version.major}.{current_version.minor + 1}')
333+
allow_prerelease = False
334+
if current_version.is_prerelease:
335+
release_version = packaging.version.parse(f'{current_version.major}.{current_version.minor}')
336+
found_release = False
337+
for version, url in pp_versions[id]:
338+
if release_version == version:
339+
new_version = release_version
340+
new_url = url
341+
found_release = True
342+
break
343+
if not found_release:
344+
allow_prerelease = True
345+
max_version = release_version
346+
347+
for version, url in pp_versions[id]:
348+
if version.is_prerelease and not allow_prerelease:
349+
continue
350+
if version > new_version and version < max_version:
351+
new_url = url
352+
new_version = version
353+
lines[index] = line[:start] + new_url + line[end:]
354+
with open('cibuildwheel/macos.py', 'wt') as f:
355+
f.writelines(lines)

requirements-dev.txt

+1
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ mypy
1010
pyyaml
1111
pygithub
1212
typing-extensions
13+
packaging>=20.8

0 commit comments

Comments
 (0)