Skip to content

Commit 4373cd5

Browse files
committed
Add Python script to build wheels using cibuildwheel (#10096)
The contents are extracted from the current GitHub action definition: https://github.com/mypyc/mypy_mypyc-wheels/blob/master/.github/workflows/build.yml This is a fairly direct translation of the existing behavior. The behavior should be identical to the current workflow. The idea is to make this easier to maintain and easier to test locally. This should also make it easier to fix #10074.
1 parent 3b0b05d commit 4373cd5

File tree

1 file changed

+131
-0
lines changed

1 file changed

+131
-0
lines changed

misc/build_wheel.py

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
"""Script to build compiled binary wheels that can be uploaded to PyPI.
2+
3+
The main GitHub workflow where this script is used:
4+
https://github.com/mypyc/mypy_mypyc-wheels/blob/master/.github/workflows/build.yml
5+
6+
This uses cibuildwheel (https://github.com/joerick/cibuildwheel) to
7+
build the wheels.
8+
9+
Usage:
10+
11+
build_wheel_ci.py --python-version <python-version> \
12+
--output-dir <dir>
13+
14+
Wheels for the given Python version will be created in the given directory.
15+
Python version is in form "39".
16+
17+
This works on macOS, Windows and Linux.
18+
19+
You can test locally by using --extra-opts. macOS example:
20+
21+
mypy/misc/build_wheel_ci.py --python-version 39 --output-dir out --extra-opts="--platform macos"
22+
23+
Other supported values for platform: linux, windows
24+
"""
25+
26+
import argparse
27+
import os
28+
import subprocess
29+
import sys
30+
from typing import Dict
31+
32+
# Clang package we use on Linux
33+
LLVM_URL = 'https://github.com/mypyc/mypy_mypyc-wheels/releases/download/llvm/llvm-centos-5.tar.gz'
34+
35+
# Mypy repository root
36+
ROOT_DIR = os.path.dirname(os.path.dirname(__file__))
37+
38+
39+
def create_environ(python_version: str) -> Dict[str, str]:
40+
"""Set up environment variables for cibuildwheel."""
41+
env = os.environ.copy()
42+
43+
env['CIBW_BUILD'] = "cp{}-*".format(python_version)
44+
45+
# Don't build 32-bit wheels
46+
env['CIBW_SKIP'] = "*-manylinux_i686 *-win32"
47+
48+
env['CIBW_BUILD_VERBOSITY'] = '1'
49+
50+
# mypy's isolated builds don't specify the requirements mypyc needs, so install
51+
# requirements and don't use isolated builds. we need to use build-requirements.txt
52+
# with recent mypy commits to get stub packages needed for compilation.
53+
#
54+
# TODO: remove use of mypy-requirements.txt once we no longer need to support
55+
# building pre modular typeshed releases
56+
env['CIBW_BEFORE_BUILD'] = """
57+
pip install -r {package}/mypy-requirements.txt &&
58+
(pip install -r {package}/build-requirements.txt || true)
59+
""".replace('\n', ' ')
60+
61+
# download a copy of clang to use to compile on linux. this was probably built in 2018,
62+
# speeds up compilation 2x
63+
env['CIBW_BEFORE_BUILD_LINUX'] = """
64+
(cd / && curl -L %s | tar xzf -) &&
65+
pip install -r {package}/mypy-requirements.txt &&
66+
(pip install -r {package}/build-requirements.txt || true)
67+
""".replace('\n', ' ') % LLVM_URL
68+
69+
# the double negative is counterintuitive, https://github.com/pypa/pip/issues/5735
70+
env['CIBW_ENVIRONMENT'] = 'MYPY_USE_MYPYC=1 MYPYC_OPT_LEVEL=3 PIP_NO_BUILD_ISOLATION=no'
71+
env['CIBW_ENVIRONMENT_LINUX'] = (
72+
'MYPY_USE_MYPYC=1 MYPYC_OPT_LEVEL=3 PIP_NO_BUILD_ISOLATION=no ' +
73+
'CC=/opt/llvm/bin/clang'
74+
)
75+
env['CIBW_ENVIRONMENT_WINDOWS'] = (
76+
'MYPY_USE_MYPYC=1 MYPYC_OPT_LEVEL=2 PIP_NO_BUILD_ISOLATION=no'
77+
)
78+
79+
# lxml is slow to build wheels for new releases, so allow installing reqs to fail
80+
# if we failed to install lxml, we'll skip tests, but allow the build to succeed
81+
env['CIBW_BEFORE_TEST'] = (
82+
'pip install -r {project}/mypy/test-requirements.txt || true'
83+
)
84+
85+
# pytest looks for configuration files in the parent directories of where the tests live.
86+
# since we are trying to run the tests from their installed location, we copy those into
87+
# the venv. Ew ew ew.
88+
env['CIBW_TEST_COMMAND'] = """
89+
( ! pip list | grep lxml ) || (
90+
DIR=$(python -c 'import mypy, os; dn = os.path.dirname; print(dn(dn(mypy.__path__[0])))')
91+
&& TEST_DIR=$(python -c 'import mypy.test; print(mypy.test.__path__[0])')
92+
&& cp '{project}/mypy/pytest.ini' '{project}/mypy/conftest.py' $DIR
93+
&& MYPY_TEST_PREFIX='{project}/mypy' pytest $TEST_DIR
94+
)
95+
""".replace('\n', ' ')
96+
97+
# i ran into some flaky tests on windows, so only run testcheck. it looks like we
98+
# previously didn't run any tests on windows wheels, so this is a net win.
99+
env['CIBW_TEST_COMMAND_WINDOWS'] = """
100+
bash -c "
101+
( ! pip list | grep lxml ) || (
102+
DIR=$(python -c 'import mypy, os; dn = os.path.dirname; print(dn(dn(mypy.__path__[0])))')
103+
&& TEST_DIR=$(python -c 'import mypy.test; print(mypy.test.__path__[0])')
104+
&& cp '{project}/mypy/pytest.ini' '{project}/mypy/conftest.py' $DIR
105+
&& MYPY_TEST_PREFIX='{project}/mypy' pytest $TEST_DIR/testcheck.py
106+
)
107+
"
108+
""".replace('\n', ' ')
109+
return env
110+
111+
112+
def main() -> None:
113+
parser = argparse.ArgumentParser()
114+
parser.add_argument('--python-version', required=True, metavar='XY',
115+
help='Python version (e.g. 38 or 39)')
116+
parser.add_argument('--output-dir', required=True, metavar='DIR',
117+
help='Output directory for created wheels')
118+
parser.add_argument('--extra-opts', default='', metavar='OPTIONS',
119+
help='Extra options passed to cibuildwheel verbatim')
120+
args = parser.parse_args()
121+
python_version = args.python_version
122+
output_dir = args.output_dir
123+
extra_opts = args.extra_opts
124+
environ = create_environ(python_version)
125+
script = 'python -m cibuildwheel {} --output-dir {} {}'.format(extra_opts, output_dir,
126+
ROOT_DIR)
127+
subprocess.check_call(script, shell=True, env=environ)
128+
129+
130+
if __name__ == '__main__':
131+
main()

0 commit comments

Comments
 (0)