Test enable groups as specified by PR labels (#2357)
* Allow CIBW_ENABLE to control the wheels built in testing * Set CIBW_ENABLE using PR labels * Add docs * Build everything on the main branch * Add CIBW_ENABLE=all option This was mostly for use in the `main` building case, because otherwise it's maybe a bit too easy to forget to update this file when adding an enable group * Remove dead code * Make unit tests robust to the value of CIBW_ENABLE * Fix tests that explicitly choose pypy * Fix test expectation * Don't expect impossible wheels in expected_wheels * Simplify logic in expected_wheels * CircleCI- run with CIBW_ENABLE=all only on the main branch * Azure pipelines - run with CIBW_ENABLE=all on main branch * Update gitlab to run CIBW_ENABLE=all on main * Set CIBW_ENABLE=all on travis - it only runs on main anyway * Fix job name error on CircleCI * Fix tests for graalpy * Update the test configuration to use the label * Remove duplication of default value. Make it affect sample build too * Move the action to after deps are installed * GraalPy workaround for this assumption * Make unit test resilient to changing CIBW_ENABLE
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
from collections.abc import Generator
|
||||
|
||||
@@ -12,6 +13,9 @@ from cibuildwheel.venv import find_uv
|
||||
|
||||
from .utils import EMULATED_ARCHS, platform
|
||||
|
||||
# default to just cpython
|
||||
DEFAULT_CIBW_ENABLE = "cpython-freethreading cpython-prerelease cpython-experimental-riscv64"
|
||||
|
||||
|
||||
def pytest_addoption(parser: pytest.Parser) -> None:
|
||||
parser.addoption(
|
||||
@@ -29,6 +33,8 @@ def pytest_addoption(parser: pytest.Parser) -> None:
|
||||
help="macOS cp38 uses the universal2 installer",
|
||||
)
|
||||
|
||||
os.environ.setdefault("CIBW_ENABLE", DEFAULT_CIBW_ENABLE)
|
||||
|
||||
|
||||
def docker_warmup(request: pytest.FixtureRequest) -> None:
|
||||
machine = request.config.getoption("--run-emulation", default=None)
|
||||
|
||||
+16
-9
@@ -1,8 +1,10 @@
|
||||
import os
|
||||
import textwrap
|
||||
|
||||
import pytest
|
||||
|
||||
from cibuildwheel.logger import Logger
|
||||
from cibuildwheel.selector import EnableGroup
|
||||
|
||||
from . import test_projects, utils
|
||||
|
||||
@@ -38,11 +40,13 @@ def test(tmp_path, build_frontend_env, capfd):
|
||||
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
# Verify pip warning not shown
|
||||
captured = capfd.readouterr()
|
||||
for stream in (captured.err, captured.out):
|
||||
assert "WARNING: Running pip as the 'root' user can result" not in stream
|
||||
assert "A new release of pip available" not in stream
|
||||
enable_groups = EnableGroup.parse_option_value(os.environ.get("CIBW_ENABLE", ""))
|
||||
if EnableGroup.GraalPy not in enable_groups:
|
||||
# Verify pip warning not shown
|
||||
captured = capfd.readouterr()
|
||||
for stream in (captured.err, captured.out):
|
||||
assert "WARNING: Running pip as the 'root' user can result" not in stream
|
||||
assert "A new release of pip available" not in stream
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="to keep test output clean")
|
||||
@@ -61,16 +65,19 @@ def test_sample_build(tmp_path, capfd):
|
||||
logger.step_end()
|
||||
|
||||
|
||||
def test_build_identifiers(tmp_path):
|
||||
@pytest.mark.parametrize(
|
||||
"enable_setting", ["", "cpython-prerelease", "pypy", "cpython-freethreading"]
|
||||
)
|
||||
def test_build_identifiers(tmp_path, enable_setting, monkeypatch):
|
||||
project_dir = tmp_path / "project"
|
||||
basic_project.generate(project_dir)
|
||||
|
||||
monkeypatch.setenv("CIBW_ENABLE", enable_setting)
|
||||
|
||||
# check that the number of expected wheels matches the number of build
|
||||
# identifiers
|
||||
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
||||
build_identifiers = utils.cibuildwheel_get_build_identifiers(
|
||||
project_dir, prerelease_pythons=True
|
||||
)
|
||||
build_identifiers = utils.cibuildwheel_get_build_identifiers(project_dir)
|
||||
assert len(expected_wheels) == len(build_identifiers), (
|
||||
f"{expected_wheels} vs {build_identifiers}"
|
||||
)
|
||||
|
||||
+17
-18
@@ -35,36 +35,34 @@ def test_abi3(tmp_path):
|
||||
project_dir = tmp_path / "project"
|
||||
limited_api_project.generate(project_dir)
|
||||
|
||||
single_python_tag = "cp{}{}".format(*utils.SINGLE_PYTHON_VERSION)
|
||||
|
||||
# build the wheels
|
||||
actual_wheels = utils.cibuildwheel_run(
|
||||
project_dir,
|
||||
add_env={
|
||||
# free_threaded, GraalPy, and PyPy do not have a Py_LIMITED_API equivalent, just build one of those
|
||||
# also limit the number of builds for test performance reasons
|
||||
"CIBW_BUILD": f"cp39-* cp310-* pp310-* gp242-* {single_python_tag}-* cp313t-*"
|
||||
"CIBW_BUILD": "cp39-* cp310-* pp310-* gp242-* cp312-* cp313t-*",
|
||||
"CIBW_ENABLE": "all",
|
||||
},
|
||||
)
|
||||
|
||||
# check that the expected wheels are produced
|
||||
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
||||
if utils.platform == "pyodide":
|
||||
# there's only 1 possible configuration for pyodide, the single_python_tag one
|
||||
expected_wheels = [
|
||||
w.replace(f"{single_python_tag}-{single_python_tag}", "cp310-abi3")
|
||||
for w in expected_wheels
|
||||
]
|
||||
# there's only 1 possible configuration for pyodide, cp312
|
||||
expected_wheels = utils.expected_wheels("spam", "0.1.0", python_abi_tags=["cp310-abi3"])
|
||||
else:
|
||||
expected_wheels = [
|
||||
w.replace("cp310-cp310", "cp310-abi3")
|
||||
for w in expected_wheels
|
||||
if "-cp39" in w
|
||||
or "-cp310" in w
|
||||
or "-pp310" in w
|
||||
or "-graalpy242" in w
|
||||
or "-cp313t" in w
|
||||
]
|
||||
expected_wheels = utils.expected_wheels(
|
||||
"spam",
|
||||
"0.1.0",
|
||||
python_abi_tags=[
|
||||
"cp39-cp39",
|
||||
"cp310-abi3", # <-- ABI3, works with 3.10 and 3.12
|
||||
"cp313-cp313t",
|
||||
"pp310-pypy310_pp73",
|
||||
"graalpy311-graalpy242_311_native",
|
||||
],
|
||||
)
|
||||
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
|
||||
@@ -187,6 +185,7 @@ def test_abi_none(tmp_path, capfd):
|
||||
"CIBW_TEST_COMMAND": f"{utils.invoke_pytest()} ./test",
|
||||
# limit the number of builds for test performance reasons
|
||||
"CIBW_BUILD": "cp38-* cp{}{}-* cp313t-* pp310-*".format(*utils.SINGLE_PYTHON_VERSION),
|
||||
"CIBW_ENABLE": "all",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
+28
-19
@@ -23,6 +23,9 @@ from cibuildwheel.util.file import CIBW_CACHE_PATH
|
||||
EMULATED_ARCHS: Final[list[str]] = sorted(
|
||||
arch.value for arch in (Architecture.all_archs("linux") - Architecture.auto_archs("linux"))
|
||||
)
|
||||
PYPY_ARCHS = ["x86_64", "i686", "AMD64", "aarch64", "arm64"]
|
||||
GRAALPY_ARCHS = ["x86_64", "AMD64", "aarch64", "arm64"]
|
||||
|
||||
SINGLE_PYTHON_VERSION: Final[tuple[int, int]] = (3, 12)
|
||||
|
||||
_AARCH64_CAN_RUN_ARMV7: Final[bool] = Architecture.aarch64.value not in EMULATED_ARCHS and {
|
||||
@@ -46,7 +49,8 @@ else:
|
||||
|
||||
|
||||
def cibuildwheel_get_build_identifiers(
|
||||
project_path: Path, env: dict[str, str] | None = None, *, prerelease_pythons: bool = False
|
||||
project_path: Path,
|
||||
env: dict[str, str] | None = None,
|
||||
) -> list[str]:
|
||||
"""
|
||||
Returns the list of build identifiers that cibuildwheel will try to build
|
||||
@@ -55,9 +59,6 @@ def cibuildwheel_get_build_identifiers(
|
||||
cmd = [sys.executable, "-m", "cibuildwheel", "--print-build-identifiers", str(project_path)]
|
||||
if env is None:
|
||||
env = os.environ.copy()
|
||||
env["CIBW_ENABLE"] = "cpython-freethreading pypy graalpy"
|
||||
if prerelease_pythons:
|
||||
env["CIBW_ENABLE"] += " cpython-prerelease"
|
||||
|
||||
cmd_output = subprocess.run(
|
||||
cmd,
|
||||
@@ -121,8 +122,6 @@ def cibuildwheel_run(
|
||||
|
||||
_update_pip_cache_dir(env)
|
||||
|
||||
env["CIBW_ENABLE"] = " ".join(EnableGroup.all_groups())
|
||||
|
||||
if single_python:
|
||||
env["CIBW_BUILD"] = "cp{}{}-*".format(*SINGLE_PYTHON_VERSION)
|
||||
|
||||
@@ -222,6 +221,8 @@ def _expected_wheels(
|
||||
# {python tag} and {abi tag} are closely related to the python interpreter used to build the wheel
|
||||
# so we'll merge them below as python_abi_tag
|
||||
|
||||
enable_groups = EnableGroup.parse_option_value(os.environ.get("CIBW_ENABLE", ""))
|
||||
|
||||
if manylinux_versions is None:
|
||||
manylinux_versions = {
|
||||
"armv7l": ["manylinux_2_17", "manylinux2014", "manylinux_2_31"],
|
||||
@@ -243,25 +244,36 @@ def _expected_wheels(
|
||||
"cp311-cp311",
|
||||
"cp312-cp312",
|
||||
"cp313-cp313",
|
||||
"cp313-cp313t",
|
||||
]
|
||||
|
||||
if machine_arch == "ARM64":
|
||||
# no CPython 3.8 on Windows ARM64
|
||||
python_abi_tags.pop(0)
|
||||
if EnableGroup.CPythonFreeThreading in enable_groups:
|
||||
python_abi_tags += [
|
||||
"cp313-cp313t",
|
||||
]
|
||||
|
||||
if machine_arch in ["x86_64", "i686", "AMD64", "aarch64", "arm64"]:
|
||||
if EnableGroup.PyPy in enable_groups:
|
||||
python_abi_tags += [
|
||||
"pp38-pypy38_pp73",
|
||||
"pp39-pypy39_pp73",
|
||||
"pp310-pypy310_pp73",
|
||||
"pp311-pypy311_pp73",
|
||||
]
|
||||
if machine_arch in ["x86_64", "AMD64", "aarch64", "arm64"]:
|
||||
|
||||
if EnableGroup.GraalPy in enable_groups:
|
||||
python_abi_tags += [
|
||||
"graalpy311-graalpy242_311_native",
|
||||
]
|
||||
|
||||
if machine_arch == "ARM64" and platform == "windows":
|
||||
# no CPython 3.8 on Windows ARM64
|
||||
python_abi_tags = [t for t in python_abi_tags if not t.startswith("cp38")]
|
||||
|
||||
if machine_arch not in PYPY_ARCHS:
|
||||
python_abi_tags = [tag for tag in python_abi_tags if not tag.startswith("pp")]
|
||||
|
||||
if machine_arch not in GRAALPY_ARCHS:
|
||||
python_abi_tags = [tag for tag in python_abi_tags if not tag.startswith("graalpy")]
|
||||
|
||||
if single_python:
|
||||
python_tag = "cp{}{}-".format(*SINGLE_PYTHON_VERSION)
|
||||
python_abi_tags = [
|
||||
@@ -272,13 +284,6 @@ def _expected_wheels(
|
||||
)
|
||||
]
|
||||
|
||||
if platform == "pyodide":
|
||||
assert len(python_abi_tags) == 1
|
||||
python_abi_tag = python_abi_tags[0]
|
||||
platform_tag = "pyodide_2024_0_wasm32"
|
||||
yield f"{package_name}-{package_version}-{python_abi_tag}-{platform_tag}.whl"
|
||||
return
|
||||
|
||||
for python_abi_tag in python_abi_tags:
|
||||
platform_tags = []
|
||||
|
||||
@@ -327,6 +332,10 @@ def _expected_wheels(
|
||||
|
||||
if include_universal2:
|
||||
platform_tags.append(f"macosx_{min_macosx.replace('.', '_')}_universal2")
|
||||
|
||||
elif platform == "pyodide":
|
||||
platform_tags = ["pyodide_2024_0_wasm32"]
|
||||
|
||||
else:
|
||||
msg = f"Unsupported platform {platform!r}"
|
||||
raise Exception(msg)
|
||||
|
||||
Reference in New Issue
Block a user