feature: add support for py3-none-{platform} wheels

This extends the mechanism introduced in #1091 for `abi3` wheels.
Most of the mentions to `abi3` have been removed and replaced by a more generic `compatible_wheel`.
This allows to build a wheel `foo-0.1-py3-none-win_amd64.whl` only once and still test with every configured python.
This commit is contained in:
mayeut
2022-06-26 11:31:59 +02:00
parent 0bf4f7abc3
commit 0696c94710
5 changed files with 72 additions and 28 deletions
+6 -6
View File
@@ -12,7 +12,7 @@ from .typing import OrderedDict, PathOrStr, assert_never
from .util import ( from .util import (
BuildSelector, BuildSelector,
NonPlatformWheelError, NonPlatformWheelError,
find_compatible_abi3_wheel, find_compatible_wheel,
get_build_verbosity_extra_flags, get_build_verbosity_extra_flags,
prepare_command, prepare_command,
read_python_configs, read_python_configs,
@@ -177,13 +177,13 @@ def build_on_docker(
) )
sys.exit(1) sys.exit(1)
abi3_wheel = find_compatible_abi3_wheel(built_wheels, config.identifier) compatible_wheel = find_compatible_wheel(built_wheels, config.identifier)
if abi3_wheel: if compatible_wheel:
log.step_end() log.step_end()
print( print(
f"\nFound previously built wheel {abi3_wheel.name}, that's compatible with {config.identifier}. Skipping build step..." f"\nFound previously built wheel {compatible_wheel.name}, that's compatible with {config.identifier}. Skipping build step..."
) )
repaired_wheels = [abi3_wheel] repaired_wheels = [compatible_wheel]
else: else:
if build_options.before_build: if build_options.before_build:
@@ -304,7 +304,7 @@ def build_on_docker(
docker.call(["rm", "-rf", venv_dir]) docker.call(["rm", "-rf", venv_dir])
# move repaired wheels to output # move repaired wheels to output
if abi3_wheel is None: if compatible_wheel is None:
docker.call(["mkdir", "-p", container_output_dir]) docker.call(["mkdir", "-p", container_output_dir])
docker.call(["mv", *repaired_wheels, container_output_dir]) docker.call(["mv", *repaired_wheels, container_output_dir])
built_wheels.extend( built_wheels.extend(
+6 -6
View File
@@ -23,7 +23,7 @@ from .util import (
call, call,
detect_ci_provider, detect_ci_provider,
download, download,
find_compatible_abi3_wheel, find_compatible_wheel,
get_build_verbosity_extra_flags, get_build_verbosity_extra_flags,
get_pip_version, get_pip_version,
install_certifi_script, install_certifi_script,
@@ -321,13 +321,13 @@ def build(options: Options, tmp_path: Path) -> None:
build_options.build_frontend, build_options.build_frontend,
) )
abi3_wheel = find_compatible_abi3_wheel(built_wheels, config.identifier) compatible_wheel = find_compatible_wheel(built_wheels, config.identifier)
if abi3_wheel: if compatible_wheel:
log.step_end() log.step_end()
print( print(
f"\nFound previously built wheel {abi3_wheel.name}, that's compatible with {config.identifier}. Skipping build step..." f"\nFound previously built wheel {compatible_wheel.name}, that's compatible with {config.identifier}. Skipping build step..."
) )
repaired_wheel = abi3_wheel repaired_wheel = compatible_wheel
else: else:
if build_options.before_build: if build_options.before_build:
log.step("Running before_build...") log.step("Running before_build...")
@@ -534,7 +534,7 @@ def build(options: Options, tmp_path: Path) -> None:
) )
# we're all done here; move it to output (overwrite existing) # we're all done here; move it to output (overwrite existing)
if abi3_wheel is None: if compatible_wheel is None:
try: try:
(build_options.output_dir / repaired_wheel.name).unlink() (build_options.output_dir / repaired_wheel.name).unlink()
except FileNotFoundError: except FileNotFoundError:
+11 -9
View File
@@ -54,7 +54,7 @@ __all__ = [
"MANYLINUX_ARCHS", "MANYLINUX_ARCHS",
"call", "call",
"shell", "shell",
"find_compatible_abi3_wheel", "find_compatible_wheel",
"format_safe", "format_safe",
"prepare_command", "prepare_command",
"get_build_verbosity_extra_flags", "get_build_verbosity_extra_flags",
@@ -574,23 +574,25 @@ def virtualenv(
T = TypeVar("T", bound=PurePath) T = TypeVar("T", bound=PurePath)
def find_compatible_abi3_wheel(wheels: Sequence[T], identifier: str) -> Optional[T]: def find_compatible_wheel(wheels: Sequence[T], identifier: str) -> Optional[T]:
""" """
Finds an ABI3 wheel in `wheels` compatible with the Python interpreter Finds a wheel with an abi3 or a none ABI tag in `wheels` compatible with the Python interpreter
specified by `identifier`. specified by `identifier`.
""" """
interpreter, platform = identifier.split("-") interpreter, platform = identifier.split("-")
if not interpreter.startswith("cp3"):
return None
for wheel in wheels: for wheel in wheels:
_, _, _, tags = parse_wheel_filename(wheel.name) _, _, _, tags = parse_wheel_filename(wheel.name)
for tag in tags: for tag in tags:
if tag.abi != "abi3": if tag.abi == "abi3":
if not (interpreter.startswith("cp3") and tag.interpreter.startswith("cp3")):
continue
elif tag.abi == "none":
if tag.interpreter[:3] != "py3":
continue
else:
continue continue
if not tag.interpreter.startswith("cp3"): if tag.interpreter != "py3" and int(tag.interpreter[3:]) > int(interpreter[3:]):
continue
if int(tag.interpreter[3:]) > int(interpreter[3:]):
continue continue
if platform.startswith(("manylinux", "musllinux", "macosx")): if platform.startswith(("manylinux", "musllinux", "macosx")):
# Linux, macOS # Linux, macOS
+6 -6
View File
@@ -22,7 +22,7 @@ from .util import (
NonPlatformWheelError, NonPlatformWheelError,
call, call,
download, download,
find_compatible_abi3_wheel, find_compatible_wheel,
get_build_verbosity_extra_flags, get_build_verbosity_extra_flags,
get_pip_version, get_pip_version,
prepare_command, prepare_command,
@@ -277,13 +277,13 @@ def build(options: Options, tmp_path: Path) -> None:
build_options.build_frontend, build_options.build_frontend,
) )
abi3_wheel = find_compatible_abi3_wheel(built_wheels, config.identifier) compatible_wheel = find_compatible_wheel(built_wheels, config.identifier)
if abi3_wheel: if compatible_wheel:
log.step_end() log.step_end()
print( print(
f"\nFound previously built wheel {abi3_wheel.name}, that's compatible with {config.identifier}. Skipping build step..." f"\nFound previously built wheel {compatible_wheel.name}, that's compatible with {config.identifier}. Skipping build step..."
) )
repaired_wheel = abi3_wheel repaired_wheel = compatible_wheel
else: else:
# run the before_build command # run the before_build command
if build_options.before_build: if build_options.before_build:
@@ -418,7 +418,7 @@ def build(options: Options, tmp_path: Path) -> None:
shell(test_command_prepared, cwd="c:\\", env=virtualenv_env) shell(test_command_prepared, cwd="c:\\", env=virtualenv_env)
# we're all done here; move it to output (remove if already exists) # we're all done here; move it to output (remove if already exists)
if abi3_wheel is None: if compatible_wheel is None:
shutil.move(str(repaired_wheel), build_options.output_dir) shutil.move(str(repaired_wheel), build_options.output_dir)
built_wheels.append(build_options.output_dir / repaired_wheel.name) built_wheels.append(build_options.output_dir / repaired_wheel.name)
+43 -1
View File
@@ -1,4 +1,8 @@
from cibuildwheel.util import format_safe, prepare_command from pathlib import PurePath
import pytest
from cibuildwheel.util import find_compatible_wheel, format_safe, prepare_command
def test_format_safe(): def test_format_safe():
@@ -46,3 +50,41 @@ def test_prepare_command():
prepare_command("{a}{a,b}{b:.2e}{c}{d%s}{e:3}{f[0]}", a="42", b="3.14159") prepare_command("{a}{a,b}{b:.2e}{c}{d%s}{e:3}{f[0]}", a="42", b="3.14159")
== "42{a,b}{b:.2e}{c}{d%s}{e:3}{f[0]}" == "42{a,b}{b:.2e}{c}{d%s}{e:3}{f[0]}"
) )
@pytest.mark.parametrize(
"wheel,identifier",
(
("foo-0.1-cp38-abi3-win_amd64.whl", "cp310-win_amd64"),
("foo-0.1-cp38-abi3-macosx_11_0_x86_64.whl", "cp310-macosx_x86_64"),
("foo-0.1-cp38-abi3-manylinux2014_x86_64.whl", "cp310-manylinux_x86_64"),
("foo-0.1-cp38-abi3-musllinux_1_1_x86_64.whl", "cp310-musllinux_x86_64"),
("foo-0.1-py2.py3-none-win_amd64.whl", "cp310-win_amd64"),
("foo-0.1-py2.py3-none-win_amd64.whl", "pp310-win_amd64"),
("foo-0.1-py3-none-win_amd64.whl", "cp310-win_amd64"),
("foo-0.1-py38-none-win_amd64.whl", "cp310-win_amd64"),
("foo-0.1-py38-none-win_amd64.whl", "pp310-win_amd64"),
),
)
def test_find_compatible_wheel_found(wheel: str, identifier: str):
wheel_ = PurePath(wheel)
found = find_compatible_wheel([wheel_], identifier)
assert found is wheel_
@pytest.mark.parametrize(
"wheel,identifier",
(
("foo-0.1-cp38-abi3-win_amd64.whl", "cp310-win32"),
("foo-0.1-cp38-abi3-win_amd64.whl", "cp37-win_amd64"),
("foo-0.1-cp38-abi3-macosx_11_0_x86_64.whl", "cp310-macosx_universal2"),
("foo-0.1-cp38-abi3-manylinux2014_x86_64.whl", "cp310-musllinux_x86_64"),
("foo-0.1-cp38-abi3-musllinux_1_1_x86_64.whl", "cp310-manylinux_x86_64"),
("foo-0.1-py2-none-win_amd64.whl", "cp310-win_amd64"),
("foo-0.1-py38-none-win_amd64.whl", "cp37-win_amd64"),
("foo-0.1-py38-none-win_amd64.whl", "pp37-win_amd64"),
("foo-0.1-cp38-cp38-win_amd64.whl", "cp310-win_amd64"),
),
)
def test_find_compatible_wheel_not_found(wheel: str, identifier: str):
assert find_compatible_wheel([PurePath(wheel)], identifier) is None