import sys from fnmatch import fnmatch from pathlib import Path import pytest from cibuildwheel.__main__ import main from cibuildwheel.environment import ParsedEnvironment from cibuildwheel.util import BuildSelector # CIBW_PLATFORM is tested in main_platform_test.py def test_output_dir(platform, intercepted_build_args, monkeypatch): OUTPUT_DIR = Path("some_output_dir") monkeypatch.setenv("CIBW_OUTPUT_DIR", str(OUTPUT_DIR)) main() assert intercepted_build_args.args[0].output_dir == OUTPUT_DIR def test_output_dir_default(platform, intercepted_build_args, monkeypatch): main() assert intercepted_build_args.args[0].output_dir == Path("wheelhouse") @pytest.mark.parametrize("also_set_environment", [False, True]) def test_output_dir_argument(also_set_environment, platform, intercepted_build_args, monkeypatch): OUTPUT_DIR = Path("some_output_dir") monkeypatch.setattr(sys, "argv", sys.argv + ["--output-dir", str(OUTPUT_DIR)]) if also_set_environment: monkeypatch.setenv("CIBW_OUTPUT_DIR", "not_this_output_dir") main() assert intercepted_build_args.args[0].output_dir == OUTPUT_DIR def test_build_selector(platform, intercepted_build_args, monkeypatch, allow_empty): BUILD = "some build* *-selector" SKIP = "some skip* *-selector" monkeypatch.setenv("CIBW_BUILD", BUILD) monkeypatch.setenv("CIBW_SKIP", SKIP) main() intercepted_build_selector = intercepted_build_args.args[0].build_selector assert isinstance(intercepted_build_selector, BuildSelector) assert intercepted_build_selector("build24-this") assert not intercepted_build_selector("skip65-that") # This unit test is just testing the options of 'main' # Unit tests for BuildSelector are in build_selector_test.py def test_empty_selector(platform, intercepted_build_args, monkeypatch): monkeypatch.setenv("CIBW_SKIP", "*") with pytest.raises(SystemExit) as e: main() assert e.value.code == 3 @pytest.mark.parametrize( "architecture, image, full_image", [ ("x86_64", None, "quay.io/pypa/manylinux2010_x86_64:*"), ("x86_64", "manylinux1", "quay.io/pypa/manylinux1_x86_64:*"), ("x86_64", "manylinux2010", "quay.io/pypa/manylinux2010_x86_64:*"), ("x86_64", "manylinux2014", "quay.io/pypa/manylinux2014_x86_64:*"), ("x86_64", "manylinux_2_24", "quay.io/pypa/manylinux_2_24_x86_64:*"), ("x86_64", "custom_image", "custom_image"), ("i686", None, "quay.io/pypa/manylinux2010_i686:*"), ("i686", "manylinux1", "quay.io/pypa/manylinux1_i686:*"), ("i686", "manylinux2010", "quay.io/pypa/manylinux2010_i686:*"), ("i686", "manylinux2014", "quay.io/pypa/manylinux2014_i686:*"), ("i686", "manylinux_2_24", "quay.io/pypa/manylinux_2_24_i686:*"), ("i686", "custom_image", "custom_image"), ("pypy_x86_64", None, "quay.io/pypa/manylinux2010_x86_64:*"), ("pypy_x86_64", "manylinux1", "manylinux1"), # Does not exist ("pypy_x86_64", "manylinux2010", "quay.io/pypa/manylinux2010_x86_64:*"), ("pypy_x86_64", "manylinux2014", "quay.io/pypa/manylinux2014_x86_64:*"), ("pypy_x86_64", "manylinux_2_24", "quay.io/pypa/manylinux_2_24_x86_64:*"), ("pypy_x86_64", "custom_image", "custom_image"), ], ) def test_manylinux_images( architecture, image, full_image, platform, intercepted_build_args, monkeypatch ): if image is not None: monkeypatch.setenv("CIBW_MANYLINUX_" + architecture.upper() + "_IMAGE", image) main() if platform == "linux": assert fnmatch(intercepted_build_args.args[0].manylinux_images[architecture], full_image) else: assert intercepted_build_args.args[0].manylinux_images is None def get_default_repair_command(platform): if platform == "linux": return "auditwheel repair -w {dest_dir} {wheel}" elif platform == "macos": return "delocate-listdeps {wheel} && delocate-wheel --require-archs {delocate_archs} -w {dest_dir} {wheel}" elif platform == "windows": return "" else: raise ValueError("Unknown platform", platform) @pytest.mark.parametrize("repair_command", [None, "repair", "repair -w {dest_dir} {wheel}"]) @pytest.mark.parametrize("platform_specific", [False, True]) def test_repair_command( repair_command, platform_specific, platform, intercepted_build_args, monkeypatch ): if repair_command is not None: if platform_specific: monkeypatch.setenv("CIBW_REPAIR_WHEEL_COMMAND_" + platform.upper(), repair_command) monkeypatch.setenv("CIBW_REPAIR_WHEEL_COMMAND", "overwritten") else: monkeypatch.setenv("CIBW_REPAIR_WHEEL_COMMAND", repair_command) main() expected_repair = repair_command or get_default_repair_command(platform) assert intercepted_build_args.args[0].repair_command == expected_repair @pytest.mark.parametrize( "environment", [{}, {"something": "value"}, {"something": "value", "something_else": "other_value"}], ) @pytest.mark.parametrize("platform_specific", [False, True]) def test_environment(environment, platform_specific, platform, intercepted_build_args, monkeypatch): env_string = " ".join(f"{k}={v}" for k, v in environment.items()) if platform_specific: monkeypatch.setenv("CIBW_ENVIRONMENT_" + platform.upper(), env_string) monkeypatch.setenv("CIBW_ENVIRONMENT", "overwritten") else: monkeypatch.setenv("CIBW_ENVIRONMENT", env_string) main() intercepted_environment = intercepted_build_args.args[0].environment assert isinstance(intercepted_environment, ParsedEnvironment) assert intercepted_environment.as_dictionary(prev_environment={}) == environment @pytest.mark.parametrize("test_requires", [None, "requirement other_requirement"]) @pytest.mark.parametrize("platform_specific", [False, True]) def test_test_requires( test_requires, platform_specific, platform, intercepted_build_args, monkeypatch ): if test_requires is not None: if platform_specific: monkeypatch.setenv("CIBW_TEST_REQUIRES_" + platform.upper(), test_requires) monkeypatch.setenv("CIBW_TEST_REQUIRES", "overwritten") else: monkeypatch.setenv("CIBW_TEST_REQUIRES", test_requires) main() assert intercepted_build_args.args[0].test_requires == (test_requires or "").split() @pytest.mark.parametrize("test_extras", [None, "extras"]) @pytest.mark.parametrize("platform_specific", [False, True]) def test_test_extras(test_extras, platform_specific, platform, intercepted_build_args, monkeypatch): if test_extras is not None: if platform_specific: monkeypatch.setenv("CIBW_TEST_EXTRAS_" + platform.upper(), test_extras) monkeypatch.setenv("CIBW_TEST_EXTRAS", "overwritten") else: monkeypatch.setenv("CIBW_TEST_EXTRAS", test_extras) main() assert intercepted_build_args.args[0].test_extras == ( "[" + test_extras + "]" if test_extras else "" ) @pytest.mark.parametrize("test_command", [None, "test --command"]) @pytest.mark.parametrize("platform_specific", [False, True]) def test_test_command( test_command, platform_specific, platform, intercepted_build_args, monkeypatch ): if test_command is not None: if platform_specific: monkeypatch.setenv("CIBW_TEST_COMMAND_" + platform.upper(), test_command) monkeypatch.setenv("CIBW_TEST_COMMAND", "overwritten") else: monkeypatch.setenv("CIBW_TEST_COMMAND", test_command) main() assert intercepted_build_args.args[0].test_command == (test_command or "") @pytest.mark.parametrize("before_build", [None, "before --build"]) @pytest.mark.parametrize("platform_specific", [False, True]) def test_before_build( before_build, platform_specific, platform, intercepted_build_args, monkeypatch ): if before_build is not None: if platform_specific: monkeypatch.setenv("CIBW_BEFORE_BUILD_" + platform.upper(), before_build) monkeypatch.setenv("CIBW_BEFORE_BUILD", "overwritten") else: monkeypatch.setenv("CIBW_BEFORE_BUILD", before_build) main() assert intercepted_build_args.args[0].before_build == (before_build or "") @pytest.mark.parametrize("build_verbosity", [None, 0, 2, -2, 4, -4]) @pytest.mark.parametrize("platform_specific", [False, True]) def test_build_verbosity( build_verbosity, platform_specific, platform, intercepted_build_args, monkeypatch ): if build_verbosity is not None: if platform_specific: monkeypatch.setenv("CIBW_BUILD_VERBOSITY_" + platform.upper(), str(build_verbosity)) monkeypatch.setenv("CIBW_BUILD_VERBOSITY", "overwritten") else: monkeypatch.setenv("CIBW_BUILD_VERBOSITY", str(build_verbosity)) main() expected_verbosity = max(-3, min(3, int(build_verbosity or 0))) assert intercepted_build_args.args[0].build_verbosity == expected_verbosity @pytest.mark.parametrize( "selector", [ "CIBW_BUILD", "CIBW_SKIP", "CIBW_TEST_SKIP", ], ) @pytest.mark.parametrize( "pattern", [ "cp27-*", "cp35-*", "?p27*", "?p2*", "?p35*", ], ) def test_build_selector_deprecated_error( monkeypatch, platform, intercepted_build_args, selector, pattern, allow_empty, capsys ): monkeypatch.setenv(selector, pattern) if selector == "CIBW_BUILD": with pytest.raises(SystemExit) as ex: main() assert ex.value.code == 4 else: main() stderr = capsys.readouterr().err msg = f"cibuildwheel 2.x no longer supports Python < 3.6. Please use the 1.x series or update {selector}" assert msg in stderr @pytest.mark.parametrize("before_all", ["", None, "test text"]) @pytest.mark.parametrize("platform_specific", [False, True]) def test_before_all(before_all, platform_specific, platform, intercepted_build_args, monkeypatch): if before_all is not None: if platform_specific: monkeypatch.setenv("CIBW_BEFORE_ALL_" + platform.upper(), before_all) monkeypatch.setenv("CIBW_BEFORE_ALL", "overwritten") else: monkeypatch.setenv("CIBW_BEFORE_ALL", before_all) main() assert intercepted_build_args.args[0].before_all == (before_all or "")