Skip to content

Commit 5eb5ea1

Browse files
authored
refactor: identifiers in a file (#511)
* refactor: identifiers in a file * chore: more typing * refactor: PlatStr -> PlatformName * refactor: load in file, use importlib.resources * refactor: change toml structure * refactor: use common Traversable * fix: ensure reasonable version of importlib_resources * style: fix extra line
1 parent 635b226 commit 5eb5ea1

File tree

9 files changed

+180
-92
lines changed

9 files changed

+180
-92
lines changed

cibuildwheel/__main__.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import cibuildwheel.macos
1313
import cibuildwheel.windows
1414
from cibuildwheel.environment import EnvironmentParseError, parse_environment
15+
from cibuildwheel.typing import PLATFORMS, PlatformName, assert_never
1516
from cibuildwheel.util import (
1617
Architecture,
1718
BuildOptions,
@@ -46,6 +47,8 @@ def get_option_from_environment(option_name: str, platform: Optional[str] = None
4647

4748

4849
def main() -> None:
50+
platform: PlatformName
51+
4952
parser = argparse.ArgumentParser(
5053
description='Build wheels for all the platforms.',
5154
epilog='''
@@ -120,15 +123,21 @@ def main() -> None:
120123
file=sys.stderr)
121124
exit(2)
122125

126+
if platform not in PLATFORMS:
127+
print(f'cibuildwheel: Unsupported platform: {platform}', file=sys.stderr)
128+
exit(2)
129+
123130
package_dir = Path(args.package_dir)
124131
output_dir = Path(args.output_dir)
125132

126133
if platform == 'linux':
127134
repair_command_default = 'auditwheel repair -w {dest_dir} {wheel}'
128135
elif platform == 'macos':
129136
repair_command_default = 'delocate-listdeps {wheel} && delocate-wheel --require-archs x86_64 -w {dest_dir} {wheel}'
130-
else:
137+
elif platform == 'windows':
131138
repair_command_default = ''
139+
else:
140+
assert_never(platform)
132141

133142
build_config, skip_config = os.environ.get('CIBW_BUILD', '*'), os.environ.get('CIBW_SKIP', '')
134143
environment_config = get_option_from_environment('CIBW_ENVIRONMENT', platform=platform, default='')
@@ -248,8 +257,7 @@ def main() -> None:
248257
elif platform == 'macos':
249258
cibuildwheel.macos.build(build_options)
250259
else:
251-
print(f'cibuildwheel: Unsupported platform: {platform}', file=sys.stderr)
252-
exit(2)
260+
assert_never(platform)
253261

254262

255263
def detect_obsolete_options() -> None:
@@ -302,6 +310,7 @@ def print_preamble(platform: str, build_options: BuildOptions) -> None:
302310
def print_build_identifiers(
303311
platform: str, build_selector: BuildSelector, architectures: Set[Architecture]
304312
) -> None:
313+
305314
python_configurations: List[Any] = []
306315
if platform == 'linux':
307316
python_configurations = cibuildwheel.linux.get_python_configurations(build_selector, architectures)

cibuildwheel/linux.py

Lines changed: 10 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
allowed_architectures_check,
1616
get_build_verbosity_extra_flags,
1717
prepare_command,
18+
read_python_configs,
19+
resources_dir,
1820
)
1921

2022

@@ -29,42 +31,13 @@ def path(self) -> PurePath:
2931

3032

3133
def get_python_configurations(
32-
build_selector: BuildSelector, architectures: Set[Architecture]
34+
build_selector: BuildSelector,
35+
architectures: Set[Architecture]
3336
) -> List[PythonConfiguration]:
34-
python_configurations = [
35-
PythonConfiguration(version='2.7', identifier='cp27-manylinux_x86_64', path_str='/opt/python/cp27-cp27m'),
36-
PythonConfiguration(version='2.7', identifier='cp27-manylinux_x86_64', path_str='/opt/python/cp27-cp27mu'),
37-
PythonConfiguration(version='3.5', identifier='cp35-manylinux_x86_64', path_str='/opt/python/cp35-cp35m'),
38-
PythonConfiguration(version='3.6', identifier='cp36-manylinux_x86_64', path_str='/opt/python/cp36-cp36m'),
39-
PythonConfiguration(version='3.7', identifier='cp37-manylinux_x86_64', path_str='/opt/python/cp37-cp37m'),
40-
PythonConfiguration(version='3.8', identifier='cp38-manylinux_x86_64', path_str='/opt/python/cp38-cp38'),
41-
PythonConfiguration(version='3.9', identifier='cp39-manylinux_x86_64', path_str='/opt/python/cp39-cp39'),
42-
PythonConfiguration(version='2.7', identifier='cp27-manylinux_i686', path_str='/opt/python/cp27-cp27m'),
43-
PythonConfiguration(version='2.7', identifier='cp27-manylinux_i686', path_str='/opt/python/cp27-cp27mu'),
44-
PythonConfiguration(version='3.5', identifier='cp35-manylinux_i686', path_str='/opt/python/cp35-cp35m'),
45-
PythonConfiguration(version='3.6', identifier='cp36-manylinux_i686', path_str='/opt/python/cp36-cp36m'),
46-
PythonConfiguration(version='3.7', identifier='cp37-manylinux_i686', path_str='/opt/python/cp37-cp37m'),
47-
PythonConfiguration(version='3.8', identifier='cp38-manylinux_i686', path_str='/opt/python/cp38-cp38'),
48-
PythonConfiguration(version='3.9', identifier='cp39-manylinux_i686', path_str='/opt/python/cp39-cp39'),
49-
PythonConfiguration(version='2.7', identifier='pp27-manylinux_x86_64', path_str='/opt/python/pp27-pypy_73'),
50-
PythonConfiguration(version='3.6', identifier='pp36-manylinux_x86_64', path_str='/opt/python/pp36-pypy36_pp73'),
51-
PythonConfiguration(version='3.7', identifier='pp37-manylinux_x86_64', path_str='/opt/python/pp37-pypy37_pp73'),
52-
PythonConfiguration(version='3.5', identifier='cp35-manylinux_aarch64', path_str='/opt/python/cp35-cp35m'),
53-
PythonConfiguration(version='3.6', identifier='cp36-manylinux_aarch64', path_str='/opt/python/cp36-cp36m'),
54-
PythonConfiguration(version='3.7', identifier='cp37-manylinux_aarch64', path_str='/opt/python/cp37-cp37m'),
55-
PythonConfiguration(version='3.8', identifier='cp38-manylinux_aarch64', path_str='/opt/python/cp38-cp38'),
56-
PythonConfiguration(version='3.9', identifier='cp39-manylinux_aarch64', path_str='/opt/python/cp39-cp39'),
57-
PythonConfiguration(version='3.5', identifier='cp35-manylinux_ppc64le', path_str='/opt/python/cp35-cp35m'),
58-
PythonConfiguration(version='3.6', identifier='cp36-manylinux_ppc64le', path_str='/opt/python/cp36-cp36m'),
59-
PythonConfiguration(version='3.7', identifier='cp37-manylinux_ppc64le', path_str='/opt/python/cp37-cp37m'),
60-
PythonConfiguration(version='3.8', identifier='cp38-manylinux_ppc64le', path_str='/opt/python/cp38-cp38'),
61-
PythonConfiguration(version='3.9', identifier='cp39-manylinux_ppc64le', path_str='/opt/python/cp39-cp39'),
62-
PythonConfiguration(version='3.5', identifier='cp35-manylinux_s390x', path_str='/opt/python/cp35-cp35m'),
63-
PythonConfiguration(version='3.6', identifier='cp36-manylinux_s390x', path_str='/opt/python/cp36-cp36m'),
64-
PythonConfiguration(version='3.7', identifier='cp37-manylinux_s390x', path_str='/opt/python/cp37-cp37m'),
65-
PythonConfiguration(version='3.8', identifier='cp38-manylinux_s390x', path_str='/opt/python/cp38-cp38'),
66-
PythonConfiguration(version='3.9', identifier='cp39-manylinux_s390x', path_str='/opt/python/cp39-cp39'),
67-
]
37+
38+
full_python_configs = read_python_configs('linux')
39+
40+
python_configurations = [PythonConfiguration(**item) for item in full_python_configs]
6841

6942
# return all configurations whose arch is in our `architectures` set,
7043
# and match the build/skip rules
@@ -76,7 +49,7 @@ def get_python_configurations(
7649

7750

7851
def build(options: BuildOptions) -> None:
79-
allowed_architectures_check("linux", options)
52+
allowed_architectures_check('linux', options)
8053

8154
try:
8255
subprocess.check_output(['docker', '--version'])
@@ -136,7 +109,7 @@ def build(options: BuildOptions) -> None:
136109
if config.identifier.startswith("pp"):
137110
# Patch PyPy to make sure headers get installed into a venv
138111
patch_version = '_27' if config.version == '2.7' else ''
139-
patch_path = Path(__file__).absolute().parent / 'resources' / f'pypy_venv{patch_version}.patch'
112+
patch_path = resources_dir / f'pypy_venv{patch_version}.patch'
140113
patch_docker_path = PurePath('/pypy_venv.patch')
141114
docker.copy_into(patch_path, patch_docker_path)
142115
try:

cibuildwheel/macos.py

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
get_pip_script,
2121
install_certifi_script,
2222
prepare_command,
23+
read_python_configs,
24+
resources_dir,
2325
)
2426

2527

@@ -39,20 +41,12 @@ class PythonConfiguration(NamedTuple):
3941
url: str
4042

4143

42-
def get_python_configurations(build_selector: BuildSelector) -> List[PythonConfiguration]:
43-
python_configurations = [
44-
# CPython
45-
PythonConfiguration(version='2.7', identifier='cp27-macosx_x86_64', url='https://www.python.org/ftp/python/2.7.18/python-2.7.18-macosx10.9.pkg'),
46-
PythonConfiguration(version='3.5', identifier='cp35-macosx_x86_64', url='https://www.python.org/ftp/python/3.5.4/python-3.5.4-macosx10.6.pkg'),
47-
PythonConfiguration(version='3.6', identifier='cp36-macosx_x86_64', url='https://www.python.org/ftp/python/3.6.8/python-3.6.8-macosx10.9.pkg'),
48-
PythonConfiguration(version='3.7', identifier='cp37-macosx_x86_64', url='https://www.python.org/ftp/python/3.7.9/python-3.7.9-macosx10.9.pkg'),
49-
PythonConfiguration(version='3.8', identifier='cp38-macosx_x86_64', url='https://www.python.org/ftp/python/3.8.7/python-3.8.7-macosx10.9.pkg'),
50-
PythonConfiguration(version='3.9', identifier='cp39-macosx_x86_64', url='https://www.python.org/ftp/python/3.9.1/python-3.9.1-macosx10.9.pkg'),
51-
# PyPy
52-
PythonConfiguration(version='2.7', identifier='pp27-macosx_x86_64', url='https://downloads.python.org/pypy/pypy2.7-v7.3.3-osx64.tar.bz2'),
53-
PythonConfiguration(version='3.6', identifier='pp36-macosx_x86_64', url='https://downloads.python.org/pypy/pypy3.6-v7.3.3-osx64.tar.bz2'),
54-
PythonConfiguration(version='3.7', identifier='pp37-macosx_x86_64', url='https://downloads.python.org/pypy/pypy3.7-v7.3.3-osx64.tar.bz2'),
55-
]
44+
def get_python_configurations(
45+
build_selector: BuildSelector) -> List[PythonConfiguration]:
46+
47+
full_python_configs = read_python_configs('macos')
48+
49+
python_configurations = [PythonConfiguration(**item) for item in full_python_configs]
5650

5751
# skip builds as required
5852
return [c for c in python_configurations if build_selector(c.identifier)]
@@ -115,7 +109,7 @@ def install_pypy(version: str, url: str) -> Path:
115109
call(['tar', '-C', '/tmp', '-xf', downloaded_tar_bz2])
116110
# Patch PyPy to make sure headers get installed into a venv
117111
patch_version = '_27' if version == '2.7' else ''
118-
patch_path = Path(__file__).absolute().parent / 'resources' / f'pypy_venv{patch_version}.patch'
112+
patch_path = resources_dir / f'pypy_venv{patch_version}.patch'
119113
call(['patch', '--force', '-p1', '-d', installation_path, '-i', patch_path])
120114

121115
installation_bin_path = installation_path / 'bin'
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
[linux]
2+
python_configurations = [
3+
{ identifier = "cp27-manylinux_x86_64", version = "2.7", path_str = "/opt/python/cp27-cp27m" },
4+
{ identifier = "cp27-manylinux_x86_64", version = "2.7", path_str = "/opt/python/cp27-cp27mu" },
5+
{ identifier = "cp35-manylinux_x86_64", version = "3.5", path_str = "/opt/python/cp35-cp35m" },
6+
{ identifier = "cp36-manylinux_x86_64", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
7+
{ identifier = "cp37-manylinux_x86_64", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
8+
{ identifier = "cp38-manylinux_x86_64", version = "3.8", path_str = "/opt/python/cp38-cp38" },
9+
{ identifier = "cp39-manylinux_x86_64", version = "3.9", path_str = "/opt/python/cp39-cp39" },
10+
{ identifier = "cp27-manylinux_i686", version = "2.7", path_str = "/opt/python/cp27-cp27m" },
11+
{ identifier = "cp27-manylinux_i686", version = "2.7", path_str = "/opt/python/cp27-cp27mu" },
12+
{ identifier = "cp35-manylinux_i686", version = "3.5", path_str = "/opt/python/cp35-cp35m" },
13+
{ identifier = "cp36-manylinux_i686", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
14+
{ identifier = "cp37-manylinux_i686", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
15+
{ identifier = "cp38-manylinux_i686", version = "3.8", path_str = "/opt/python/cp38-cp38" },
16+
{ identifier = "cp39-manylinux_i686", version = "3.9", path_str = "/opt/python/cp39-cp39" },
17+
{ identifier = "pp27-manylinux_x86_64", version = "2.7", path_str = "/opt/python/pp27-pypy_73" },
18+
{ identifier = "pp36-manylinux_x86_64", version = "3.6", path_str = "/opt/python/pp36-pypy36_pp73" },
19+
{ identifier = "pp37-manylinux_x86_64", version = "3.7", path_str = "/opt/python/pp37-pypy37_pp73" },
20+
{ identifier = "cp35-manylinux_aarch64", version = "3.5", path_str = "/opt/python/cp35-cp35m" },
21+
{ identifier = "cp36-manylinux_aarch64", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
22+
{ identifier = "cp37-manylinux_aarch64", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
23+
{ identifier = "cp38-manylinux_aarch64", version = "3.8", path_str = "/opt/python/cp38-cp38" },
24+
{ identifier = "cp39-manylinux_aarch64", version = "3.9", path_str = "/opt/python/cp39-cp39" },
25+
{ identifier = "cp35-manylinux_ppc64le", version = "3.5", path_str = "/opt/python/cp35-cp35m" },
26+
{ identifier = "cp36-manylinux_ppc64le", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
27+
{ identifier = "cp37-manylinux_ppc64le", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
28+
{ identifier = "cp38-manylinux_ppc64le", version = "3.8", path_str = "/opt/python/cp38-cp38" },
29+
{ identifier = "cp39-manylinux_ppc64le", version = "3.9", path_str = "/opt/python/cp39-cp39" },
30+
{ identifier = "cp35-manylinux_s390x", version = "3.5", path_str = "/opt/python/cp35-cp35m" },
31+
{ identifier = "cp36-manylinux_s390x", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
32+
{ identifier = "cp37-manylinux_s390x", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
33+
{ identifier = "cp38-manylinux_s390x", version = "3.8", path_str = "/opt/python/cp38-cp38" },
34+
{ identifier = "cp39-manylinux_s390x", version = "3.9", path_str = "/opt/python/cp39-cp39" },
35+
]
36+
37+
[macos]
38+
python_configurations = [
39+
{ identifier = "cp27-macosx_x86_64", version = "2.7", url = "https://www.python.org/ftp/python/2.7.18/python-2.7.18-macosx10.9.pkg" },
40+
{ identifier = "cp35-macosx_x86_64", version = "3.5", url = "https://www.python.org/ftp/python/3.5.4/python-3.5.4-macosx10.6.pkg" },
41+
{ identifier = "cp36-macosx_x86_64", version = "3.6", url = "https://www.python.org/ftp/python/3.6.8/python-3.6.8-macosx10.9.pkg" },
42+
{ identifier = "cp37-macosx_x86_64", version = "3.7", url = "https://www.python.org/ftp/python/3.7.9/python-3.7.9-macosx10.9.pkg" },
43+
{ identifier = "cp38-macosx_x86_64", version = "3.8", url = "https://www.python.org/ftp/python/3.8.7/python-3.8.7-macosx10.9.pkg" },
44+
{ identifier = "cp39-macosx_x86_64", version = "3.9", url = "https://www.python.org/ftp/python/3.9.1/python-3.9.1-macosx10.9.pkg" },
45+
{ identifier = "pp27-macosx_x86_64", version = "2.7", url = "https://downloads.python.org/pypy/pypy2.7-v7.3.3-osx64.tar.bz2" },
46+
{ identifier = "pp36-macosx_x86_64", version = "3.6", url = "https://downloads.python.org/pypy/pypy3.6-v7.3.3-osx64.tar.bz2" },
47+
{ identifier = "pp37-macosx_x86_64", version = "3.7", url = "https://downloads.python.org/pypy/pypy3.7-v7.3.3-osx64.tar.bz2" },
48+
]
49+
50+
[windows]
51+
python_configurations = [
52+
{ identifier = "cp27-win32", version = "2.7.18", arch = "32" },
53+
{ identifier = "cp27-win_amd64", version = "2.7.18", arch = "64" },
54+
{ identifier = "cp35-win32", version = "3.5.4", arch = "32" },
55+
{ identifier = "cp35-win_amd64", version = "3.5.4", arch = "64" },
56+
{ identifier = "cp36-win32", version = "3.6.8", arch = "32" },
57+
{ identifier = "cp36-win_amd64", version = "3.6.8", arch = "64" },
58+
{ identifier = "cp37-win32", version = "3.7.9", arch = "32" },
59+
{ identifier = "cp37-win_amd64", version = "3.7.9", arch = "64" },
60+
{ identifier = "cp38-win32", version = "3.8.7", arch = "32" },
61+
{ identifier = "cp38-win_amd64", version = "3.8.7", arch = "64" },
62+
{ identifier = "cp39-win32", version = "3.9.1", arch = "32" },
63+
{ identifier = "cp39-win_amd64", version = "3.9.1", arch = "64" },
64+
{ identifier = "pp27-win32", version = "2.7", arch = "32", url = "https://downloads.python.org/pypy/pypy2.7-v7.3.3-win32.zip" },
65+
{ identifier = "pp36-win32", version = "3.6", arch = "32", url = "https://downloads.python.org/pypy/pypy3.6-v7.3.3-win32.zip" },
66+
{ identifier = "pp37-win32", version = "3.7", arch = "32", url = "https://downloads.python.org/pypy/pypy3.7-v7.3.3-win32.zip" },
67+
]

cibuildwheel/typing.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,25 @@
11
import os
22
import subprocess
3-
from typing import TYPE_CHECKING, Union
3+
import sys
4+
from typing import TYPE_CHECKING, NoReturn, Set, Union
5+
6+
if sys.version_info < (3, 8):
7+
from typing_extensions import Final, Literal
8+
else:
9+
from typing import Final, Literal
10+
411

512
if TYPE_CHECKING:
613
PopenBytes = subprocess.Popen[bytes]
714
PathOrStr = Union[str, os.PathLike[str]]
815
else:
916
PopenBytes = subprocess.Popen
1017
PathOrStr = Union[str, "os.PathLike[str]"]
18+
19+
20+
PlatformName = Literal["linux", "macos", "windows"]
21+
PLATFORMS: Final[Set[PlatformName]] = {"linux", "macos", "windows"}
22+
23+
24+
def assert_never(value: NoReturn) -> NoReturn:
25+
assert False, f'Unhandled value: {value} ({type(value).__name__})' # noqa: B011

cibuildwheel/util.py

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,20 @@
1313
from typing import Dict, List, NamedTuple, Optional, Set
1414

1515
import certifi
16+
import toml
1617

1718
from .environment import ParsedEnvironment
18-
from .typing import PathOrStr
19+
from .typing import PathOrStr, PlatformName
1920

20-
if sys.version_info < (3, 8):
21-
from typing_extensions import Literal
21+
if sys.version_info < (3, 9):
22+
from importlib_resources import files
2223
else:
23-
from typing import Literal
24+
from importlib.resources import files
25+
26+
27+
resources_dir = files('cibuildwheel') / 'resources'
28+
get_pip_script = resources_dir / 'get-pip.py'
29+
install_certifi_script = resources_dir / "install_certifi.py"
2430

2531

2632
def prepare_command(command: str, **kwargs: PathOrStr) -> str:
@@ -42,6 +48,13 @@ def get_build_verbosity_extra_flags(level: int) -> List[str]:
4248
return []
4349

4450

51+
def read_python_configs(config: PlatformName) -> List[Dict[str, str]]:
52+
input_file = resources_dir / 'build-platforms.toml'
53+
loaded_file = toml.load(input_file)
54+
results: List[Dict[str, str]] = list(loaded_file[config]['python_configurations'])
55+
return results
56+
57+
4558
class BuildSelector:
4659
def __init__(self, build_config: str, skip_config: str):
4760
self.build_patterns = build_config.split()
@@ -151,7 +164,7 @@ def __lt__(self, other: "Architecture") -> bool:
151164
return self.value < other.value
152165

153166
@staticmethod
154-
def parse_config(config: str, platform: str) -> 'Set[Architecture]':
167+
def parse_config(config: str, platform: PlatformName) -> 'Set[Architecture]':
155168
result = set()
156169
for arch_str in re.split(r'[\s,]+', config):
157170
if arch_str == 'auto':
@@ -161,7 +174,7 @@ def parse_config(config: str, platform: str) -> 'Set[Architecture]':
161174
return result
162175

163176
@staticmethod
164-
def auto_archs(platform: str) -> 'Set[Architecture]':
177+
def auto_archs(platform: PlatformName) -> 'Set[Architecture]':
165178
native_architecture = Architecture(platform_module.machine())
166179
result = {native_architecture}
167180
if platform == 'linux' and native_architecture == Architecture.x86_64:
@@ -190,11 +203,6 @@ class BuildOptions(NamedTuple):
190203
build_verbosity: int
191204

192205

193-
resources_dir = Path(__file__).resolve().parent / 'resources'
194-
get_pip_script = resources_dir / 'get-pip.py'
195-
install_certifi_script = resources_dir / "install_certifi.py"
196-
197-
198206
class NonPlatformWheelError(Exception):
199207
def __init__(self) -> None:
200208
message = textwrap.dedent('''
@@ -255,7 +263,7 @@ def detect_ci_provider() -> Optional[CIProvider]:
255263

256264

257265
def allowed_architectures_check(
258-
name: Literal['linux', 'macos', 'windows'],
266+
name: PlatformName,
259267
options: BuildOptions,
260268
) -> None:
261269

0 commit comments

Comments
 (0)