Merge remote-tracking branch 'origin/master' into macos-universal2

# Conflicts:
#	bin/sample_build.py
#	cibuildwheel/__main__.py
#	cibuildwheel/macos.py
#	cibuildwheel/util.py
#	cibuildwheel/windows.py
This commit is contained in:
Joe Rickerby
2021-01-23 13:28:06 +00:00
52 changed files with 1117 additions and 375 deletions
+1 -1
View File
@@ -1 +1 @@
__version__ = '1.7.4'
__version__ = '1.8.0'
+52 -20
View File
@@ -5,18 +5,20 @@ import textwrap
import traceback
from configparser import ConfigParser
from pathlib import Path
from typing import Any, Dict, List, Optional, Set, overload
from typing import Dict, List, Optional, Set, Union, overload
import cibuildwheel
import cibuildwheel.linux
import cibuildwheel.macos
import cibuildwheel.windows
from cibuildwheel.architecture import Architecture, allowed_architectures_check
from cibuildwheel.environment import EnvironmentParseError, parse_environment
from cibuildwheel.typing import PLATFORMS, PlatformName, assert_never
from cibuildwheel.util import (
Architecture,
BuildOptions,
BuildSelector,
DependencyConstraints,
TestSelector,
Unbuffered,
detect_ci_provider,
resources_dir,
@@ -46,6 +48,8 @@ def get_option_from_environment(option_name: str, platform: Optional[str] = None
def main() -> None:
platform: PlatformName
parser = argparse.ArgumentParser(
description='Build wheels for all the platforms.',
epilog='''
@@ -73,7 +77,7 @@ def main() -> None:
on this machine. Set this option to build an architecture
via emulation, for example, using binfmt_misc and QEMU.
Default: auto.
Choices: auto, {}
Choices: auto, native, all, {}
'''.format(", ".join(a.name for a in Architecture)))
parser.add_argument('--output-dir',
default=os.environ.get('CIBW_OUTPUT_DIR', 'wheelhouse'),
@@ -91,6 +95,9 @@ def main() -> None:
parser.add_argument('--print-build-identifiers',
action='store_true',
help='Print the build identifiers matched by the current invocation and exit.')
parser.add_argument('--allow-empty',
action='store_true',
help='Do not report an error code if the build does not match any wheels.')
args = parser.parse_args()
@@ -107,7 +114,7 @@ def main() -> None:
supported. You can run on your development machine or other CI providers using the
--platform argument. Check --help output for more information.
'''), file=sys.stderr)
exit(2)
sys.exit(2)
if sys.platform.startswith('linux'):
platform = 'linux'
elif sys.platform == 'darwin':
@@ -118,7 +125,11 @@ def main() -> None:
print('cibuildwheel: Unable to detect platform from "sys.platform" in a CI environment. You can run '
'cibuildwheel using the --platform argument. Check --help output for more information.',
file=sys.stderr)
exit(2)
sys.exit(2)
if platform not in PLATFORMS:
print(f'cibuildwheel: Unsupported platform: {platform}', file=sys.stderr)
sys.exit(2)
package_dir = Path(args.package_dir)
output_dir = Path(args.output_dir)
@@ -127,10 +138,13 @@ def main() -> None:
repair_command_default = 'auditwheel repair -w {dest_dir} {wheel}'
elif platform == 'macos':
repair_command_default = 'delocate-listdeps {wheel} && delocate-wheel --require-archs {delocate_archs} -w {dest_dir} {wheel}'
else:
elif platform == 'windows':
repair_command_default = ''
else:
assert_never(platform)
build_config, skip_config = os.environ.get('CIBW_BUILD', '*'), os.environ.get('CIBW_SKIP', '')
test_skip = os.environ.get('CIBW_TEST_SKIP', '')
environment_config = get_option_from_environment('CIBW_ENVIRONMENT', platform=platform, default='')
before_all = get_option_from_environment('CIBW_BEFORE_ALL', platform=platform, default='')
before_build = get_option_from_environment('CIBW_BEFORE_BUILD', platform=platform)
@@ -142,14 +156,15 @@ def main() -> None:
test_extras = get_option_from_environment('CIBW_TEST_EXTRAS', platform=platform, default='')
build_verbosity_str = get_option_from_environment('CIBW_BUILD_VERBOSITY', platform=platform, default='')
build_selector = BuildSelector(build_config, skip_config)
build_selector = BuildSelector(build_config=build_config, skip_config=skip_config)
test_selector = TestSelector(skip_config=test_skip)
try:
environment = parse_environment(environment_config)
except (EnvironmentParseError, ValueError):
print(f'cibuildwheel: Malformed environment option "{environment_config}"', file=sys.stderr)
traceback.print_exc(None, sys.stderr)
exit(2)
sys.exit(2)
if dependency_versions == 'pinned':
dependency_constraints: Optional[DependencyConstraints] = DependencyConstraints.with_defaults()
@@ -174,7 +189,7 @@ def main() -> None:
if not any((package_dir / name).exists()
for name in ["setup.py", "setup.cfg", "pyproject.toml"]):
print('cibuildwheel: Could not find setup.py, setup.cfg or pyproject.toml at root of package', file=sys.stderr)
exit(2)
sys.exit(2)
if args.archs is not None:
archs_config_str = args.archs
@@ -182,9 +197,12 @@ def main() -> None:
archs_config_str = get_option_from_environment('CIBW_ARCHS', platform=platform, default='auto')
archs = Architecture.parse_config(archs_config_str, platform=platform)
identifiers = get_build_identifiers(platform, build_selector, archs)
if args.print_build_identifiers:
print_build_identifiers(platform, build_selector, archs)
exit(0)
for identifier in identifiers:
print(identifier)
sys.exit(0)
manylinux_images: Optional[Dict[str, str]] = None
if platform == 'linux':
@@ -227,6 +245,7 @@ def main() -> None:
before_all=before_all,
build_verbosity=build_verbosity,
build_selector=build_selector,
test_selector=test_selector,
repair_command=repair_command,
environment=environment,
dependency_constraints=dependency_constraints,
@@ -238,6 +257,17 @@ def main() -> None:
print_preamble(platform, build_options)
try:
allowed_architectures_check(platform, build_options.architectures)
except ValueError as err:
print("cibuildwheel:", *err.args, file=sys.stderr)
sys.exit(4)
if not identifiers:
print(f'cibuildwheel: No build identifiers selected: {build_selector}', file=sys.stderr)
if not args.allow_empty:
sys.exit(3)
if not output_dir.exists():
output_dir.mkdir(parents=True)
@@ -248,8 +278,7 @@ def main() -> None:
elif platform == 'macos':
cibuildwheel.macos.build(build_options)
else:
print(f'cibuildwheel: Unsupported platform: {platform}', file=sys.stderr)
exit(2)
assert_never(platform)
def detect_obsolete_options() -> None:
@@ -263,7 +292,7 @@ def detect_obsolete_options() -> None:
os.environ[alternative] = os.environ[deprecated]
else:
print(f"Option '{alternative}' is not empty. Please unset '{deprecated}'")
exit(2)
sys.exit(2)
# Check for deprecated identifiers in 'CIBW_BUILD' and 'CIBW_SKIP' options
for option in ['CIBW_BUILD', 'CIBW_SKIP']:
@@ -299,19 +328,22 @@ def print_preamble(platform: str, build_options: BuildOptions) -> None:
print('\nHere we go!\n')
def print_build_identifiers(
platform: str, build_selector: BuildSelector, architectures: Set[Architecture]
) -> None:
python_configurations: List[Any] = []
def get_build_identifiers(
platform: PlatformName, build_selector: BuildSelector, architectures: Set[Architecture]
) -> List[str]:
python_configurations: Union[List[cibuildwheel.linux.PythonConfiguration],
List[cibuildwheel.windows.PythonConfiguration],
List[cibuildwheel.macos.PythonConfiguration]]
if platform == 'linux':
python_configurations = cibuildwheel.linux.get_python_configurations(build_selector, architectures)
elif platform == 'windows':
python_configurations = cibuildwheel.windows.get_python_configurations(build_selector, architectures)
elif platform == 'macos':
python_configurations = cibuildwheel.macos.get_python_configurations(build_selector, architectures)
else:
assert_never(platform)
for config in python_configurations:
print(config.identifier)
return [config.identifier for config in python_configurations]
def detect_warnings(platform: str, build_options: BuildOptions) -> List[str]:
+99
View File
@@ -0,0 +1,99 @@
import functools
import platform as platform_module
import re
from enum import Enum
from typing import Set
from .typing import PlatformName, assert_never
PRETTY_NAMES = {'linux': 'Linux', 'macos': 'macOS', 'windows': 'Windows'}
@functools.total_ordering
class Architecture(Enum):
value: str
# mac/linux archs
x86_64 = 'x86_64'
# linux archs
i686 = 'i686'
aarch64 = 'aarch64'
ppc64le = 'ppc64le'
s390x = 's390x'
# mac archs
universal2 = 'universal2'
arm64 = 'arm64'
# windows archs
x86 = 'x86'
AMD64 = 'AMD64'
# Allow this to be sorted
def __lt__(self, other: "Architecture") -> bool:
return self.value < other.value
@staticmethod
def parse_config(config: str, platform: PlatformName) -> 'Set[Architecture]':
result = set()
for arch_str in re.split(r'[\s,]+', config):
if arch_str == 'auto':
result |= Architecture.auto_archs(platform=platform)
elif arch_str == 'native':
result.add(Architecture(platform_module.machine()))
elif arch_str == 'all':
result |= Architecture.all_archs(platform=platform)
else:
result.add(Architecture(arch_str))
return result
@staticmethod
def auto_archs(platform: PlatformName) -> 'Set[Architecture]':
native_architecture = Architecture(platform_module.machine())
result = {native_architecture}
if platform == 'linux' and native_architecture == Architecture.x86_64:
# x86_64 machines can run i686 docker containers
result.add(Architecture.i686)
if platform == 'windows' and native_architecture == Architecture.AMD64:
result.add(Architecture.x86)
if platform == 'macos' and native_architecture == Architecture.arm64:
# arm64 can build and test both archs of a universal2 wheel.
result.add(Architecture.universal2)
return result
@staticmethod
def all_archs(platform: PlatformName) -> 'Set[Architecture]':
if platform == 'linux':
return {Architecture.x86_64, Architecture.i686, Architecture.aarch64, Architecture.ppc64le, Architecture.s390x}
elif platform == 'macos':
return {Architecture.x86_64, Architecture.arm64, Architecture.universal2}
elif platform == 'windows':
return {Architecture.x86, Architecture.AMD64}
else:
assert_never(platform)
def allowed_architectures_check(
platform: PlatformName,
architectures: Set[Architecture],
) -> None:
allowed_architectures = Architecture.all_archs(platform)
msg = f'{PRETTY_NAMES[platform]} only supports {sorted(allowed_architectures)} at the moment.'
if platform != 'linux':
msg += ' If you want to set emulation architectures on Linux, use CIBW_ARCHS_LINUX instead.'
if not architectures <= allowed_architectures:
msg = f'Invalid archs option {architectures}. ' + msg
raise ValueError(msg)
if not architectures:
msg = 'Empty archs option set. ' + msg
raise ValueError(msg)
+3
View File
@@ -30,6 +30,9 @@ class DockerContainer:
bash_stdout: IO[bytes]
def __init__(self, docker_image: str, simulate_32_bit: bool = False, cwd: Optional[PathOrStr] = None):
if not docker_image:
raise ValueError("Must have a non-empty docker image to run.")
self.docker_image = docker_image
self.simulate_32_bit = simulate_32_bit
self.cwd = cwd
+24
View File
@@ -0,0 +1,24 @@
"""
These are utilities for the `/bin` scripts, not for the `cibuildwheel` program.
"""
from typing import Any, Dict
import toml.encoder
from packaging.version import Version
class InlineArrayDictEncoder(toml.encoder.TomlEncoder): # type: ignore
def __init__(self) -> None:
super().__init__()
self.dump_funcs[Version] = lambda v: f'"{v}"'
def dump_sections(self, o: Dict[str, Any], sup: str) -> Any:
if all(isinstance(a, list) for a in o.values()):
val = ""
for k, v in o.items():
inner = ",\n ".join(self.dump_inline_table(d_i).strip() for d_i in v)
val += f"{k} = [\n {inner},\n]\n"
return val, self._dict()
else:
return super().dump_sections(o, sup)
+15 -45
View File
@@ -4,17 +4,18 @@ import textwrap
from pathlib import Path, PurePath
from typing import List, NamedTuple, Set
from .architecture import Architecture
from .docker_container import DockerContainer
from .logger import log
from .typing import PathOrStr
from .util import (
Architecture,
BuildOptions,
BuildSelector,
NonPlatformWheelError,
allowed_architectures_check,
get_build_verbosity_extra_flags,
prepare_command,
read_python_configs,
resources_dir,
)
@@ -29,42 +30,13 @@ class PythonConfiguration(NamedTuple):
def get_python_configurations(
build_selector: BuildSelector, architectures: Set[Architecture]
build_selector: BuildSelector,
architectures: Set[Architecture]
) -> List[PythonConfiguration]:
python_configurations = [
PythonConfiguration(version='2.7', identifier='cp27-manylinux_x86_64', path_str='/opt/python/cp27-cp27m'),
PythonConfiguration(version='2.7', identifier='cp27-manylinux_x86_64', path_str='/opt/python/cp27-cp27mu'),
PythonConfiguration(version='3.5', identifier='cp35-manylinux_x86_64', path_str='/opt/python/cp35-cp35m'),
PythonConfiguration(version='3.6', identifier='cp36-manylinux_x86_64', path_str='/opt/python/cp36-cp36m'),
PythonConfiguration(version='3.7', identifier='cp37-manylinux_x86_64', path_str='/opt/python/cp37-cp37m'),
PythonConfiguration(version='3.8', identifier='cp38-manylinux_x86_64', path_str='/opt/python/cp38-cp38'),
PythonConfiguration(version='3.9', identifier='cp39-manylinux_x86_64', path_str='/opt/python/cp39-cp39'),
PythonConfiguration(version='2.7', identifier='cp27-manylinux_i686', path_str='/opt/python/cp27-cp27m'),
PythonConfiguration(version='2.7', identifier='cp27-manylinux_i686', path_str='/opt/python/cp27-cp27mu'),
PythonConfiguration(version='3.5', identifier='cp35-manylinux_i686', path_str='/opt/python/cp35-cp35m'),
PythonConfiguration(version='3.6', identifier='cp36-manylinux_i686', path_str='/opt/python/cp36-cp36m'),
PythonConfiguration(version='3.7', identifier='cp37-manylinux_i686', path_str='/opt/python/cp37-cp37m'),
PythonConfiguration(version='3.8', identifier='cp38-manylinux_i686', path_str='/opt/python/cp38-cp38'),
PythonConfiguration(version='3.9', identifier='cp39-manylinux_i686', path_str='/opt/python/cp39-cp39'),
PythonConfiguration(version='2.7', identifier='pp27-manylinux_x86_64', path_str='/opt/python/pp27-pypy_73'),
PythonConfiguration(version='3.6', identifier='pp36-manylinux_x86_64', path_str='/opt/python/pp36-pypy36_pp73'),
PythonConfiguration(version='3.7', identifier='pp37-manylinux_x86_64', path_str='/opt/python/pp37-pypy37_pp73'),
PythonConfiguration(version='3.5', identifier='cp35-manylinux_aarch64', path_str='/opt/python/cp35-cp35m'),
PythonConfiguration(version='3.6', identifier='cp36-manylinux_aarch64', path_str='/opt/python/cp36-cp36m'),
PythonConfiguration(version='3.7', identifier='cp37-manylinux_aarch64', path_str='/opt/python/cp37-cp37m'),
PythonConfiguration(version='3.8', identifier='cp38-manylinux_aarch64', path_str='/opt/python/cp38-cp38'),
PythonConfiguration(version='3.9', identifier='cp39-manylinux_aarch64', path_str='/opt/python/cp39-cp39'),
PythonConfiguration(version='3.5', identifier='cp35-manylinux_ppc64le', path_str='/opt/python/cp35-cp35m'),
PythonConfiguration(version='3.6', identifier='cp36-manylinux_ppc64le', path_str='/opt/python/cp36-cp36m'),
PythonConfiguration(version='3.7', identifier='cp37-manylinux_ppc64le', path_str='/opt/python/cp37-cp37m'),
PythonConfiguration(version='3.8', identifier='cp38-manylinux_ppc64le', path_str='/opt/python/cp38-cp38'),
PythonConfiguration(version='3.9', identifier='cp39-manylinux_ppc64le', path_str='/opt/python/cp39-cp39'),
PythonConfiguration(version='3.5', identifier='cp35-manylinux_s390x', path_str='/opt/python/cp35-cp35m'),
PythonConfiguration(version='3.6', identifier='cp36-manylinux_s390x', path_str='/opt/python/cp36-cp36m'),
PythonConfiguration(version='3.7', identifier='cp37-manylinux_s390x', path_str='/opt/python/cp37-cp37m'),
PythonConfiguration(version='3.8', identifier='cp38-manylinux_s390x', path_str='/opt/python/cp38-cp38'),
PythonConfiguration(version='3.9', identifier='cp39-manylinux_s390x', path_str='/opt/python/cp39-cp39'),
]
full_python_configs = read_python_configs('linux')
python_configurations = [PythonConfiguration(**item) for item in full_python_configs]
# return all configurations whose arch is in our `architectures` set,
# and match the build/skip rules
@@ -76,8 +48,6 @@ def get_python_configurations(
def build(options: BuildOptions) -> None:
allowed_architectures_check("linux", options)
try:
subprocess.check_output(['docker', '--version'])
except Exception:
@@ -85,7 +55,7 @@ def build(options: BuildOptions) -> None:
'If you\'re building on Travis CI, add `services: [docker]` to your .travis.yml.'
'If you\'re building on Circle CI in Linux, add a `setup_remote_docker` step to your .circleci/config.yml',
file=sys.stderr)
exit(2)
sys.exit(2)
assert options.manylinux_images is not None
python_configurations = get_python_configurations(options.build_selector, options.architectures)
@@ -136,7 +106,7 @@ def build(options: BuildOptions) -> None:
if config.identifier.startswith("pp"):
# Patch PyPy to make sure headers get installed into a venv
patch_version = '_27' if config.version == '2.7' else ''
patch_path = Path(__file__).absolute().parent / 'resources' / f'pypy_venv{patch_version}.patch'
patch_path = resources_dir / f'pypy_venv{patch_version}.patch'
patch_docker_path = PurePath('/pypy_venv.patch')
docker.copy_into(patch_path, patch_docker_path)
try:
@@ -165,12 +135,12 @@ def build(options: BuildOptions) -> None:
which_python = docker.call(['which', 'python'], env=env, capture_output=True).strip()
if PurePath(which_python) != python_bin / 'python':
print("cibuildwheel: python available on PATH doesn't match our installed instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert python above it.", file=sys.stderr)
exit(1)
sys.exit(1)
which_pip = docker.call(['which', 'pip'], env=env, capture_output=True).strip()
if PurePath(which_pip) != python_bin / 'pip':
print("cibuildwheel: pip available on PATH doesn't match our installed instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert pip above it.", file=sys.stderr)
exit(1)
sys.exit(1)
if options.before_build:
log.step('Running before_build...')
@@ -210,7 +180,7 @@ def build(options: BuildOptions) -> None:
repaired_wheels = docker.glob(repaired_wheel_dir, '*.whl')
if options.test_command:
if options.test_command and options.test_selector(config.identifier):
log.step('Testing wheel...')
# set up a virtual environment to install and test from, to make sure
@@ -260,7 +230,7 @@ def build(options: BuildOptions) -> None:
except subprocess.CalledProcessError as error:
log.step_end_with_error(f'Command {error.cmd} failed with code {error.returncode}. {error.stdout}')
troubleshoot(options.package_dir, error)
exit(1)
sys.exit(1)
def troubleshoot(package_dir: Path, error: Exception) -> None:
+12 -24
View File
@@ -8,20 +8,21 @@ import tempfile
from pathlib import Path
from typing import Any, Dict, List, NamedTuple, Optional, Sequence, Set, Tuple, cast
from .architecture import Architecture
from .environment import ParsedEnvironment
from .logger import log
from .typing import PathOrStr
from .util import (
Architecture,
BuildOptions,
BuildSelector,
NonPlatformWheelError,
allowed_architectures_check,
download,
get_build_verbosity_extra_flags,
get_pip_script,
install_certifi_script,
prepare_command,
read_python_configs,
resources_dir,
unwrap,
)
@@ -58,21 +59,10 @@ class PythonConfiguration(NamedTuple):
def get_python_configurations(build_selector: BuildSelector,
architectures: Set[Architecture]) -> List[PythonConfiguration]:
python_configurations = [
# CPython
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'),
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'),
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'),
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'),
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'),
PythonConfiguration(version='3.9', identifier='cp39-macosx_x86_64', url='https://www.python.org/ftp/python/3.9.1/python-3.9.1-macos11.0.pkg'),
PythonConfiguration(version='3.9', identifier='cp39-macosx_arm64', url='https://www.python.org/ftp/python/3.9.1/python-3.9.1-macos11.0.pkg'),
PythonConfiguration(version='3.9', identifier='cp39-macosx_universal2', url='https://www.python.org/ftp/python/3.9.1/python-3.9.1-macos11.0.pkg'),
# PyPy
PythonConfiguration(version='2.7', identifier='pp27-macosx_x86_64', url='https://downloads.python.org/pypy/pypy2.7-v7.3.3-osx64.tar.bz2'),
PythonConfiguration(version='3.6', identifier='pp36-macosx_x86_64', url='https://downloads.python.org/pypy/pypy3.6-v7.3.3-osx64.tar.bz2'),
PythonConfiguration(version='3.7', identifier='pp37-macosx_x86_64', url='https://downloads.python.org/pypy/pypy3.7-v7.3.3-osx64.tar.bz2'),
]
full_python_configs = read_python_configs('macos')
python_configurations = [PythonConfiguration(**item) for item in full_python_configs]
# filter out configs that don't match any of the selected architectures
python_configurations = [c for c in python_configurations
@@ -163,7 +153,7 @@ def install_pypy(version: str, url: str) -> Path:
call(['tar', '-C', '/tmp', '-xf', downloaded_tar_bz2])
# Patch PyPy to make sure headers get installed into a venv
patch_version = '_27' if version == '2.7' else ''
patch_path = Path(__file__).absolute().parent / 'resources' / f'pypy_venv{patch_version}.patch'
patch_path = resources_dir / f'pypy_venv{patch_version}.patch'
call(['patch', '--force', '-p1', '-d', installation_path, '-i', patch_path])
installation_bin_path = installation_path / 'bin'
@@ -211,7 +201,7 @@ def setup_python(python_configuration: PythonConfiguration,
which_python = subprocess.check_output(['which', 'python'], env=env, universal_newlines=True).strip()
if which_python != '/tmp/cibw_bin/python':
print("cibuildwheel: python available on PATH doesn't match our installed instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert python above it.", file=sys.stderr)
exit(1)
sys.exit(1)
# install pip & wheel
call(['python', get_pip_script, *dependency_constraint_flags], env=env, cwd="/tmp")
@@ -221,7 +211,7 @@ def setup_python(python_configuration: PythonConfiguration,
which_pip = subprocess.check_output(['which', 'pip'], env=env, universal_newlines=True).strip()
if which_pip != '/tmp/cibw_bin/pip':
print("cibuildwheel: pip available on PATH doesn't match our installed instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert pip above it.", file=sys.stderr)
exit(1)
sys.exit(1)
# Set MACOSX_DEPLOYMENT_TARGET to 10.9, if the user didn't set it.
# CPython 3.5 defaults to 10.6, and pypy defaults to 10.7, causing
@@ -254,8 +244,6 @@ def setup_python(python_configuration: PythonConfiguration,
def build(options: BuildOptions) -> None:
allowed_architectures_check("macos", options)
temp_dir = Path(tempfile.mkdtemp(prefix='cibuildwheel'))
built_wheel_dir = temp_dir / 'built_wheel'
repaired_wheel_dir = temp_dir / 'repaired_wheel'
@@ -343,7 +331,7 @@ def build(options: BuildOptions) -> None:
log.step_end()
if options.test_command:
if options.test_command and options.test_selector(config.identifier):
machine_arch = platform.machine()
testing_archs: List[str] = []
@@ -447,4 +435,4 @@ def build(options: BuildOptions) -> None:
log.build_end()
except subprocess.CalledProcessError as error:
log.step_end_with_error(f'Command {error.cmd} failed with code {error.returncode}. {error.stdout}')
exit(1)
sys.exit(1)
@@ -0,0 +1,69 @@
[linux]
python_configurations = [
{ identifier = "cp27-manylinux_x86_64", version = "2.7", path_str = "/opt/python/cp27-cp27m" },
{ identifier = "cp27-manylinux_x86_64", version = "2.7", path_str = "/opt/python/cp27-cp27mu" },
{ identifier = "cp35-manylinux_x86_64", version = "3.5", path_str = "/opt/python/cp35-cp35m" },
{ identifier = "cp36-manylinux_x86_64", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
{ identifier = "cp37-manylinux_x86_64", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
{ identifier = "cp38-manylinux_x86_64", version = "3.8", path_str = "/opt/python/cp38-cp38" },
{ identifier = "cp39-manylinux_x86_64", version = "3.9", path_str = "/opt/python/cp39-cp39" },
{ identifier = "cp27-manylinux_i686", version = "2.7", path_str = "/opt/python/cp27-cp27m" },
{ identifier = "cp27-manylinux_i686", version = "2.7", path_str = "/opt/python/cp27-cp27mu" },
{ identifier = "cp35-manylinux_i686", version = "3.5", path_str = "/opt/python/cp35-cp35m" },
{ identifier = "cp36-manylinux_i686", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
{ identifier = "cp37-manylinux_i686", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
{ identifier = "cp38-manylinux_i686", version = "3.8", path_str = "/opt/python/cp38-cp38" },
{ identifier = "cp39-manylinux_i686", version = "3.9", path_str = "/opt/python/cp39-cp39" },
{ identifier = "pp27-manylinux_x86_64", version = "2.7", path_str = "/opt/python/pp27-pypy_73" },
{ identifier = "pp36-manylinux_x86_64", version = "3.6", path_str = "/opt/python/pp36-pypy36_pp73" },
{ identifier = "pp37-manylinux_x86_64", version = "3.7", path_str = "/opt/python/pp37-pypy37_pp73" },
{ identifier = "cp35-manylinux_aarch64", version = "3.5", path_str = "/opt/python/cp35-cp35m" },
{ identifier = "cp36-manylinux_aarch64", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
{ identifier = "cp37-manylinux_aarch64", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
{ identifier = "cp38-manylinux_aarch64", version = "3.8", path_str = "/opt/python/cp38-cp38" },
{ identifier = "cp39-manylinux_aarch64", version = "3.9", path_str = "/opt/python/cp39-cp39" },
{ identifier = "cp35-manylinux_ppc64le", version = "3.5", path_str = "/opt/python/cp35-cp35m" },
{ identifier = "cp36-manylinux_ppc64le", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
{ identifier = "cp37-manylinux_ppc64le", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
{ identifier = "cp38-manylinux_ppc64le", version = "3.8", path_str = "/opt/python/cp38-cp38" },
{ identifier = "cp39-manylinux_ppc64le", version = "3.9", path_str = "/opt/python/cp39-cp39" },
{ identifier = "cp35-manylinux_s390x", version = "3.5", path_str = "/opt/python/cp35-cp35m" },
{ identifier = "cp36-manylinux_s390x", version = "3.6", path_str = "/opt/python/cp36-cp36m" },
{ identifier = "cp37-manylinux_s390x", version = "3.7", path_str = "/opt/python/cp37-cp37m" },
{ identifier = "cp38-manylinux_s390x", version = "3.8", path_str = "/opt/python/cp38-cp38" },
{ identifier = "cp39-manylinux_s390x", version = "3.9", path_str = "/opt/python/cp39-cp39" },
]
[macos]
python_configurations = [
{ 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" },
{ 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" },
{ 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" },
{ 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" },
{ 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" },
{ identifier = "cp39-macosx_x86_64", version = "3.9", url = "https://www.python.org/ftp/python/3.9.1/python-3.9.1-macos11.0.pkg" },
{ identifier = "cp39-macosx_arm64", version = "3.9", url = "https://www.python.org/ftp/python/3.9.1/python-3.9.1-macos11.0.pkg" },
{ identifier = "cp39-macosx_universal2", version = "3.9", url = "https://www.python.org/ftp/python/3.9.1/python-3.9.1-macos11.0.pkg" },
{ identifier = "pp27-macosx_x86_64", version = "2.7", url = "https://downloads.python.org/pypy/pypy2.7-v7.3.3-osx64.tar.bz2" },
{ identifier = "pp36-macosx_x86_64", version = "3.6", url = "https://downloads.python.org/pypy/pypy3.6-v7.3.3-osx64.tar.bz2" },
{ identifier = "pp37-macosx_x86_64", version = "3.7", url = "https://downloads.python.org/pypy/pypy3.7-v7.3.3-osx64.tar.bz2" },
]
[windows]
python_configurations = [
{ identifier = "cp27-win32", version = "2.7.18", arch = "32" },
{ identifier = "cp27-win_amd64", version = "2.7.18", arch = "64" },
{ identifier = "cp35-win32", version = "3.5.4", arch = "32" },
{ identifier = "cp35-win_amd64", version = "3.5.4", arch = "64" },
{ identifier = "cp36-win32", version = "3.6.8", arch = "32" },
{ identifier = "cp36-win_amd64", version = "3.6.8", arch = "64" },
{ identifier = "cp37-win32", version = "3.7.9", arch = "32" },
{ identifier = "cp37-win_amd64", version = "3.7.9", arch = "64" },
{ identifier = "cp38-win32", version = "3.8.7", arch = "32" },
{ identifier = "cp38-win_amd64", version = "3.8.7", arch = "64" },
{ identifier = "cp39-win32", version = "3.9.1", arch = "32" },
{ identifier = "cp39-win_amd64", version = "3.9.1", arch = "64" },
{ identifier = "pp27-win32", version = "2.7", arch = "32", url = "https://downloads.python.org/pypy/pypy2.7-v7.3.3-win32.zip" },
{ identifier = "pp36-win32", version = "3.6", arch = "32", url = "https://downloads.python.org/pypy/pypy3.6-v7.3.3-win32.zip" },
{ identifier = "pp37-win32", version = "3.7", arch = "32", url = "https://downloads.python.org/pypy/pypy3.7-v7.3.3-win32.zip" },
]
@@ -37,7 +37,7 @@ six==1.15.0
# virtualenv
typing==3.7.4.3
# via importlib-resources
virtualenv==20.2.2
virtualenv==20.4.0
# via -r cibuildwheel/resources/constraints.in
wheel==0.36.2
# via
@@ -18,7 +18,7 @@ importlib-resources==3.2.1
# via virtualenv
six==1.15.0
# via virtualenv
virtualenv==20.2.2
virtualenv==20.4.0
# via -r cibuildwheel/resources/constraints.in
wheel==0.36.2
# via
@@ -12,15 +12,15 @@ distlib==0.3.1
# via virtualenv
filelock==3.0.12
# via virtualenv
importlib-metadata==3.3.0
importlib-metadata==3.4.0
# via virtualenv
importlib-resources==4.1.1
importlib-resources==5.1.0
# via virtualenv
six==1.15.0
# via virtualenv
typing-extensions==3.7.4.3
# via importlib-metadata
virtualenv==20.2.2
virtualenv==20.4.0
# via -r cibuildwheel/resources/constraints.in
wheel==0.36.2
# via
@@ -34,5 +34,5 @@ zipp==3.4.0
# The following packages are considered to be unsafe in a requirements file:
pip==20.3.3
# via -r cibuildwheel/resources/constraints.in
setuptools==51.1.1
setuptools==51.3.3
# via -r cibuildwheel/resources/constraints.in
@@ -12,13 +12,13 @@ distlib==0.3.1
# via virtualenv
filelock==3.0.12
# via virtualenv
importlib-metadata==3.3.0
importlib-metadata==3.4.0
# via virtualenv
six==1.15.0
# via virtualenv
typing-extensions==3.7.4.3
# via importlib-metadata
virtualenv==20.2.2
virtualenv==20.4.0
# via -r cibuildwheel/resources/constraints.in
wheel==0.36.2
# via
@@ -30,5 +30,5 @@ zipp==3.4.0
# The following packages are considered to be unsafe in a requirements file:
pip==20.3.3
# via -r cibuildwheel/resources/constraints.in
setuptools==51.1.1
setuptools==51.3.3
# via -r cibuildwheel/resources/constraints.in
@@ -14,7 +14,7 @@ filelock==3.0.12
# via virtualenv
six==1.15.0
# via virtualenv
virtualenv==20.2.2
virtualenv==20.4.0
# via -r cibuildwheel/resources/constraints.in
wheel==0.36.2
# via
@@ -24,5 +24,5 @@ wheel==0.36.2
# The following packages are considered to be unsafe in a requirements file:
pip==20.3.3
# via -r cibuildwheel/resources/constraints.in
setuptools==51.1.1
setuptools==51.3.3
# via -r cibuildwheel/resources/constraints.in
@@ -14,7 +14,7 @@ filelock==3.0.12
# via virtualenv
six==1.15.0
# via virtualenv
virtualenv==20.2.2
virtualenv==20.4.0
# via -r cibuildwheel/resources/constraints.in
wheel==0.36.2
# via
@@ -24,5 +24,5 @@ wheel==0.36.2
# The following packages are considered to be unsafe in a requirements file:
pip==20.3.3
# via -r cibuildwheel/resources/constraints.in
setuptools==51.1.1
setuptools==51.3.3
# via -r cibuildwheel/resources/constraints.in
+2 -2
View File
@@ -14,7 +14,7 @@ filelock==3.0.12
# via virtualenv
six==1.15.0
# via virtualenv
virtualenv==20.2.2
virtualenv==20.4.0
# via -r cibuildwheel/resources/constraints.in
wheel==0.36.2
# via
@@ -24,5 +24,5 @@ wheel==0.36.2
# The following packages are considered to be unsafe in a requirements file:
pip==20.3.3
# via -r cibuildwheel/resources/constraints.in
setuptools==51.1.1
setuptools==51.3.3
# via -r cibuildwheel/resources/constraints.in
@@ -1,22 +1,22 @@
[x86_64]
manylinux1 = quay.io/pypa/manylinux1_x86_64:2020-12-31-84e1e23
manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2020-12-31-4928808
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2020-12-31-56195b3
manylinux1 = quay.io/pypa/manylinux1_x86_64:2021-01-11-28ab838
manylinux2010 = quay.io/pypa/manylinux2010_x86_64:2021-01-12-ff3830d
manylinux2014 = quay.io/pypa/manylinux2014_x86_64:2021-01-12-c8250d8
[i686]
manylinux1 = quay.io/pypa/manylinux1_i686:2020-12-31-84e1e23
manylinux2010 = quay.io/pypa/manylinux2010_i686:2020-12-31-4928808
manylinux2014 = quay.io/pypa/manylinux2014_i686:2020-12-31-56195b3
manylinux1 = quay.io/pypa/manylinux1_i686:2021-01-11-28ab838
manylinux2010 = quay.io/pypa/manylinux2010_i686:2021-01-12-ff3830d
manylinux2014 = quay.io/pypa/manylinux2014_i686:2021-01-12-c8250d8
[pypy_x86_64]
manylinux2010 = pypywheels/manylinux2010-pypy_x86_64:2020-12-11-f1e0e80
[aarch64]
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2020-12-31-56195b3
manylinux2014 = quay.io/pypa/manylinux2014_aarch64:2021-01-12-c8250d8
[ppc64le]
manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2020-12-31-56195b3
manylinux2014 = quay.io/pypa/manylinux2014_ppc64le:2021-01-12-c8250d8
[s390x]
manylinux2014 = quay.io/pypa/manylinux2014_s390x:2020-12-31-56195b3
manylinux2014 = quay.io/pypa/manylinux2014_s390x:2021-01-12-c8250d8
+19 -1
View File
@@ -1,6 +1,16 @@
import os
import subprocess
from typing import TYPE_CHECKING, Union
import sys
from typing import TYPE_CHECKING, NoReturn, Set, Union
if sys.version_info < (3, 8):
from typing_extensions import Final, Literal, TypedDict
else:
from typing import Final, Literal, TypedDict
__all__ = ("Final", "Literal", "TypedDict", "Set", "Union", "PopenBytes", "PathOrStr", "PlatformName", "PLATFORMS", "assert_never")
if TYPE_CHECKING:
PopenBytes = subprocess.Popen[bytes]
@@ -8,3 +18,11 @@ if TYPE_CHECKING:
else:
PopenBytes = subprocess.Popen
PathOrStr = Union[str, "os.PathLike[str]"]
PlatformName = Literal["linux", "macos", "windows"]
PLATFORMS: Final[Set[PlatformName]] = {"linux", "macos", "windows"}
def assert_never(value: NoReturn) -> NoReturn:
assert False, f'Unhandled value: {value} ({type(value).__name__})' # noqa: B011
+41 -105
View File
@@ -1,26 +1,26 @@
import functools
import fnmatch
import itertools
import os
import platform as platform_module
import re
import ssl
import sys
import textwrap
import urllib.request
from enum import Enum
from fnmatch import fnmatch
from pathlib import Path
from time import sleep
from typing import Dict, List, NamedTuple, Optional, Set
import bracex
import certifi
import toml
from .architecture import Architecture
from .environment import ParsedEnvironment
from .typing import PathOrStr
from .typing import PathOrStr, PlatformName
if sys.version_info < (3, 8):
from typing_extensions import Literal
else:
from typing import Literal
resources_dir = Path(__file__).parent / 'resources'
get_pip_script = resources_dir / 'get-pip.py'
install_certifi_script = resources_dir / "install_certifi.py"
def prepare_command(command: str, **kwargs: PathOrStr) -> str:
@@ -42,21 +42,45 @@ def get_build_verbosity_extra_flags(level: int) -> List[str]:
return []
class BuildSelector:
def __init__(self, build_config: str, skip_config: str):
def read_python_configs(config: PlatformName) -> List[Dict[str, str]]:
input_file = resources_dir / 'build-platforms.toml'
loaded_file = toml.load(input_file)
results: List[Dict[str, str]] = list(loaded_file[config]['python_configurations'])
return results
class IdentifierSelector:
"""
This class holds a set of build/skip patterns. You call an instance with a
build identifier, and it returns True if that identifier should be
included.
"""
def __init__(self, *, build_config: str, skip_config: str):
self.build_patterns = build_config.split()
self.skip_patterns = skip_config.split()
def __call__(self, build_id: str) -> bool:
def match_any(patterns: List[str]) -> bool:
return any(fnmatch(build_id, pattern) for pattern in patterns)
return match_any(self.build_patterns) and not match_any(self.skip_patterns)
build_patterns = itertools.chain.from_iterable(bracex.expand(p) for p in self.build_patterns)
skip_patterns = itertools.chain.from_iterable(bracex.expand(p) for p in self.skip_patterns)
build: bool = any(fnmatch.fnmatch(build_id, pat) for pat in build_patterns)
skip: bool = any(fnmatch.fnmatch(build_id, pat) for pat in skip_patterns)
return build and not skip
def __repr__(self) -> str:
if not self.skip_patterns:
return f'BuildSelector({" ".join(self.build_patterns)!r})'
return f'{self.__class__.__name__}({" ".join(self.build_patterns)!r})'
else:
return f'BuildSelector({" ".join(self.build_patterns)!r} - {" ".join(self.skip_patterns)!r})'
return f'{self.__class__.__name__}({" ".join(self.build_patterns)!r} - {" ".join(self.skip_patterns)!r})'
class BuildSelector(IdentifierSelector):
pass
class TestSelector(IdentifierSelector):
def __init__(self, *, skip_config: str):
super().__init__(build_config="*", skip_config=skip_config)
# Taken from https://stackoverflow.com/a/107717
@@ -131,60 +155,6 @@ class DependencyConstraints:
return f'{self.__class__.__name__}{self.base_file_path!r})'
@functools.total_ordering
class Architecture(Enum):
value: str
# mac/linux archs
x86_64 = 'x86_64'
# linux archs
i686 = 'i686'
aarch64 = 'aarch64'
ppc64le = 'ppc64le'
s390x = 's390x'
# mac archs
universal2 = 'universal2'
arm64 = 'arm64'
# windows archs
x86 = 'x86'
AMD64 = 'AMD64'
# Allow this to be sorted
def __lt__(self, other: "Architecture") -> bool:
return self.value < other.value
@staticmethod
def parse_config(config: str, platform: str) -> 'Set[Architecture]':
result = set()
for arch_str in re.split(r'[\s,]+', config):
if arch_str == 'auto':
result |= Architecture.auto_archs(platform=platform)
else:
result.add(Architecture(arch_str))
return result
@staticmethod
def auto_archs(platform: str) -> 'Set[Architecture]':
native_architecture = Architecture(platform_module.machine())
result = {native_architecture}
if platform == 'linux' and native_architecture == Architecture.x86_64:
# x86_64 machines can run i686 docker containers
result.add(Architecture.i686)
if platform == 'windows' and native_architecture == Architecture.AMD64:
result.add(Architecture.x86)
if platform == 'macos' and native_architecture == Architecture.arm64:
# arm64 can build and test both archs of a universal2 wheel.
result.add(Architecture.universal2)
return result
class BuildOptions(NamedTuple):
package_dir: Path
output_dir: Path
@@ -197,17 +167,13 @@ class BuildOptions(NamedTuple):
manylinux_images: Optional[Dict[str, str]]
dependency_constraints: Optional[DependencyConstraints]
test_command: Optional[str]
test_selector: TestSelector
before_test: Optional[str]
test_requires: List[str]
test_extras: str
build_verbosity: int
resources_dir = Path(__file__).resolve().parent / 'resources'
get_pip_script = resources_dir / 'get-pip.py'
install_certifi_script = resources_dir / "install_certifi.py"
class NonPlatformWheelError(Exception):
def __init__(self) -> None:
message = textwrap.dedent('''
@@ -258,36 +224,6 @@ def detect_ci_provider() -> Optional[CIProvider]:
return None
PRETTY_NAMES = {'linux': 'Linux', 'macos': 'macOS', 'windows': 'Windows'}
ALLOWED_ARCHITECTURES = {
'linux': {Architecture.x86_64, Architecture.i686, Architecture.aarch64, Architecture.ppc64le, Architecture.s390x},
'macos': {Architecture.x86_64, Architecture.universal2, Architecture.arm64},
'windows': {Architecture.AMD64, Architecture.x86},
}
def allowed_architectures_check(
name: Literal['linux', 'macos', 'windows'],
options: BuildOptions,
) -> None:
allowed_architectures = ALLOWED_ARCHITECTURES[name]
msg = f'{PRETTY_NAMES[name]} only supports {sorted(allowed_architectures)} at the moment.'
if name != 'linux':
msg += ' If you want to set emulation architectures on Linux, use CIBW_ARCHS_LINUX instead.'
if not options.architectures <= allowed_architectures:
msg = f'Invalid archs option {options.architectures}. ' + msg
raise ValueError(msg)
if not options.architectures:
msg = 'Empty archs option set. ' + msg
raise ValueError(msg)
def unwrap(text: str) -> str:
'''
Unwraps multi-line text to a single line
+19 -32
View File
@@ -9,19 +9,19 @@ from zipfile import ZipFile
import toml
from .architecture import Architecture
from .environment import ParsedEnvironment
from .logger import log
from .typing import PathOrStr
from .util import (
Architecture,
BuildOptions,
BuildSelector,
NonPlatformWheelError,
allowed_architectures_check,
download,
get_build_verbosity_extra_flags,
get_pip_script,
prepare_command,
read_python_configs,
)
IS_RUNNING_ON_AZURE = Path('C:\\hostedtoolcache').exists()
@@ -52,36 +52,25 @@ class PythonConfiguration(NamedTuple):
version: str
arch: str
identifier: str
url: Optional[str]
url: Optional[str] = None
def get_python_configurations(build_selector: BuildSelector, architectures: Set[Architecture]) -> List[PythonConfiguration]:
def get_python_configurations(
build_selector: BuildSelector,
architectures: Set[Architecture],
) -> List[PythonConfiguration]:
full_python_configs = read_python_configs('windows')
python_configurations = [PythonConfiguration(**item) for item in full_python_configs]
map_arch = {
'32': Architecture.x86,
'64': Architecture.AMD64,
}
python_configurations = [
# CPython
PythonConfiguration(version='2.7.18', arch='32', identifier='cp27-win32', url=None),
PythonConfiguration(version='2.7.18', arch='64', identifier='cp27-win_amd64', url=None),
PythonConfiguration(version='3.5.4', arch='32', identifier='cp35-win32', url=None),
PythonConfiguration(version='3.5.4', arch='64', identifier='cp35-win_amd64', url=None),
PythonConfiguration(version='3.6.8', arch='32', identifier='cp36-win32', url=None),
PythonConfiguration(version='3.6.8', arch='64', identifier='cp36-win_amd64', url=None),
PythonConfiguration(version='3.7.9', arch='32', identifier='cp37-win32', url=None),
PythonConfiguration(version='3.7.9', arch='64', identifier='cp37-win_amd64', url=None),
PythonConfiguration(version='3.8.7', arch='32', identifier='cp38-win32', url=None),
PythonConfiguration(version='3.8.7', arch='64', identifier='cp38-win_amd64', url=None),
PythonConfiguration(version='3.9.1', arch='32', identifier='cp39-win32', url=None),
PythonConfiguration(version='3.9.1', arch='64', identifier='cp39-win_amd64', url=None),
# PyPy
PythonConfiguration(version='2.7', arch='32', identifier='pp27-win32', url='https://downloads.python.org/pypy/pypy2.7-v7.3.3-win32.zip'),
PythonConfiguration(version='3.6', arch='32', identifier='pp36-win32', url='https://downloads.python.org/pypy/pypy3.6-v7.3.3-win32.zip'),
PythonConfiguration(version='3.7', arch='32', identifier='pp37-win32', url='https://downloads.python.org/pypy/pypy3.7-v7.3.3-win32.zip'),
]
if IS_RUNNING_ON_TRAVIS:
custom_compiler = os.environ.get('DISTUTILS_USE_SDK') and os.environ.get('MSSdk')
if IS_RUNNING_ON_TRAVIS and not custom_compiler:
# cannot install VCForPython27.msi which is needed for compiling C software
# try with (and similar): msiexec /i VCForPython27.msi ALLUSERS=1 ACCEPT=YES /passive
python_configurations = [c for c in python_configurations if not c.version.startswith('2.7')]
@@ -164,7 +153,7 @@ def setup_python(python_configuration: PythonConfiguration, dependency_constrain
where_python = subprocess.check_output(['where', 'python'], env=env, universal_newlines=True).splitlines()[0].strip()
if where_python != str(installation_path / 'python.exe'):
print("cibuildwheel: python available on PATH doesn't match our installed instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert python above it.", file=sys.stderr)
exit(1)
sys.exit(1)
# make sure pip is installed
if not (installation_path / 'Scripts' / 'pip.exe').exists():
@@ -173,7 +162,7 @@ def setup_python(python_configuration: PythonConfiguration, dependency_constrain
where_pip = subprocess.check_output(['where', 'pip'], env=env, universal_newlines=True).splitlines()[0].strip()
if where_pip.strip() != str(installation_path / 'Scripts' / 'pip.exe'):
print("cibuildwheel: pip available on PATH doesn't match our installed instance. If you have modified PATH, ensure that you don't overwrite cibuildwheel's entry or insert pip above it.", file=sys.stderr)
exit(1)
sys.exit(1)
log.step('Installing build tools...')
@@ -210,15 +199,13 @@ def pep_518_cp35_workaround(package_dir: Path, env: Dict[str, str]) -> None:
log.step('Performing PEP518 workaround...')
with tempfile.TemporaryDirectory() as d:
reqfile = Path(d) / "requirements.txt"
with reqfile.open("w") as f:
with reqfile.open('w') as f:
for r in requirements:
print(r, file=f)
call(['pip', 'install', '-r', reqfile], env=env)
def build(options: BuildOptions) -> None:
allowed_architectures_check("windows", options)
temp_dir = Path(tempfile.mkdtemp(prefix='cibuildwheel'))
built_wheel_dir = temp_dir / 'built_wheel'
repaired_wheel_dir = temp_dir / 'repaired_wheel'
@@ -288,7 +275,7 @@ def build(options: BuildOptions) -> None:
repaired_wheel = next(repaired_wheel_dir.glob('*.whl'))
if options.test_command:
if options.test_command and options.test_selector(config.identifier):
log.step('Testing wheel...')
# set up a virtual environment to install and test from, to make sure
# there are no dependencies that were pulled in at build time.
@@ -341,4 +328,4 @@ def build(options: BuildOptions) -> None:
log.build_end()
except subprocess.CalledProcessError as error:
log.step_end_with_error(f'Command {error.cmd} failed with code {error.returncode}. {error.stdout}')
exit(1)
sys.exit(1)