Files
cibuildwheel/test/test_macos_archs.py
T
26e12290b5 feat: add support for building iOS wheels. (#2286)
* Add support for building iOS wheels.

* Replace use of system() in test binary module.

* Restored the 'minimal' approach of the minimal examples.

* Split out platform details into standalone pages, and expand iOS platform details.

* More doc corrections.

* Bump support package to include fix for python/cpython#130292

* Ensure iOS tests are all run on the same xdist worker.

* More iOS documentation tweaks.

* Factor out common xcode version test utility.

* Simplify iOS to a single platform with an expanded interpretation of arch.

* I guess I should update the iOS tests as well...

* Additional safety for missing iOS test output.

* Remove DYLD_LIBRARY_PATH from the iOS environment.

* Make test-sources mandatory for iOS builds.

* Updates and clarifications to documentation.

* Clarify what a slice is.

* Normalize use of underscores in platform name.

* Modify auto target to be matching CPU only.

* Use consistent ordering of platforms in examples.

* Use consistent naming in iOS archiectures.

* Placate the linter.

* Miscellaneous cleanups picked up by @joerick's review.

* Correct the list of expected wheels.

* Correct which 'native' we're actually checking.

* Correct the docs links so they're all relative.

* Correct the identification of free threaded builds.

* Use target instead of host to describe the platform we're building for.

* Rework iOS test to remove issue with log completeness.

* Convert errors to FatalError

Co-authored-by: Matthieu Darbois <mayeut@users.noreply.github.com>
Co-authored-by: Joe Rickerby <joerick@mac.com>

* Removed a repeated check for a valid python.

* Update bin/update_pythons.py to update iOS support packages.

* Document that iOS CI is available on other platforms.

* Restore a comment needed for some platforms.

* Small cleanups identified in code review

Co-authored-by: Joe Rickerby <joerick@mac.com>

* Simplify logic to appease linter.

* Modify dependency constraint handling to use new API.

* Cosmetic change to trigger a CI rebuild.

---------

Co-authored-by: Matthieu Darbois <mayeut@users.noreply.github.com>
Co-authored-by: Joe Rickerby <joerick@mac.com>
2025-03-11 16:48:35 -04:00

271 lines
9.7 KiB
Python

import platform
import pytest
from . import test_projects, utils
basic_project = test_projects.new_c_project()
basic_project.files["tests/test_suite.py"] = r"""
import platform
print("running tests on " + platform.machine())
"""
ALL_MACOS_WHEELS = {
*utils.expected_wheels("spam", "0.1.0", machine_arch="x86_64"),
*utils.expected_wheels("spam", "0.1.0", machine_arch="arm64", include_universal2=True),
}
DEPLOYMENT_TARGET_TOO_LOW_WARNING = "Bumping MACOSX_DEPLOYMENT_TARGET"
def test_cross_compiled_build(tmp_path):
if utils.platform != "macos":
pytest.skip("this test is only relevant to macos")
if utils.get_xcode_version() < (12, 2):
pytest.skip("this test only works with Xcode 12.2 or greater")
project_dir = tmp_path / "project"
basic_project.generate(project_dir)
actual_wheels = utils.cibuildwheel_run(
project_dir,
add_env={"CIBW_ARCHS": "x86_64, universal2, arm64"},
single_python=True,
)
python_tag = "cp{}{}".format(*utils.SINGLE_PYTHON_VERSION)
expected_wheels = [w for w in ALL_MACOS_WHEELS if python_tag in w]
assert set(actual_wheels) == set(expected_wheels)
@pytest.mark.parametrize("build_universal2", [False, True])
@pytest.mark.parametrize(
"test_config",
[
# Run the test suite in the project folder
{
"CIBW_TEST_COMMAND": '''python -c "import platform; print('running tests on ' + platform.machine())"''',
},
# Nominate the set of test sources to copy
{
"CIBW_TEST_COMMAND": "python tests/test_suite.py",
"CIBW_TEST_SOURCES": "tests",
},
],
)
def test_cross_compiled_test(tmp_path, capfd, build_universal2, test_config):
if utils.platform != "macos":
pytest.skip("this test is only relevant to macos")
if utils.get_xcode_version() < (12, 2):
pytest.skip("this test only works with Xcode 12.2 or greater")
project_dir = tmp_path / "project"
basic_project.generate(project_dir)
actual_wheels = utils.cibuildwheel_run(
project_dir,
add_env={
"CIBW_BUILD": "cp310-*" if build_universal2 else "*p310-*",
"CIBW_ARCHS": "universal2" if build_universal2 else "x86_64 arm64",
"CIBW_BUILD_VERBOSITY": "3",
**test_config,
},
)
captured = capfd.readouterr()
assert DEPLOYMENT_TARGET_TOO_LOW_WARNING not in captured.err
platform_machine = platform.machine()
if platform_machine == "x86_64":
# ensure that tests were run on only x86_64
assert "running tests on x86_64" in captured.out
assert "running tests on arm64" not in captured.out
if build_universal2:
assert (
"While universal2 wheels can be built on x86_64, the arm64 part of the wheel cannot be tested"
in captured.err
)
else:
assert (
"While arm64 wheels can be built on x86_64, they cannot be tested" in captured.err
)
elif platform_machine == "arm64":
# ensure that tests were run on both x86_64 and arm64
assert "running tests on x86_64" in captured.out
assert "running tests on arm64" in captured.out
assert (
"While universal2 wheels can be built on x86_64, the arm64 part of the wheel cannot be tested"
not in captured.err
)
assert (
"While arm64 wheels can be built on x86_64, they cannot be tested" not in captured.err
)
if build_universal2:
expected_wheels = [w for w in ALL_MACOS_WHEELS if "cp310" in w and "universal2" in w]
else:
expected_wheels = [w for w in ALL_MACOS_WHEELS if "p310-" in w and "universal2" not in w]
if platform_machine == "x86_64":
expected_wheels = [w for w in expected_wheels if not ("pp310" in w and "arm64" in w)]
assert set(actual_wheels) == set(expected_wheels)
def test_deployment_target_warning_is_firing(tmp_path, capfd):
# force the warning to check that we can detect it if it happens
if utils.platform != "macos":
pytest.skip("this test is only relevant to macos")
project_dir = tmp_path / "project"
basic_project.generate(project_dir)
utils.cibuildwheel_run(
project_dir,
add_env={
"CIBW_ARCHS": "x86_64",
"MACOSX_DEPLOYMENT_TARGET": "10.8",
"CIBW_BUILD_VERBOSITY": "3",
},
single_python=True,
)
captured = capfd.readouterr()
assert DEPLOYMENT_TARGET_TOO_LOW_WARNING in captured.err
@pytest.mark.parametrize("skip_arm64_test", [False, True])
def test_universal2_testing_on_x86_64(tmp_path, capfd, skip_arm64_test):
if utils.platform != "macos":
pytest.skip("this test is only relevant to macos")
if utils.get_xcode_version() < (12, 2):
pytest.skip("this test only works with Xcode 12.2 or greater")
if platform.machine() != "x86_64":
pytest.skip("this test only works on x86_64")
project_dir = tmp_path / "project"
basic_project.generate(project_dir)
actual_wheels = utils.cibuildwheel_run(
project_dir,
add_env={
"CIBW_TEST_COMMAND": '''python -c "import platform; print('running tests on ' + platform.machine())"''',
"CIBW_ARCHS": "universal2",
"CIBW_TEST_SKIP": "*_universal2:arm64" if skip_arm64_test else "",
},
single_python=True,
)
captured = capfd.readouterr()
if platform.machine() == "x86_64":
assert "running tests on x86_64" in captured.out
assert "running tests on arm64" not in captured.out
warning_message = "While universal2 wheels can be built on x86_64, the arm64 part of the wheel cannot be tested"
if skip_arm64_test:
assert warning_message not in captured.err
else:
assert warning_message in captured.err
python_tag = "cp{}{}".format(*utils.SINGLE_PYTHON_VERSION)
expected_wheels = [w for w in ALL_MACOS_WHEELS if python_tag in w and "universal2" in w]
assert set(actual_wheels) == set(expected_wheels)
def test_universal2_testing_on_arm64(build_frontend_env, tmp_path, capfd):
# cibuildwheel should test the universal2 wheel on both x86_64 and arm64, when run on arm64
if utils.platform != "macos":
pytest.skip("this test is only relevant to macos")
if platform.machine() != "arm64":
pytest.skip("this test only works on arm64")
project_dir = tmp_path / "project"
basic_project.generate(project_dir)
actual_wheels = utils.cibuildwheel_run(
project_dir,
add_env={
"CIBW_ARCHS": "universal2",
# check that a native dependency is correctly installed, once per each testing arch
"CIBW_TEST_REQUIRES": "--only-binary :all: pillow>=10.3", # pillow>=10.3 provides wheels for macOS 10.10, not 10.9
"CIBW_TEST_COMMAND": '''python -c "import PIL, platform; print(f'running tests on {platform.machine()} with pillow {PIL.__version__}')"''',
**build_frontend_env,
},
single_python=True,
)
captured = capfd.readouterr()
assert "running tests on arm64 with pillow" in captured.out
assert "running tests on x86_64 with pillow" in captured.out
python_tag = "cp{}{}".format(*utils.SINGLE_PYTHON_VERSION)
expected_wheels = [w for w in ALL_MACOS_WHEELS if python_tag in w and "universal2" in w]
assert set(actual_wheels) == set(expected_wheels)
def test_cp38_arm64_testing(tmp_path, capfd, request):
if utils.platform != "macos":
pytest.skip("this test is only relevant to macos")
if utils.get_xcode_version() < (12, 2):
pytest.skip("this test only works with Xcode 12.2 or greater")
if platform.machine() != "arm64":
pytest.skip("this test only works on arm64")
if request.config.getoption("--run-cp38-universal2"):
pytest.skip("--run-cp38-universal2 option skips this test")
project_dir = tmp_path / "project"
basic_project.generate(project_dir)
actual_wheels = utils.cibuildwheel_run(
project_dir,
add_env={
"CIBW_BUILD": "cp38-*",
"CIBW_TEST_COMMAND": '''python -c "import platform; print('running tests on ' + platform.machine())"''',
"CIBW_ARCHS": "x86_64,universal2,arm64",
},
)
captured = capfd.readouterr()
assert "running tests on x86_64" in captured.out
assert "running tests on arm64" not in captured.out
warning_message = "While cibuildwheel can build CPython 3.8 universal2/arm64 wheels, we cannot test the arm64 part of them"
assert warning_message in captured.err
expected_wheels = [w for w in ALL_MACOS_WHEELS if "cp38" in w]
assert set(actual_wheels) == set(expected_wheels)
def test_cp38_arm64_testing_universal2_installer(tmp_path, capfd, request):
if not request.config.getoption("--run-cp38-universal2"):
pytest.skip("needs --run-cp38-universal2 option to run")
project_dir = tmp_path / "project"
basic_project.generate(project_dir)
actual_wheels = utils.cibuildwheel_run(
project_dir,
add_env={
"CIBW_BUILD": "cp38-*",
"CIBW_TEST_COMMAND": '''python -c "import platform; print('running tests on ' + platform.machine())"''',
"CIBW_ARCHS": "x86_64,universal2,arm64",
"MACOSX_DEPLOYMENT_TARGET": "11.0",
},
)
captured = capfd.readouterr()
assert "running tests on x86_64" in captured.out
assert "running tests on arm64" in captured.out
warning_message = "While cibuildwheel can build CPython 3.8 universal2/arm64 wheels, we cannot test the arm64 part of them"
assert warning_message not in captured.err
expected_wheels = [w.replace("10_9", "11_0") for w in ALL_MACOS_WHEELS if "cp38" in w]
assert set(actual_wheels) == set(expected_wheels)