style: activate string normalization
This commit is contained in:
committed by
Henry Schreiner
parent
d1900f6a05
commit
bda76b21cb
+12
-12
@@ -9,38 +9,38 @@ from . import test_projects, utils
|
||||
|
||||
basic_project = test_projects.new_c_project(
|
||||
setup_py_add=textwrap.dedent(
|
||||
'''
|
||||
"""
|
||||
import os
|
||||
|
||||
if os.environ.get("CIBUILDWHEEL", "0") != "1":
|
||||
raise Exception("CIBUILDWHEEL environment variable is not set to 1")
|
||||
'''
|
||||
"""
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def test(tmp_path):
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
basic_project.generate(project_dir)
|
||||
|
||||
# build the wheels
|
||||
actual_wheels = utils.cibuildwheel_run(project_dir)
|
||||
|
||||
# check that the expected wheels are produced
|
||||
expected_wheels = utils.expected_wheels('spam', '0.1.0')
|
||||
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
|
||||
@pytest.mark.skip(reason='to keep test output clean')
|
||||
@pytest.mark.skip(reason="to keep test output clean")
|
||||
def test_sample_build(tmp_path, capfd):
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
basic_project.generate(project_dir)
|
||||
|
||||
# build the wheels, and let the output passthrough to the caller, so
|
||||
# we can see how it looks
|
||||
with capfd.disabled():
|
||||
logger = Logger()
|
||||
logger.step('test_sample_build')
|
||||
logger.step("test_sample_build")
|
||||
try:
|
||||
utils.cibuildwheel_run(project_dir)
|
||||
finally:
|
||||
@@ -48,7 +48,7 @@ def test_sample_build(tmp_path, capfd):
|
||||
|
||||
|
||||
def test_build_identifiers(tmp_path):
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
basic_project.generate(project_dir)
|
||||
|
||||
# check that the number of expected wheels matches the number of build
|
||||
@@ -56,13 +56,13 @@ def test_build_identifiers(tmp_path):
|
||||
# after adding CIBW_MANYLINUX_IMAGE to support manylinux2010, there
|
||||
# can be multiple wheels for each wheel, though, so we need to limit
|
||||
# the expected wheels
|
||||
if platform.machine() in ['x86_64', 'i686']:
|
||||
if platform.machine() in ["x86_64", "i686"]:
|
||||
expected_wheels = [
|
||||
w
|
||||
for w in utils.expected_wheels('spam', '0.1.0')
|
||||
if '-manylinux' not in w or '-manylinux1' in w
|
||||
for w in utils.expected_wheels("spam", "0.1.0")
|
||||
if "-manylinux" not in w or "-manylinux1" in w
|
||||
]
|
||||
else:
|
||||
expected_wheels = utils.expected_wheels('spam', '0.1.0')
|
||||
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
||||
build_identifiers = utils.cibuildwheel_get_build_identifiers(project_dir)
|
||||
assert len(expected_wheels) == len(build_identifiers)
|
||||
|
||||
+16
-16
@@ -7,7 +7,7 @@ from . import test_projects, utils
|
||||
|
||||
project_with_before_build_asserts = test_projects.new_c_project(
|
||||
setup_py_add=textwrap.dedent(
|
||||
r'''
|
||||
r"""
|
||||
# assert that the Python version as written to text_info.txt in the CIBW_BEFORE_ALL step
|
||||
# is the same one as is currently running.
|
||||
with open("text_info.txt") as f:
|
||||
@@ -15,16 +15,16 @@ project_with_before_build_asserts = test_projects.new_c_project(
|
||||
|
||||
print("## stored text: " + stored_text)
|
||||
assert stored_text == "sample text 123"
|
||||
'''
|
||||
"""
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def test(tmp_path):
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
project_with_before_build_asserts.generate(project_dir)
|
||||
|
||||
with (project_dir / 'text_info.txt').open(mode='w') as ff:
|
||||
with (project_dir / "text_info.txt").open(mode="w") as ff:
|
||||
print("dummy text", file=ff)
|
||||
|
||||
# build the wheels
|
||||
@@ -34,43 +34,43 @@ def test(tmp_path):
|
||||
add_env={
|
||||
# write python version information to a temporary file, this is
|
||||
# checked in setup.py
|
||||
'CIBW_BEFORE_ALL': before_all_command,
|
||||
'CIBW_BEFORE_ALL_LINUX': f'{before_all_command} && python -c "import sys; assert sys.version_info >= (3, 6)"',
|
||||
'CIBW_ENVIRONMENT': "TEST_VAL='123'",
|
||||
"CIBW_BEFORE_ALL": before_all_command,
|
||||
"CIBW_BEFORE_ALL_LINUX": f'{before_all_command} && python -c "import sys; assert sys.version_info >= (3, 6)"',
|
||||
"CIBW_ENVIRONMENT": "TEST_VAL='123'",
|
||||
},
|
||||
)
|
||||
|
||||
# also check that we got the right wheels
|
||||
(project_dir / 'text_info.txt').unlink()
|
||||
expected_wheels = utils.expected_wheels('spam', '0.1.0')
|
||||
(project_dir / "text_info.txt").unlink()
|
||||
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
|
||||
def test_failing_command(tmp_path):
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
test_projects.new_c_project().generate(project_dir)
|
||||
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
utils.cibuildwheel_run(
|
||||
project_dir,
|
||||
add_env={
|
||||
'CIBW_BEFORE_ALL': 'false',
|
||||
'CIBW_BEFORE_ALL_WINDOWS': 'exit /b 1',
|
||||
"CIBW_BEFORE_ALL": "false",
|
||||
"CIBW_BEFORE_ALL_WINDOWS": "exit /b 1",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def test_cwd(tmp_path):
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
test_projects.new_c_project().generate(project_dir)
|
||||
|
||||
actual_wheels = utils.cibuildwheel_run(
|
||||
project_dir,
|
||||
add_env={
|
||||
'CIBW_BEFORE_ALL': f'''python -c "import os; assert os.getcwd() == {str(project_dir)!r}"''',
|
||||
'CIBW_BEFORE_ALL_LINUX': '''python -c "import os; assert os.getcwd() == '/project'"''',
|
||||
"CIBW_BEFORE_ALL": f'''python -c "import os; assert os.getcwd() == {str(project_dir)!r}"''',
|
||||
"CIBW_BEFORE_ALL_LINUX": '''python -c "import os; assert os.getcwd() == '/project'"''',
|
||||
},
|
||||
)
|
||||
|
||||
expected_wheels = utils.expected_wheels('spam', '0.1.0')
|
||||
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
+14
-14
@@ -7,7 +7,7 @@ from . import test_projects, utils
|
||||
|
||||
project_with_before_build_asserts = test_projects.new_c_project(
|
||||
setup_py_add=textwrap.dedent(
|
||||
r'''
|
||||
r"""
|
||||
import os
|
||||
|
||||
# assert that the Python version as written to pythonversion.txt in the CIBW_BEFORE_BUILD step
|
||||
@@ -27,17 +27,17 @@ project_with_before_build_asserts = test_projects.new_c_project(
|
||||
print('sys.executable', sys.executable)
|
||||
# windows/mac are case insensitive
|
||||
assert os.path.realpath(stored_executable).lower() == os.path.realpath(sys.executable).lower()
|
||||
'''
|
||||
"""
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def test(tmp_path):
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
project_with_before_build_asserts.generate(project_dir)
|
||||
|
||||
before_build = (
|
||||
'''python -c "import sys; open('{output_dir}pythonversion.txt', 'w').write(sys.version)" && '''
|
||||
"""python -c "import sys; open('{output_dir}pythonversion.txt', 'w').write(sys.version)" && """
|
||||
'''python -c "import sys; open('{output_dir}pythonexecutable.txt', 'w').write(sys.executable)"'''
|
||||
)
|
||||
|
||||
@@ -47,41 +47,41 @@ def test(tmp_path):
|
||||
add_env={
|
||||
# write python version information to a temporary file, this is
|
||||
# checked in setup.py
|
||||
'CIBW_BEFORE_BUILD': before_build.format(output_dir='/tmp/'),
|
||||
'CIBW_BEFORE_BUILD_WINDOWS': before_build.format(output_dir=r'c:\\'),
|
||||
"CIBW_BEFORE_BUILD": before_build.format(output_dir="/tmp/"),
|
||||
"CIBW_BEFORE_BUILD_WINDOWS": before_build.format(output_dir=r"c:\\"),
|
||||
},
|
||||
)
|
||||
|
||||
# also check that we got the right wheels
|
||||
expected_wheels = utils.expected_wheels('spam', '0.1.0')
|
||||
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
|
||||
def test_failing_command(tmp_path):
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
test_projects.new_c_project().generate(project_dir)
|
||||
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
utils.cibuildwheel_run(
|
||||
project_dir,
|
||||
add_env={
|
||||
'CIBW_BEFORE_BUILD': 'false',
|
||||
'CIBW_BEFORE_BUILD_WINDOWS': 'exit /b 1',
|
||||
"CIBW_BEFORE_BUILD": "false",
|
||||
"CIBW_BEFORE_BUILD_WINDOWS": "exit /b 1",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def test_cwd(tmp_path):
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
test_projects.new_c_project().generate(project_dir)
|
||||
|
||||
actual_wheels = utils.cibuildwheel_run(
|
||||
project_dir,
|
||||
add_env={
|
||||
'CIBW_BEFORE_BUILD': f'''python -c "import os; assert os.getcwd() == {str(project_dir)!r}"''',
|
||||
'CIBW_BEFORE_BUILD_LINUX': '''python -c "import os; assert os.getcwd() == '/project'"''',
|
||||
"CIBW_BEFORE_BUILD": f'''python -c "import os; assert os.getcwd() == {str(project_dir)!r}"''',
|
||||
"CIBW_BEFORE_BUILD_LINUX": '''python -c "import os; assert os.getcwd() == '/project'"''',
|
||||
},
|
||||
)
|
||||
|
||||
expected_wheels = utils.expected_wheels('spam', '0.1.0')
|
||||
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
+11
-11
@@ -2,8 +2,8 @@ from . import test_projects, utils
|
||||
|
||||
before_test_project = test_projects.new_c_project()
|
||||
before_test_project.files[
|
||||
'test/spam_test.py'
|
||||
] = r'''
|
||||
"test/spam_test.py"
|
||||
] = r"""
|
||||
import sys
|
||||
import os
|
||||
from unittest import TestCase
|
||||
@@ -32,13 +32,13 @@ class TestBeforeTest(TestCase):
|
||||
# vssadm~1 instead of vssadministrator
|
||||
|
||||
assert os.stat(stored_prefix) == os.stat(sys.prefix)
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
def test(tmp_path):
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
before_test_project.generate(project_dir)
|
||||
test_project_dir = project_dir / 'dependency'
|
||||
test_project_dir = project_dir / "dependency"
|
||||
test_projects.new_c_project().generate(test_project_dir)
|
||||
|
||||
# build the wheels
|
||||
@@ -47,16 +47,16 @@ def test(tmp_path):
|
||||
add_env={
|
||||
# write python version information to a temporary file, this is
|
||||
# checked in setup.py
|
||||
'CIBW_BEFORE_TEST': '''python -c "import sys; open('/tmp/pythonversion.txt', 'w').write(sys.version)" && python -c "import sys; open('/tmp/pythonprefix.txt', 'w').write(sys.prefix)" && python -m pip install {project}/dependency''',
|
||||
'CIBW_BEFORE_TEST_WINDOWS': '''python -c "import sys; open('c:\\pythonversion.txt', 'w').write(sys.version)" && python -c "import sys; open('c:\\pythonprefix.txt', 'w').write(sys.prefix)" && python -m pip install {project}/dependency''',
|
||||
'CIBW_TEST_REQUIRES': 'nose',
|
||||
"CIBW_BEFORE_TEST": """python -c "import sys; open('/tmp/pythonversion.txt', 'w').write(sys.version)" && python -c "import sys; open('/tmp/pythonprefix.txt', 'w').write(sys.prefix)" && python -m pip install {project}/dependency""",
|
||||
"CIBW_BEFORE_TEST_WINDOWS": """python -c "import sys; open('c:\\pythonversion.txt', 'w').write(sys.version)" && python -c "import sys; open('c:\\pythonprefix.txt', 'w').write(sys.prefix)" && python -m pip install {project}/dependency""",
|
||||
"CIBW_TEST_REQUIRES": "nose",
|
||||
# the 'false ||' bit is to ensure this command runs in a shell on
|
||||
# mac/linux.
|
||||
'CIBW_TEST_COMMAND': 'false || nosetests {project}/test',
|
||||
'CIBW_TEST_COMMAND_WINDOWS': 'nosetests {project}/test',
|
||||
"CIBW_TEST_COMMAND": "false || nosetests {project}/test",
|
||||
"CIBW_TEST_COMMAND_WINDOWS": "nosetests {project}/test",
|
||||
},
|
||||
)
|
||||
|
||||
# also check that we got the right wheels
|
||||
expected_wheels = utils.expected_wheels('spam', '0.1.0')
|
||||
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
@@ -4,32 +4,32 @@ from . import test_projects, utils
|
||||
|
||||
project_with_skip_asserts = test_projects.new_c_project(
|
||||
setup_py_add=textwrap.dedent(
|
||||
r'''
|
||||
r"""
|
||||
# explode if run on Python 2.7 or Python 3.7 (these should be skipped)
|
||||
if sys.version_info[0:2] == (2, 7):
|
||||
raise Exception("Python 2.7 should not be built")
|
||||
if sys.version_info[0:2] == (3, 7):
|
||||
raise Exception("Python 3.7 should be skipped")
|
||||
'''
|
||||
"""
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def test(tmp_path):
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
project_with_skip_asserts.generate(project_dir)
|
||||
|
||||
# build the wheels
|
||||
actual_wheels = utils.cibuildwheel_run(
|
||||
project_dir,
|
||||
add_env={
|
||||
'CIBW_BUILD': 'cp3?-*',
|
||||
'CIBW_SKIP': 'cp37-*',
|
||||
"CIBW_BUILD": "cp3?-*",
|
||||
"CIBW_SKIP": "cp37-*",
|
||||
},
|
||||
)
|
||||
|
||||
# check that we got the right wheels. There should be no 2.7 or 3.7.
|
||||
expected_wheels = [
|
||||
w for w in utils.expected_wheels('spam', '0.1.0') if ('-cp3' in w) and ('-cp37' not in w)
|
||||
w for w in utils.expected_wheels("spam", "0.1.0") if ("-cp3" in w) and ("-cp37" not in w)
|
||||
]
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
+46
-46
@@ -8,7 +8,7 @@ from .test_projects import TestProject
|
||||
|
||||
cpp_test_project = TestProject()
|
||||
|
||||
setup_py_template = r'''
|
||||
setup_py_template = r"""
|
||||
from setuptools import Extension, setup
|
||||
|
||||
setup(
|
||||
@@ -16,9 +16,9 @@ setup(
|
||||
ext_modules=[Extension('spam', sources=['spam.cpp'], language="c++", extra_compile_args={{ extra_compile_args }})],
|
||||
version="0.1.0",
|
||||
)
|
||||
'''
|
||||
"""
|
||||
|
||||
spam_cpp_template = r'''
|
||||
spam_cpp_template = r"""
|
||||
#include <Python.h>
|
||||
|
||||
{{ spam_cpp_top_level_add }}
|
||||
@@ -69,59 +69,59 @@ MOD_INIT(spam)
|
||||
|
||||
MOD_RETURN(m)
|
||||
}
|
||||
'''
|
||||
"""
|
||||
|
||||
cpp_test_project.files['setup.py'] = jinja2.Template(setup_py_template)
|
||||
cpp_test_project.files['spam.cpp'] = jinja2.Template(spam_cpp_template)
|
||||
cpp_test_project.files["setup.py"] = jinja2.Template(setup_py_template)
|
||||
cpp_test_project.files["spam.cpp"] = jinja2.Template(spam_cpp_template)
|
||||
|
||||
cpp11_project = cpp_test_project.copy()
|
||||
cpp11_project.template_context['extra_compile_args'] = (
|
||||
['/std:c++11'] if utils.platform == 'windows' else ['-std=c++11']
|
||||
cpp11_project.template_context["extra_compile_args"] = (
|
||||
["/std:c++11"] if utils.platform == "windows" else ["-std=c++11"]
|
||||
)
|
||||
cpp11_project.template_context['spam_cpp_top_level_add'] = '#include <array>'
|
||||
cpp11_project.template_context["spam_cpp_top_level_add"] = "#include <array>"
|
||||
|
||||
|
||||
def test_cpp11(tmp_path):
|
||||
# This test checks that the C++11 standard is supported
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
|
||||
cpp11_project.generate(project_dir)
|
||||
|
||||
# VC++ for Python 2.7 does not support modern standards
|
||||
add_env = {'CIBW_SKIP': 'cp27-win* pp27-win32'}
|
||||
add_env = {"CIBW_SKIP": "cp27-win* pp27-win32"}
|
||||
|
||||
actual_wheels = utils.cibuildwheel_run(project_dir, add_env=add_env)
|
||||
expected_wheels = [
|
||||
w
|
||||
for w in utils.expected_wheels('spam', '0.1.0')
|
||||
if 'cp27-cp27m-win' not in w and 'pp27-pypy_73-win32' not in w
|
||||
for w in utils.expected_wheels("spam", "0.1.0")
|
||||
if "cp27-cp27m-win" not in w and "pp27-pypy_73-win32" not in w
|
||||
]
|
||||
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
|
||||
cpp14_project = cpp_test_project.copy()
|
||||
cpp14_project.template_context['extra_compile_args'] = (
|
||||
['/std:c++14'] if utils.platform == 'windows' else ['-std=c++14']
|
||||
cpp14_project.template_context["extra_compile_args"] = (
|
||||
["/std:c++14"] if utils.platform == "windows" else ["-std=c++14"]
|
||||
)
|
||||
cpp14_project.template_context['spam_cpp_top_level_add'] = "int a = 100'000;"
|
||||
cpp14_project.template_context["spam_cpp_top_level_add"] = "int a = 100'000;"
|
||||
|
||||
|
||||
def test_cpp14(tmp_path):
|
||||
# This test checks that the C++14 standard is supported
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
|
||||
cpp14_project.generate(project_dir)
|
||||
|
||||
# VC++ for Python 2.7 does not support modern standards
|
||||
# The manylinux1 docker image does not have a compiler which supports C++11
|
||||
add_env = {'CIBW_SKIP': 'cp27-win* pp27-win32'}
|
||||
add_env = {"CIBW_SKIP": "cp27-win* pp27-win32"}
|
||||
|
||||
actual_wheels = utils.cibuildwheel_run(project_dir, add_env=add_env)
|
||||
expected_wheels = [
|
||||
w
|
||||
for w in utils.expected_wheels('spam', '0.1.0')
|
||||
if 'cp27-cp27m-win' not in w and 'pp27-pypy_73-win32' not in w
|
||||
for w in utils.expected_wheels("spam", "0.1.0")
|
||||
if "cp27-cp27m-win" not in w and "pp27-pypy_73-win32" not in w
|
||||
]
|
||||
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
@@ -131,38 +131,38 @@ cpp17_project = cpp_test_project.copy()
|
||||
|
||||
# Python and PyPy 2.7 headers use the `register` keyword, which is forbidden in
|
||||
# the C++17 standard, so we need the -Wno-register or /wd5033 options
|
||||
cpp17_project.template_context['extra_compile_args'] = (
|
||||
['/std:c++17', '/wd5033'] if utils.platform == 'windows' else ['-std=c++17', '-Wno-register']
|
||||
cpp17_project.template_context["extra_compile_args"] = (
|
||||
["/std:c++17", "/wd5033"] if utils.platform == "windows" else ["-std=c++17", "-Wno-register"]
|
||||
)
|
||||
cpp17_project.template_context[
|
||||
'spam_cpp_top_level_add'
|
||||
] = r'''
|
||||
"spam_cpp_top_level_add"
|
||||
] = r"""
|
||||
#include <utility>
|
||||
auto a = std::pair(5.0, false);
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
def test_cpp17(tmp_path):
|
||||
# This test checks that the C++17 standard is supported
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
|
||||
cpp17_project.generate(project_dir)
|
||||
|
||||
if os.environ.get('APPVEYOR_BUILD_WORKER_IMAGE', '') == 'Visual Studio 2015':
|
||||
pytest.skip('Visual Studio 2015 does not support C++17')
|
||||
if os.environ.get("APPVEYOR_BUILD_WORKER_IMAGE", "") == "Visual Studio 2015":
|
||||
pytest.skip("Visual Studio 2015 does not support C++17")
|
||||
|
||||
# Pypy's distutils sets the default compiler to 'msvc9compiler', which
|
||||
# is too old to support cpp17.
|
||||
add_env = {'CIBW_SKIP': 'cp27-win* pp??-*'}
|
||||
add_env = {"CIBW_SKIP": "cp27-win* pp??-*"}
|
||||
|
||||
if utils.platform == 'macos':
|
||||
add_env['MACOSX_DEPLOYMENT_TARGET'] = '10.13'
|
||||
if utils.platform == "macos":
|
||||
add_env["MACOSX_DEPLOYMENT_TARGET"] = "10.13"
|
||||
|
||||
actual_wheels = utils.cibuildwheel_run(project_dir, add_env=add_env)
|
||||
expected_wheels = [
|
||||
w
|
||||
for w in utils.expected_wheels('spam', '0.1.0', macosx_deployment_target='10.13')
|
||||
if 'cp27-cp27m-win' not in w and '-pp' not in w
|
||||
for w in utils.expected_wheels("spam", "0.1.0", macosx_deployment_target="10.13")
|
||||
if "cp27-cp27m-win" not in w and "-pp" not in w
|
||||
]
|
||||
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
@@ -171,13 +171,13 @@ def test_cpp17(tmp_path):
|
||||
def test_cpp17_py27_modern_msvc_workaround(tmp_path):
|
||||
# This test checks the workaround for building Python 2.7 wheel with MSVC 14
|
||||
|
||||
if utils.platform != 'windows':
|
||||
pytest.skip('the test is only relevant to the Windows build')
|
||||
if utils.platform != "windows":
|
||||
pytest.skip("the test is only relevant to the Windows build")
|
||||
|
||||
if os.environ.get('APPVEYOR_BUILD_WORKER_IMAGE', '') == 'Visual Studio 2015':
|
||||
pytest.skip('Visual Studio 2015 does not support C++17')
|
||||
if os.environ.get("APPVEYOR_BUILD_WORKER_IMAGE", "") == "Visual Studio 2015":
|
||||
pytest.skip("Visual Studio 2015 does not support C++17")
|
||||
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
cpp17_project.generate(project_dir)
|
||||
|
||||
# VC++ for Python 2.7 (i.e., MSVC 9) does not support modern standards
|
||||
@@ -186,7 +186,7 @@ def test_cpp17_py27_modern_msvc_workaround(tmp_path):
|
||||
# included with Python: see documentation for more info
|
||||
# DISTUTILS_USE_SDK and MSSdk=1 tell distutils/setuptools that we are adding
|
||||
# MSVC's compiler, tools, and libraries to PATH ourselves
|
||||
add_env = {'DISTUTILS_USE_SDK': '1', 'MSSdk': '1'}
|
||||
add_env = {"DISTUTILS_USE_SDK": "1", "MSSdk": "1"}
|
||||
|
||||
# Use existing setuptools code to run Visual Studio's vcvarsall.bat and get the
|
||||
# necessary environment variables, since running vcvarsall.bat in a subprocess
|
||||
@@ -201,22 +201,22 @@ def test_cpp17_py27_modern_msvc_workaround(tmp_path):
|
||||
def add_vcvars(prev_env, platform):
|
||||
vcvarsall_env = setuptools.msvc.msvc14_get_vc_env(platform)
|
||||
env = prev_env.copy()
|
||||
for vcvar in ['path', 'include', 'lib']:
|
||||
for vcvar in ["path", "include", "lib"]:
|
||||
env[vcvar] = vcvarsall_env[vcvar]
|
||||
return env
|
||||
|
||||
add_env_x86 = add_vcvars(add_env, 'x86')
|
||||
add_env_x86['CIBW_BUILD'] = '?p27-win32'
|
||||
add_env_x86 = add_vcvars(add_env, "x86")
|
||||
add_env_x86["CIBW_BUILD"] = "?p27-win32"
|
||||
actual_wheels = utils.cibuildwheel_run(project_dir, add_env=add_env_x86)
|
||||
|
||||
add_env_x64 = add_vcvars(add_env, 'x64')
|
||||
add_env_x64['CIBW_BUILD'] = 'cp27-win_amd64'
|
||||
add_env_x64 = add_vcvars(add_env, "x64")
|
||||
add_env_x64["CIBW_BUILD"] = "cp27-win_amd64"
|
||||
actual_wheels += utils.cibuildwheel_run(project_dir, add_env=add_env_x64)
|
||||
|
||||
expected_wheels = [
|
||||
w
|
||||
for w in utils.expected_wheels('spam', '0.1.0', exclude_27=False)
|
||||
if 'cp27-cp27m-win' in w or 'pp27-pypy_73-win32' in w
|
||||
for w in utils.expected_wheels("spam", "0.1.0", exclude_27=False)
|
||||
if "cp27-cp27m-win" in w or "pp27-pypy_73-win32" in w
|
||||
]
|
||||
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
@@ -9,7 +9,7 @@ from . import test_projects, utils
|
||||
|
||||
project_with_expected_version_checks = test_projects.new_c_project(
|
||||
setup_py_add=textwrap.dedent(
|
||||
r'''
|
||||
r"""
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
@@ -31,124 +31,124 @@ project_with_expected_version_checks = test_projects.new_c_project(
|
||||
assert '{}=={}'.format(package_name, expected_version) in versions, (
|
||||
'error: {} version should equal {}'.format(package_name, expected_version)
|
||||
)
|
||||
'''
|
||||
"""
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
VERSION_REGEX = r'([\w-]+)==([^\s]+)'
|
||||
VERSION_REGEX = r"([\w-]+)==([^\s]+)"
|
||||
|
||||
|
||||
def get_versions_from_constraint_file(constraint_file):
|
||||
constraint_file_text = constraint_file.read_text(encoding='utf8')
|
||||
constraint_file_text = constraint_file.read_text(encoding="utf8")
|
||||
|
||||
return {
|
||||
package: version for package, version in re.findall(VERSION_REGEX, constraint_file_text)
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize('python_version', ['2.7', '3.5', '3.6', '3.8'])
|
||||
@pytest.mark.parametrize("python_version", ["2.7", "3.5", "3.6", "3.8"])
|
||||
def test_pinned_versions(tmp_path, python_version):
|
||||
if utils.platform == 'linux':
|
||||
pytest.skip('linux doesn\'t pin individual tool versions, it pins manylinux images instead')
|
||||
if utils.platform == "linux":
|
||||
pytest.skip("linux doesn't pin individual tool versions, it pins manylinux images instead")
|
||||
|
||||
if utils.platform == 'windows' and python_version == '2.7':
|
||||
pytest.skip('Windows requires a workaround')
|
||||
if utils.platform == "windows" and python_version == "2.7":
|
||||
pytest.skip("Windows requires a workaround")
|
||||
|
||||
is_macos_11_or_later = utils.platform == 'macos' and utils.get_macos_version() >= (10, 16)
|
||||
is_macos_11_or_later = utils.platform == "macos" and utils.get_macos_version() >= (10, 16)
|
||||
|
||||
if is_macos_11_or_later and python_version == '3.5':
|
||||
pytest.skip('CPython 3.5 doesn\'t work on macOS Big Sur+')
|
||||
if is_macos_11_or_later and python_version == "3.5":
|
||||
pytest.skip("CPython 3.5 doesn't work on macOS Big Sur+")
|
||||
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
project_with_expected_version_checks.generate(project_dir)
|
||||
|
||||
build_environment = {}
|
||||
|
||||
if python_version == '2.7':
|
||||
constraint_filename = 'constraints-python27.txt'
|
||||
build_pattern = '[cp]p27-*'
|
||||
elif python_version == '3.5':
|
||||
constraint_filename = 'constraints-python35.txt'
|
||||
build_pattern = '[cp]p35-*'
|
||||
elif python_version == '3.6':
|
||||
constraint_filename = 'constraints-python36.txt'
|
||||
build_pattern = '[cp]p36-*'
|
||||
elif python_version == '3.7':
|
||||
constraint_filename = 'constraints-python37.txt'
|
||||
build_pattern = '[cp]p37-*'
|
||||
if python_version == "2.7":
|
||||
constraint_filename = "constraints-python27.txt"
|
||||
build_pattern = "[cp]p27-*"
|
||||
elif python_version == "3.5":
|
||||
constraint_filename = "constraints-python35.txt"
|
||||
build_pattern = "[cp]p35-*"
|
||||
elif python_version == "3.6":
|
||||
constraint_filename = "constraints-python36.txt"
|
||||
build_pattern = "[cp]p36-*"
|
||||
elif python_version == "3.7":
|
||||
constraint_filename = "constraints-python37.txt"
|
||||
build_pattern = "[cp]p37-*"
|
||||
else:
|
||||
constraint_filename = 'constraints.txt'
|
||||
build_pattern = '[cp]p38-*'
|
||||
constraint_filename = "constraints.txt"
|
||||
build_pattern = "[cp]p38-*"
|
||||
|
||||
constraint_file = cibuildwheel.util.resources_dir / constraint_filename
|
||||
constraint_versions = get_versions_from_constraint_file(constraint_file)
|
||||
|
||||
for package in ['pip', 'setuptools', 'wheel', 'virtualenv']:
|
||||
env_name = f'EXPECTED_{package.upper()}_VERSION'
|
||||
for package in ["pip", "setuptools", "wheel", "virtualenv"]:
|
||||
env_name = f"EXPECTED_{package.upper()}_VERSION"
|
||||
build_environment[env_name] = constraint_versions[package]
|
||||
|
||||
cibw_environment_option = ' '.join(f'{k}={v}' for k, v in build_environment.items())
|
||||
cibw_environment_option = " ".join(f"{k}={v}" for k, v in build_environment.items())
|
||||
|
||||
# build and test the wheels
|
||||
actual_wheels = utils.cibuildwheel_run(
|
||||
project_dir,
|
||||
add_env={
|
||||
'CIBW_BUILD': build_pattern,
|
||||
'CIBW_ENVIRONMENT': cibw_environment_option,
|
||||
"CIBW_BUILD": build_pattern,
|
||||
"CIBW_ENVIRONMENT": cibw_environment_option,
|
||||
},
|
||||
)
|
||||
|
||||
# also check that we got the right wheels
|
||||
if python_version == '2.7':
|
||||
if python_version == "2.7":
|
||||
expected_wheels = [
|
||||
w for w in utils.expected_wheels('spam', '0.1.0') if '-cp27' in w or '-pp27' in w
|
||||
w for w in utils.expected_wheels("spam", "0.1.0") if "-cp27" in w or "-pp27" in w
|
||||
]
|
||||
elif python_version == '3.5':
|
||||
elif python_version == "3.5":
|
||||
expected_wheels = [
|
||||
w for w in utils.expected_wheels('spam', '0.1.0') if '-cp35' in w or '-pp35' in w
|
||||
w for w in utils.expected_wheels("spam", "0.1.0") if "-cp35" in w or "-pp35" in w
|
||||
]
|
||||
elif python_version == '3.6':
|
||||
elif python_version == "3.6":
|
||||
expected_wheels = [
|
||||
w for w in utils.expected_wheels('spam', '0.1.0') if '-cp36' in w or '-pp36' in w
|
||||
w for w in utils.expected_wheels("spam", "0.1.0") if "-cp36" in w or "-pp36" in w
|
||||
]
|
||||
elif python_version == '3.8':
|
||||
elif python_version == "3.8":
|
||||
expected_wheels = [
|
||||
w for w in utils.expected_wheels('spam', '0.1.0') if '-cp38' in w or '-pp38' in w
|
||||
w for w in utils.expected_wheels("spam", "0.1.0") if "-cp38" in w or "-pp38" in w
|
||||
]
|
||||
else:
|
||||
raise ValueError('unhandled python version')
|
||||
raise ValueError("unhandled python version")
|
||||
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('python_version', ['2.7', '3.x'])
|
||||
@pytest.mark.parametrize("python_version", ["2.7", "3.x"])
|
||||
def test_dependency_constraints_file(tmp_path, python_version):
|
||||
if utils.platform == 'linux':
|
||||
pytest.skip('linux doesn\'t pin individual tool versions, it pins manylinux images instead')
|
||||
if utils.platform == "linux":
|
||||
pytest.skip("linux doesn't pin individual tool versions, it pins manylinux images instead")
|
||||
|
||||
if utils.platform == 'windows' and python_version == '2.7':
|
||||
pytest.skip('Windows + Travis CI requires a workaround')
|
||||
if utils.platform == "windows" and python_version == "2.7":
|
||||
pytest.skip("Windows + Travis CI requires a workaround")
|
||||
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
project_with_expected_version_checks.generate(project_dir)
|
||||
|
||||
tool_versions = {
|
||||
'pip': '20.0.2',
|
||||
'setuptools': '44.0.0' if python_version == '2.7' else '46.0.0',
|
||||
'wheel': '0.34.2',
|
||||
'virtualenv': '20.0.10',
|
||||
"pip": "20.0.2",
|
||||
"setuptools": "44.0.0" if python_version == "2.7" else "46.0.0",
|
||||
"wheel": "0.34.2",
|
||||
"virtualenv": "20.0.10",
|
||||
}
|
||||
|
||||
constraints_file = tmp_path / 'constraints.txt'
|
||||
constraints_file = tmp_path / "constraints.txt"
|
||||
constraints_file.write_text(
|
||||
textwrap.dedent(
|
||||
'''
|
||||
"""
|
||||
pip=={pip}
|
||||
setuptools=={setuptools}
|
||||
wheel=={wheel}
|
||||
virtualenv=={virtualenv}
|
||||
'''.format(
|
||||
""".format(
|
||||
**tool_versions
|
||||
)
|
||||
)
|
||||
@@ -157,31 +157,31 @@ def test_dependency_constraints_file(tmp_path, python_version):
|
||||
build_environment = {}
|
||||
|
||||
for package_name, version in tool_versions.items():
|
||||
env_name = f'EXPECTED_{package_name.upper()}_VERSION'
|
||||
env_name = f"EXPECTED_{package_name.upper()}_VERSION"
|
||||
build_environment[env_name] = version
|
||||
|
||||
cibw_environment_option = ' '.join(f'{k}={v}' for k, v in build_environment.items())
|
||||
cibw_environment_option = " ".join(f"{k}={v}" for k, v in build_environment.items())
|
||||
|
||||
# build and test the wheels
|
||||
actual_wheels = utils.cibuildwheel_run(
|
||||
project_dir,
|
||||
add_env={
|
||||
'CIBW_BUILD': '[cp]p27-*' if python_version == '2.7' else '[cp]p3?-*',
|
||||
'CIBW_ENVIRONMENT': cibw_environment_option,
|
||||
'CIBW_DEPENDENCY_VERSIONS': str(constraints_file),
|
||||
"CIBW_BUILD": "[cp]p27-*" if python_version == "2.7" else "[cp]p3?-*",
|
||||
"CIBW_ENVIRONMENT": cibw_environment_option,
|
||||
"CIBW_DEPENDENCY_VERSIONS": str(constraints_file),
|
||||
},
|
||||
)
|
||||
|
||||
# also check that we got the right wheels
|
||||
if python_version == '2.7':
|
||||
if python_version == "2.7":
|
||||
expected_wheels = [
|
||||
w for w in utils.expected_wheels('spam', '0.1.0') if '-cp27' in w or '-pp27' in w
|
||||
w for w in utils.expected_wheels("spam", "0.1.0") if "-cp27" in w or "-pp27" in w
|
||||
]
|
||||
else:
|
||||
expected_wheels = [
|
||||
w
|
||||
for w in utils.expected_wheels('spam', '0.1.0')
|
||||
if '-cp27' not in w and '-pp27' not in w
|
||||
for w in utils.expected_wheels("spam", "0.1.0")
|
||||
if "-cp27" not in w and "-pp27" not in w
|
||||
]
|
||||
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
+12
-12
@@ -7,7 +7,7 @@ from . import test_projects, utils
|
||||
|
||||
dockcross_only_project = test_projects.new_c_project(
|
||||
setup_py_add=textwrap.dedent(
|
||||
r'''
|
||||
r"""
|
||||
import os
|
||||
|
||||
# check that we're running in the correct docker image as specified in the
|
||||
@@ -16,35 +16,35 @@ dockcross_only_project = test_projects.new_c_project(
|
||||
raise Exception(
|
||||
"/dockcross directory not found. Is this test running in the correct docker image?"
|
||||
)
|
||||
'''
|
||||
"""
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def test(tmp_path):
|
||||
if utils.platform != 'linux':
|
||||
pytest.skip('the test is only relevant to the linux build')
|
||||
if platform.machine() not in ['x86_64', 'i686']:
|
||||
if utils.platform != "linux":
|
||||
pytest.skip("the test is only relevant to the linux build")
|
||||
if platform.machine() not in ["x86_64", "i686"]:
|
||||
pytest.skip(
|
||||
'this test is currently only possible on x86_64/i686 due to availability of alternative images'
|
||||
"this test is currently only possible on x86_64/i686 due to availability of alternative images"
|
||||
)
|
||||
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
dockcross_only_project.generate(project_dir)
|
||||
|
||||
actual_wheels = utils.cibuildwheel_run(
|
||||
project_dir,
|
||||
add_env={
|
||||
'CIBW_MANYLINUX_X86_64_IMAGE': 'dockcross/manylinux2010-x64',
|
||||
'CIBW_MANYLINUX_I686_IMAGE': 'dockcross/manylinux2010-x86',
|
||||
'CIBW_SKIP': 'pp* cp27-* cp39-*',
|
||||
"CIBW_MANYLINUX_X86_64_IMAGE": "dockcross/manylinux2010-x64",
|
||||
"CIBW_MANYLINUX_I686_IMAGE": "dockcross/manylinux2010-x86",
|
||||
"CIBW_SKIP": "pp* cp27-* cp39-*",
|
||||
},
|
||||
)
|
||||
|
||||
# also check that we got the right wheels built
|
||||
expected_wheels = [
|
||||
w
|
||||
for w in utils.expected_wheels('spam', '0.1.0')
|
||||
if '-pp' not in w and '-cp39-' not in w and '-cp27-' not in w
|
||||
for w in utils.expected_wheels("spam", "0.1.0")
|
||||
if "-pp" not in w and "-cp39-" not in w and "-cp27-" not in w
|
||||
]
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
+14
-14
@@ -7,45 +7,45 @@ from . import test_projects, utils
|
||||
project_with_a_test = test_projects.new_c_project()
|
||||
|
||||
project_with_a_test.files[
|
||||
'test/spam_test.py'
|
||||
] = r'''
|
||||
"test/spam_test.py"
|
||||
] = r"""
|
||||
import spam
|
||||
|
||||
def test_spam():
|
||||
assert spam.system('python -c "exit(0)"') == 0
|
||||
assert spam.system('python -c "exit(1)"') != 0
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
@pytest.mark.emulation
|
||||
def test(tmp_path):
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
project_with_a_test.generate(project_dir)
|
||||
|
||||
# build and test the wheels
|
||||
actual_wheels = utils.cibuildwheel_run(
|
||||
project_dir,
|
||||
add_env={
|
||||
'CIBW_TEST_REQUIRES': 'pytest',
|
||||
'CIBW_TEST_COMMAND': 'pytest {project}/test',
|
||||
'CIBW_ARCHS': 'aarch64 ppc64le s390x',
|
||||
"CIBW_TEST_REQUIRES": "pytest",
|
||||
"CIBW_TEST_COMMAND": "pytest {project}/test",
|
||||
"CIBW_ARCHS": "aarch64 ppc64le s390x",
|
||||
},
|
||||
)
|
||||
|
||||
# also check that we got the right wheels
|
||||
expected_wheels = (
|
||||
utils.expected_wheels('spam', '0.1.0', machine_arch='aarch64')
|
||||
+ utils.expected_wheels('spam', '0.1.0', machine_arch='ppc64le')
|
||||
+ utils.expected_wheels('spam', '0.1.0', machine_arch='s390x')
|
||||
utils.expected_wheels("spam", "0.1.0", machine_arch="aarch64")
|
||||
+ utils.expected_wheels("spam", "0.1.0", machine_arch="ppc64le")
|
||||
+ utils.expected_wheels("spam", "0.1.0", machine_arch="s390x")
|
||||
)
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
|
||||
def test_setting_arch_on_other_platforms(tmp_path, capfd):
|
||||
if utils.platform == 'linux':
|
||||
pytest.skip('this test checks the behaviour on platforms other than linux')
|
||||
if utils.platform == "linux":
|
||||
pytest.skip("this test checks the behaviour on platforms other than linux")
|
||||
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
project_with_a_test.generate(project_dir)
|
||||
|
||||
# build and test the wheels
|
||||
@@ -53,7 +53,7 @@ def test_setting_arch_on_other_platforms(tmp_path, capfd):
|
||||
utils.cibuildwheel_run(
|
||||
project_dir,
|
||||
add_env={
|
||||
'CIBW_ARCHS': 'aarch64',
|
||||
"CIBW_ARCHS": "aarch64",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
+15
-15
@@ -8,7 +8,7 @@ from . import test_projects, utils
|
||||
|
||||
project_with_environment_asserts = test_projects.new_c_project(
|
||||
setup_py_add=textwrap.dedent(
|
||||
r'''
|
||||
r"""
|
||||
import os
|
||||
|
||||
# explode if environment isn't correct, as set in CIBW_ENVIRONMENT
|
||||
@@ -27,13 +27,13 @@ project_with_environment_asserts = test_projects.new_c_project(
|
||||
raise Exception('PATH should contain "/opt/cibw_test_path". It was "%s"' % PATH)
|
||||
if "$PATH" in PATH:
|
||||
raise Exception('$PATH should be expanded in PATH. It was "%s"' % PATH)
|
||||
'''
|
||||
"""
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def test(tmp_path):
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
project_with_environment_asserts.generate(project_dir)
|
||||
|
||||
# write some information into the CIBW_ENVIRONMENT, for expansion and
|
||||
@@ -42,19 +42,19 @@ def test(tmp_path):
|
||||
actual_wheels = utils.cibuildwheel_run(
|
||||
project_dir,
|
||||
add_env={
|
||||
'CIBW_ENVIRONMENT': '''CIBW_TEST_VAR="a b c" CIBW_TEST_VAR_2=1 CIBW_TEST_VAR_3="$(echo 'test string 3')" PATH=$PATH:/opt/cibw_test_path''',
|
||||
'CIBW_ENVIRONMENT_WINDOWS': '''CIBW_TEST_VAR="a b c" CIBW_TEST_VAR_2=1 CIBW_TEST_VAR_3="$(echo 'test string 3')" PATH="$PATH;/opt/cibw_test_path"''',
|
||||
"CIBW_ENVIRONMENT": """CIBW_TEST_VAR="a b c" CIBW_TEST_VAR_2=1 CIBW_TEST_VAR_3="$(echo 'test string 3')" PATH=$PATH:/opt/cibw_test_path""",
|
||||
"CIBW_ENVIRONMENT_WINDOWS": '''CIBW_TEST_VAR="a b c" CIBW_TEST_VAR_2=1 CIBW_TEST_VAR_3="$(echo 'test string 3')" PATH="$PATH;/opt/cibw_test_path"''',
|
||||
},
|
||||
)
|
||||
|
||||
# also check that we got the right wheels built
|
||||
expected_wheels = utils.expected_wheels('spam', '0.1.0')
|
||||
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
|
||||
def test_overridden_path(tmp_path, capfd):
|
||||
project_dir = tmp_path / 'project'
|
||||
output_dir = tmp_path / 'output'
|
||||
project_dir = tmp_path / "project"
|
||||
output_dir = tmp_path / "output"
|
||||
|
||||
project = test_projects.new_c_project()
|
||||
project.generate(project_dir)
|
||||
@@ -62,26 +62,26 @@ def test_overridden_path(tmp_path, capfd):
|
||||
|
||||
# mess up PATH, somehow
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
if utils.platform == 'linux':
|
||||
if utils.platform == "linux":
|
||||
utils.cibuildwheel_run(
|
||||
project_dir,
|
||||
output_dir=output_dir,
|
||||
add_env={
|
||||
'CIBW_BEFORE_ALL': 'mkdir new_path && touch new_path/python && chmod +x new_path/python',
|
||||
'CIBW_ENVIRONMENT': '''PATH="$(pwd)/new_path:$PATH"''',
|
||||
"CIBW_BEFORE_ALL": "mkdir new_path && touch new_path/python && chmod +x new_path/python",
|
||||
"CIBW_ENVIRONMENT": '''PATH="$(pwd)/new_path:$PATH"''',
|
||||
},
|
||||
)
|
||||
else:
|
||||
new_path = tmp_path / 'another_bin'
|
||||
new_path = tmp_path / "another_bin"
|
||||
new_path.mkdir()
|
||||
(new_path / 'python').touch(mode=0o777)
|
||||
(new_path / "python").touch(mode=0o777)
|
||||
|
||||
utils.cibuildwheel_run(
|
||||
project_dir,
|
||||
output_dir=output_dir,
|
||||
add_env={
|
||||
'NEW_PATH': str(new_path),
|
||||
'CIBW_ENVIRONMENT': f'''PATH="$NEW_PATH{os.pathsep}$PATH"''',
|
||||
"NEW_PATH": str(new_path),
|
||||
"CIBW_ENVIRONMENT": f'''PATH="$NEW_PATH{os.pathsep}$PATH"''',
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
+45
-45
@@ -9,14 +9,14 @@ from . import test_projects, utils
|
||||
basic_project = test_projects.new_c_project()
|
||||
|
||||
ALL_MACOS_WHEELS = {
|
||||
*utils.expected_wheels('spam', '0.1.0', machine_arch='x86_64'),
|
||||
*utils.expected_wheels('spam', '0.1.0', machine_arch='arm64'),
|
||||
*utils.expected_wheels("spam", "0.1.0", machine_arch="x86_64"),
|
||||
*utils.expected_wheels("spam", "0.1.0", machine_arch="arm64"),
|
||||
}
|
||||
|
||||
|
||||
def get_xcode_version() -> Tuple[int, int]:
|
||||
output = subprocess.run(
|
||||
['xcodebuild', '-version'],
|
||||
["xcodebuild", "-version"],
|
||||
universal_newlines=True,
|
||||
check=True,
|
||||
stdout=subprocess.PIPE,
|
||||
@@ -24,112 +24,112 @@ def get_xcode_version() -> Tuple[int, int]:
|
||||
lines = output.splitlines()
|
||||
_, version_str = lines[0].split()
|
||||
|
||||
version_parts = version_str.split('.')
|
||||
version_parts = version_str.split(".")
|
||||
return (int(version_parts[0]), int(version_parts[1]))
|
||||
|
||||
|
||||
def test_cross_compiled_build(tmp_path):
|
||||
if utils.platform != 'macos':
|
||||
pytest.skip('this test is only relevant to macos')
|
||||
if utils.platform != "macos":
|
||||
pytest.skip("this test is only relevant to macos")
|
||||
if get_xcode_version() < (12, 2):
|
||||
pytest.skip('this test only works with Xcode 12.2 or greater')
|
||||
pytest.skip("this test only works with Xcode 12.2 or greater")
|
||||
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
basic_project.generate(project_dir)
|
||||
|
||||
actual_wheels = utils.cibuildwheel_run(
|
||||
project_dir,
|
||||
add_env={
|
||||
'CIBW_BUILD': 'cp39-*',
|
||||
'CIBW_ARCHS': 'x86_64, universal2, arm64',
|
||||
"CIBW_BUILD": "cp39-*",
|
||||
"CIBW_ARCHS": "x86_64, universal2, arm64",
|
||||
},
|
||||
)
|
||||
|
||||
expected_wheels = [w for w in ALL_MACOS_WHEELS if 'cp39' in w]
|
||||
expected_wheels = [w for w in ALL_MACOS_WHEELS if "cp39" in w]
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('build_universal2', [False, True])
|
||||
@pytest.mark.parametrize("build_universal2", [False, True])
|
||||
def test_cross_compiled_test(tmp_path, capfd, build_universal2):
|
||||
if utils.platform != 'macos':
|
||||
pytest.skip('this test is only relevant to macos')
|
||||
if utils.platform != "macos":
|
||||
pytest.skip("this test is only relevant to macos")
|
||||
if get_xcode_version() < (12, 2):
|
||||
pytest.skip('this test only works with Xcode 12.2 or greater')
|
||||
pytest.skip("this test only works with Xcode 12.2 or greater")
|
||||
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
basic_project.generate(project_dir)
|
||||
|
||||
actual_wheels = utils.cibuildwheel_run(
|
||||
project_dir,
|
||||
add_env={
|
||||
'CIBW_BUILD': 'cp39-*',
|
||||
'CIBW_TEST_COMMAND': '''python -c "import platform; print('running tests on ' + platform.machine())"''',
|
||||
'CIBW_ARCHS': 'universal2' if build_universal2 else 'x86_64 arm64',
|
||||
"CIBW_BUILD": "cp39-*",
|
||||
"CIBW_TEST_COMMAND": '''python -c "import platform; print('running tests on ' + platform.machine())"''',
|
||||
"CIBW_ARCHS": "universal2" if build_universal2 else "x86_64 arm64",
|
||||
},
|
||||
)
|
||||
|
||||
captured = capfd.readouterr()
|
||||
|
||||
if platform.machine() == 'x86_64':
|
||||
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
|
||||
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 them cannot currently be tested'
|
||||
"While universal2 wheels can be built on x86_64, the arm64 part of them cannot currently be tested"
|
||||
in captured.err
|
||||
)
|
||||
else:
|
||||
assert (
|
||||
'While arm64 wheels can be built on x86_64, they cannot be tested' in captured.err
|
||||
"While arm64 wheels can be built on x86_64, they cannot be tested" in captured.err
|
||||
)
|
||||
elif platform.machine() == 'arm64':
|
||||
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 "running tests on x86_64" in captured.out
|
||||
assert "running tests on arm64" in captured.out
|
||||
|
||||
if build_universal2:
|
||||
expected_wheels = [w for w in ALL_MACOS_WHEELS if 'cp39' in w and 'universal2' in w]
|
||||
expected_wheels = [w for w in ALL_MACOS_WHEELS if "cp39" in w and "universal2" in w]
|
||||
else:
|
||||
expected_wheels = [w for w in ALL_MACOS_WHEELS if 'cp39' in w and 'universal2' not in w]
|
||||
expected_wheels = [w for w in ALL_MACOS_WHEELS if "cp39" in w and "universal2" not in w]
|
||||
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('skip_arm64_test', [False, True])
|
||||
@pytest.mark.parametrize("skip_arm64_test", [False, True])
|
||||
def test_universal2_testing(tmp_path, capfd, skip_arm64_test):
|
||||
if utils.platform != 'macos':
|
||||
pytest.skip('this test is only relevant to macos')
|
||||
if utils.platform != "macos":
|
||||
pytest.skip("this test is only relevant to macos")
|
||||
if 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')
|
||||
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'
|
||||
project_dir = tmp_path / "project"
|
||||
basic_project.generate(project_dir)
|
||||
|
||||
actual_wheels = utils.cibuildwheel_run(
|
||||
project_dir,
|
||||
add_env={
|
||||
'CIBW_BUILD': 'cp39-*',
|
||||
'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 '',
|
||||
"CIBW_BUILD": "cp39-*",
|
||||
"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 "",
|
||||
},
|
||||
)
|
||||
|
||||
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
|
||||
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 them cannot currently be tested'
|
||||
warning_message = "While universal2 wheels can be built on x86_64, the arm64 part of them cannot currently be tested"
|
||||
if skip_arm64_test:
|
||||
assert warning_message not in captured.err
|
||||
else:
|
||||
assert warning_message in captured.err
|
||||
|
||||
expected_wheels = [w for w in ALL_MACOS_WHEELS if 'cp39' in w and 'universal2' in w]
|
||||
expected_wheels = [w for w in ALL_MACOS_WHEELS if "cp39" in w and "universal2" in w]
|
||||
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
@@ -8,7 +8,7 @@ from . import test_projects, utils
|
||||
# TODO: specify these at runtime according to manylinux_image
|
||||
project_with_manylinux_symbols = test_projects.new_c_project(
|
||||
spam_c_top_level_add=textwrap.dedent(
|
||||
r'''
|
||||
r"""
|
||||
#include <malloc.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
@@ -21,10 +21,10 @@ project_with_manylinux_symbols = test_projects.new_c_project(
|
||||
#if !__GLIBC_PREREQ(2, 5) /* manylinux1 is glibc 2.5 */
|
||||
#error "Must run on a glibc >= 2.5 linux environment"
|
||||
#endif
|
||||
'''
|
||||
"""
|
||||
),
|
||||
spam_c_function_add=textwrap.dedent(
|
||||
r'''
|
||||
r"""
|
||||
#if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 24)
|
||||
// nextupf is only available in manylinux_2_24+
|
||||
sts = (int)nextupf(0.0F);
|
||||
@@ -35,50 +35,50 @@ project_with_manylinux_symbols = test_projects.new_c_project(
|
||||
// malloc_info is only available on manylinux2010+
|
||||
sts = malloc_info(0, stdout);
|
||||
#endif
|
||||
'''
|
||||
"""
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'manylinux_image', ['manylinux1', 'manylinux2010', 'manylinux2014', 'manylinux_2_24']
|
||||
"manylinux_image", ["manylinux1", "manylinux2010", "manylinux2014", "manylinux_2_24"]
|
||||
)
|
||||
def test(manylinux_image, tmp_path):
|
||||
if utils.platform != 'linux':
|
||||
pytest.skip('the docker test is only relevant to the linux build')
|
||||
elif platform.machine() not in ['x86_64', 'i686']:
|
||||
if manylinux_image in ['manylinux1', 'manylinux2010']:
|
||||
if utils.platform != "linux":
|
||||
pytest.skip("the docker test is only relevant to the linux build")
|
||||
elif platform.machine() not in ["x86_64", "i686"]:
|
||||
if manylinux_image in ["manylinux1", "manylinux2010"]:
|
||||
pytest.skip("manylinux1 and 2010 doesn't exist for non-x86 architectures")
|
||||
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
project_with_manylinux_symbols.generate(project_dir)
|
||||
|
||||
# build the wheels
|
||||
# CFLAGS environment variable is necessary to fail on 'malloc_info' (on manylinux1) during compilation/linking,
|
||||
# rather than when dynamically loading the Python
|
||||
add_env = {
|
||||
'CIBW_ENVIRONMENT': 'CFLAGS="$CFLAGS -O0 -Werror=implicit-function-declaration"',
|
||||
'CIBW_MANYLINUX_X86_64_IMAGE': manylinux_image,
|
||||
'CIBW_MANYLINUX_I686_IMAGE': manylinux_image,
|
||||
'CIBW_MANYLINUX_PYPY_X86_64_IMAGE': manylinux_image,
|
||||
'CIBW_MANYLINUX_AARCH64_IMAGE': manylinux_image,
|
||||
'CIBW_MANYLINUX_PPC64LE_IMAGE': manylinux_image,
|
||||
'CIBW_MANYLINUX_S390X_IMAGE': manylinux_image,
|
||||
"CIBW_ENVIRONMENT": 'CFLAGS="$CFLAGS -O0 -Werror=implicit-function-declaration"',
|
||||
"CIBW_MANYLINUX_X86_64_IMAGE": manylinux_image,
|
||||
"CIBW_MANYLINUX_I686_IMAGE": manylinux_image,
|
||||
"CIBW_MANYLINUX_PYPY_X86_64_IMAGE": manylinux_image,
|
||||
"CIBW_MANYLINUX_AARCH64_IMAGE": manylinux_image,
|
||||
"CIBW_MANYLINUX_PPC64LE_IMAGE": manylinux_image,
|
||||
"CIBW_MANYLINUX_S390X_IMAGE": manylinux_image,
|
||||
}
|
||||
if manylinux_image == 'manylinux1':
|
||||
if manylinux_image == "manylinux1":
|
||||
# We don't have a manylinux1 image for PyPy
|
||||
add_env['CIBW_SKIP'] = 'pp*'
|
||||
elif manylinux_image in {'manylinux2014', 'manylinux_2_24'}:
|
||||
add_env["CIBW_SKIP"] = "pp*"
|
||||
elif manylinux_image in {"manylinux2014", "manylinux_2_24"}:
|
||||
# We don't have a manylinux2014 / 'manylinux_2_24' image for PyPy (yet?)
|
||||
# Python 2.7 not available on manylinux2014 / 'manylinux_2_24'
|
||||
add_env['CIBW_SKIP'] = 'cp27* pp*'
|
||||
add_env["CIBW_SKIP"] = "cp27* pp*"
|
||||
actual_wheels = utils.cibuildwheel_run(project_dir, add_env=add_env)
|
||||
|
||||
expected_wheels = [
|
||||
w for w in utils.expected_wheels('spam', '0.1.0', manylinux_versions=[manylinux_image])
|
||||
w for w in utils.expected_wheels("spam", "0.1.0", manylinux_versions=[manylinux_image])
|
||||
]
|
||||
if manylinux_image in {'manylinux2014', 'manylinux_2_24'}:
|
||||
expected_wheels = [w for w in expected_wheels if '-cp27' not in w]
|
||||
if manylinux_image in {'manylinux1', 'manylinux2014', 'manylinux_2_24'}:
|
||||
expected_wheels = [w for w in expected_wheels if '-pp' not in w]
|
||||
if manylinux_image in {"manylinux2014", "manylinux_2_24"}:
|
||||
expected_wheels = [w for w in expected_wheels if "-cp27" not in w]
|
||||
if manylinux_image in {"manylinux1", "manylinux2014", "manylinux_2_24"}:
|
||||
expected_wheels = [w for w in expected_wheels if "-pp" not in w]
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
@@ -8,42 +8,42 @@ from pathlib import Path
|
||||
|
||||
def main():
|
||||
parser = ArgumentParser(
|
||||
prog="python -m test.test_projects", description='Generate a test project to check it out'
|
||||
prog="python -m test.test_projects", description="Generate a test project to check it out"
|
||||
)
|
||||
parser.add_argument(
|
||||
'--open',
|
||||
action='store_true',
|
||||
help='Open the generated project in a file explorer',
|
||||
"--open",
|
||||
action="store_true",
|
||||
help="Open the generated project in a file explorer",
|
||||
)
|
||||
parser.add_argument(
|
||||
'PROJECT',
|
||||
help='Python path to a project object. E.g. test.test_0_basic.basic_project',
|
||||
"PROJECT",
|
||||
help="Python path to a project object. E.g. test.test_0_basic.basic_project",
|
||||
)
|
||||
parser.add_argument(
|
||||
'OUTPUT',
|
||||
nargs='?',
|
||||
help='Path to output dir. If no dir is passed, a tempdir will be generated.',
|
||||
"OUTPUT",
|
||||
nargs="?",
|
||||
help="Path to output dir. If no dir is passed, a tempdir will be generated.",
|
||||
)
|
||||
options = parser.parse_args()
|
||||
|
||||
module, _, name = options.PROJECT.rpartition('.')
|
||||
module, _, name = options.PROJECT.rpartition(".")
|
||||
|
||||
project = getattr(importlib.import_module(module), name)
|
||||
|
||||
project_dir = Path(options.OUTPUT or tempfile.mkdtemp())
|
||||
project.generate(project_dir)
|
||||
|
||||
print('Project generated at', project_dir)
|
||||
print("Project generated at", project_dir)
|
||||
print()
|
||||
|
||||
if options.open:
|
||||
if sys.platform == 'darwin':
|
||||
subprocess.run(['open', '--', project_dir], check=True)
|
||||
elif sys.platform == 'linux2':
|
||||
subprocess.run(['xdg-open', '--', project_dir], check=True)
|
||||
elif sys.platform == 'win32':
|
||||
subprocess.run(['explorer', project_dir], check=True)
|
||||
if sys.platform == "darwin":
|
||||
subprocess.run(["open", "--", project_dir], check=True)
|
||||
elif sys.platform == "linux2":
|
||||
subprocess.run(["xdg-open", "--", project_dir], check=True)
|
||||
elif sys.platform == "win32":
|
||||
subprocess.run(["explorer", project_dir], check=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -8,12 +8,12 @@ TemplateContext = Dict[str, Any]
|
||||
|
||||
|
||||
class TestProject:
|
||||
'''
|
||||
"""
|
||||
An object that represents a project that can be built by cibuildwheel.
|
||||
Can be manipulated in tests by changing `files` and `template_context`.
|
||||
|
||||
Write out to the filesystem using `generate`.
|
||||
'''
|
||||
"""
|
||||
|
||||
__test__ = False # Have pytest ignore this class on `from .test_projects import TestProject`
|
||||
|
||||
@@ -29,7 +29,7 @@ class TestProject:
|
||||
file_path = path / filename
|
||||
file_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with file_path.open('w', encoding='utf8') as f:
|
||||
with file_path.open("w", encoding="utf8") as f:
|
||||
if isinstance(content, jinja2.Template):
|
||||
content = content.render(self.template_context)
|
||||
|
||||
|
||||
+19
-19
@@ -2,7 +2,7 @@ import jinja2
|
||||
|
||||
from .base import TestProject
|
||||
|
||||
SPAM_C_TEMPLATE = r'''
|
||||
SPAM_C_TEMPLATE = r"""
|
||||
#include <Python.h>
|
||||
|
||||
{{ spam_c_top_level_add }}
|
||||
@@ -57,9 +57,9 @@ MOD_INIT(spam)
|
||||
|
||||
MOD_RETURN(m)
|
||||
}
|
||||
'''
|
||||
"""
|
||||
|
||||
SETUP_PY_TEMPLATE = r'''
|
||||
SETUP_PY_TEMPLATE = r"""
|
||||
import sys
|
||||
from setuptools import setup, Extension
|
||||
|
||||
@@ -77,42 +77,42 @@ setup(
|
||||
)],
|
||||
{{ setup_py_setup_args_add | indent(4) }}
|
||||
)
|
||||
'''
|
||||
"""
|
||||
|
||||
SETUP_CFG_TEMPLATE = r'''
|
||||
SETUP_CFG_TEMPLATE = r"""
|
||||
[metadata]
|
||||
name = spam
|
||||
version = 0.1.0
|
||||
|
||||
{{ setup_cfg_add }}
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
def new_c_project(
|
||||
*,
|
||||
spam_c_top_level_add='',
|
||||
spam_c_function_add='',
|
||||
setup_py_add='',
|
||||
setup_py_setup_args_add='',
|
||||
setup_cfg_add='',
|
||||
spam_c_top_level_add="",
|
||||
spam_c_function_add="",
|
||||
setup_py_add="",
|
||||
setup_py_setup_args_add="",
|
||||
setup_cfg_add="",
|
||||
):
|
||||
project = TestProject()
|
||||
|
||||
project.files.update(
|
||||
{
|
||||
'spam.c': jinja2.Template(SPAM_C_TEMPLATE),
|
||||
'setup.py': jinja2.Template(SETUP_PY_TEMPLATE),
|
||||
'setup.cfg': jinja2.Template(SETUP_CFG_TEMPLATE),
|
||||
"spam.c": jinja2.Template(SPAM_C_TEMPLATE),
|
||||
"setup.py": jinja2.Template(SETUP_PY_TEMPLATE),
|
||||
"setup.cfg": jinja2.Template(SETUP_CFG_TEMPLATE),
|
||||
}
|
||||
)
|
||||
|
||||
project.template_context.update(
|
||||
{
|
||||
'spam_c_top_level_add': spam_c_top_level_add,
|
||||
'spam_c_function_add': spam_c_function_add,
|
||||
'setup_py_add': setup_py_add,
|
||||
'setup_py_setup_args_add': setup_py_setup_args_add,
|
||||
'setup_cfg_add': setup_cfg_add,
|
||||
"spam_c_top_level_add": spam_c_top_level_add,
|
||||
"spam_c_function_add": spam_c_function_add,
|
||||
"setup_py_add": setup_py_add,
|
||||
"setup_py_setup_args_add": setup_py_setup_args_add,
|
||||
"setup_cfg_add": setup_cfg_add,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
+10
-10
@@ -7,8 +7,8 @@ from . import utils
|
||||
|
||||
pure_python_project = test_projects.TestProject()
|
||||
pure_python_project.files[
|
||||
'setup.py'
|
||||
] = '''
|
||||
"setup.py"
|
||||
] = """
|
||||
from setuptools import Extension, setup
|
||||
|
||||
setup(
|
||||
@@ -16,27 +16,27 @@ setup(
|
||||
py_modules=['spam'],
|
||||
version="0.1.0",
|
||||
)
|
||||
'''
|
||||
"""
|
||||
|
||||
pure_python_project.files[
|
||||
'spam.py'
|
||||
] = '''
|
||||
"spam.py"
|
||||
] = """
|
||||
def a_function():
|
||||
pass
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
def test(tmp_path, capfd):
|
||||
# this test checks that if a pure wheel is generated, the build should
|
||||
# fail.
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
pure_python_project.generate(project_dir)
|
||||
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
actual_wheels = utils.cibuildwheel_run(project_dir)
|
||||
print('produced wheels:', actual_wheels)
|
||||
print("produced wheels:", actual_wheels)
|
||||
|
||||
captured = capfd.readouterr()
|
||||
print('out', captured.out)
|
||||
print('err', captured.err)
|
||||
print("out", captured.out)
|
||||
print("err", captured.err)
|
||||
assert "Build failed because a pure Python wheel was generated" in captured.err
|
||||
|
||||
+4
-4
@@ -4,7 +4,7 @@ from . import test_projects, utils
|
||||
|
||||
project_with_ssl_tests = test_projects.new_c_project(
|
||||
setup_py_add=textwrap.dedent(
|
||||
r'''
|
||||
r"""
|
||||
import ssl
|
||||
|
||||
if sys.version_info[0] == 2:
|
||||
@@ -16,7 +16,7 @@ project_with_ssl_tests = test_projects.new_c_project(
|
||||
data = urlopen("https://www.nist.gov", context=context)
|
||||
data = urlopen("https://raw.githubusercontent.com/joerick/cibuildwheel/master/CI.md", context=context)
|
||||
data = urlopen("https://raw.githubusercontent.com/joerick/cibuildwheel/master/CI.md")
|
||||
'''
|
||||
"""
|
||||
)
|
||||
)
|
||||
|
||||
@@ -24,10 +24,10 @@ project_with_ssl_tests = test_projects.new_c_project(
|
||||
def test(tmp_path):
|
||||
# this test checks that SSL is working in the build environment using
|
||||
# some checks in setup.py.
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
project_with_ssl_tests.generate(project_dir)
|
||||
|
||||
actual_wheels = utils.cibuildwheel_run(project_dir)
|
||||
|
||||
expected_wheels = utils.expected_wheels('spam', '0.1.0')
|
||||
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
+18
-18
@@ -8,13 +8,13 @@ from .test_projects.c import SPAM_C_TEMPLATE
|
||||
|
||||
subdir_package_project = TestProject()
|
||||
|
||||
subdir_package_project.files['src/spam/spam.c'] = jinja2.Template(SPAM_C_TEMPLATE)
|
||||
subdir_package_project.template_context['spam_c_top_level_add'] = ''
|
||||
subdir_package_project.template_context['spam_c_function_add'] = ''
|
||||
subdir_package_project.files["src/spam/spam.c"] = jinja2.Template(SPAM_C_TEMPLATE)
|
||||
subdir_package_project.template_context["spam_c_top_level_add"] = ""
|
||||
subdir_package_project.template_context["spam_c_function_add"] = ""
|
||||
|
||||
subdir_package_project.files[
|
||||
'src/spam/setup.py'
|
||||
] = r'''
|
||||
"src/spam/setup.py"
|
||||
] = r"""
|
||||
from setuptools import Extension, setup
|
||||
|
||||
setup(
|
||||
@@ -22,40 +22,40 @@ setup(
|
||||
ext_modules=[Extension('spam', sources=['spam.c'])],
|
||||
version="0.1.0",
|
||||
)
|
||||
'''
|
||||
"""
|
||||
|
||||
subdir_package_project.files[
|
||||
'src/spam/test/run_tests.py'
|
||||
] = r'''
|
||||
"src/spam/test/run_tests.py"
|
||||
] = r"""
|
||||
print('run_tests.py executed!')
|
||||
'''
|
||||
"""
|
||||
|
||||
subdir_package_project.files[
|
||||
'bin/before_build.py'
|
||||
] = r'''
|
||||
"bin/before_build.py"
|
||||
] = r"""
|
||||
print('before_build.py executed!')
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
def test(capfd, tmp_path):
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
subdir_package_project.generate(project_dir)
|
||||
|
||||
package_dir = Path('src', 'spam')
|
||||
package_dir = Path("src", "spam")
|
||||
# build the wheels
|
||||
actual_wheels = utils.cibuildwheel_run(
|
||||
project_dir,
|
||||
package_dir=package_dir,
|
||||
add_env={
|
||||
'CIBW_BEFORE_BUILD': 'python {project}/bin/before_build.py',
|
||||
'CIBW_TEST_COMMAND': 'python {package}/test/run_tests.py',
|
||||
"CIBW_BEFORE_BUILD": "python {project}/bin/before_build.py",
|
||||
"CIBW_TEST_COMMAND": "python {package}/test/run_tests.py",
|
||||
# this shouldn't depend on the version of python, so build only CPython 3.6
|
||||
'CIBW_BUILD': 'cp36-*',
|
||||
"CIBW_BUILD": "cp36-*",
|
||||
},
|
||||
)
|
||||
|
||||
# check that the expected wheels are produced
|
||||
expected_wheels = [w for w in utils.expected_wheels('spam', '0.1.0') if 'cp36' in w]
|
||||
expected_wheels = [w for w in utils.expected_wheels("spam", "0.1.0") if "cp36" in w]
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
captured = capfd.readouterr()
|
||||
|
||||
+22
-22
@@ -8,15 +8,15 @@ from . import test_projects, utils
|
||||
|
||||
project_with_a_test = test_projects.new_c_project(
|
||||
setup_cfg_add=textwrap.dedent(
|
||||
r'''
|
||||
r"""
|
||||
[options.extras_require]
|
||||
test = nose
|
||||
'''
|
||||
"""
|
||||
)
|
||||
)
|
||||
|
||||
project_with_a_test.files[
|
||||
'test/spam_test.py'
|
||||
"test/spam_test.py"
|
||||
] = r'''
|
||||
import os
|
||||
import platform
|
||||
@@ -75,63 +75,63 @@ class TestSpam(TestCase):
|
||||
|
||||
|
||||
def test(tmp_path):
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
project_with_a_test.generate(project_dir)
|
||||
|
||||
# build and test the wheels
|
||||
actual_wheels = utils.cibuildwheel_run(
|
||||
project_dir,
|
||||
add_env={
|
||||
'CIBW_TEST_REQUIRES': 'nose',
|
||||
"CIBW_TEST_REQUIRES": "nose",
|
||||
# the 'false ||' bit is to ensure this command runs in a shell on
|
||||
# mac/linux.
|
||||
'CIBW_TEST_COMMAND': 'false || nosetests {project}/test',
|
||||
'CIBW_TEST_COMMAND_WINDOWS': 'COLOR 00 || nosetests {project}/test',
|
||||
"CIBW_TEST_COMMAND": "false || nosetests {project}/test",
|
||||
"CIBW_TEST_COMMAND_WINDOWS": "COLOR 00 || nosetests {project}/test",
|
||||
},
|
||||
)
|
||||
|
||||
# also check that we got the right wheels
|
||||
expected_wheels = utils.expected_wheels('spam', '0.1.0')
|
||||
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
|
||||
def test_extras_require(tmp_path):
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
project_with_a_test.generate(project_dir)
|
||||
|
||||
# build and test the wheels
|
||||
actual_wheels = utils.cibuildwheel_run(
|
||||
project_dir,
|
||||
add_env={
|
||||
'CIBW_TEST_EXTRAS': 'test',
|
||||
"CIBW_TEST_EXTRAS": "test",
|
||||
# the 'false ||' bit is to ensure this command runs in a shell on
|
||||
# mac/linux.
|
||||
'CIBW_TEST_COMMAND': 'false || nosetests {project}/test',
|
||||
'CIBW_TEST_COMMAND_WINDOWS': 'COLOR 00 || nosetests {project}/test',
|
||||
"CIBW_TEST_COMMAND": "false || nosetests {project}/test",
|
||||
"CIBW_TEST_COMMAND_WINDOWS": "COLOR 00 || nosetests {project}/test",
|
||||
},
|
||||
)
|
||||
|
||||
# also check that we got the right wheels
|
||||
expected_wheels = utils.expected_wheels('spam', '0.1.0')
|
||||
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
|
||||
project_with_a_failing_test = test_projects.new_c_project()
|
||||
project_with_a_failing_test.files[
|
||||
'test/spam_test.py'
|
||||
] = r'''
|
||||
"test/spam_test.py"
|
||||
] = r"""
|
||||
from unittest import TestCase
|
||||
|
||||
class TestSpam(TestCase):
|
||||
def test_something(self):
|
||||
self.fail('this test is supposed to fail')
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
def test_failing_test(tmp_path):
|
||||
"""Ensure a failing test causes cibuildwheel to error out and exit"""
|
||||
project_dir = tmp_path / 'project'
|
||||
output_dir = tmp_path / 'output'
|
||||
project_dir = tmp_path / "project"
|
||||
output_dir = tmp_path / "output"
|
||||
project_with_a_failing_test.generate(project_dir)
|
||||
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
@@ -139,12 +139,12 @@ def test_failing_test(tmp_path):
|
||||
project_dir,
|
||||
output_dir=output_dir,
|
||||
add_env={
|
||||
'CIBW_TEST_REQUIRES': 'nose',
|
||||
'CIBW_TEST_COMMAND': 'nosetests {project}/test',
|
||||
"CIBW_TEST_REQUIRES": "nose",
|
||||
"CIBW_TEST_COMMAND": "nosetests {project}/test",
|
||||
# manylinux1 has a version of bash that's been shown to have
|
||||
# problems with this, so let's check that.
|
||||
'CIBW_MANYLINUX_I686_IMAGE': 'manylinux1',
|
||||
'CIBW_MANYLINUX_X86_64_IMAGE': 'manylinux1',
|
||||
"CIBW_MANYLINUX_I686_IMAGE": "manylinux1",
|
||||
"CIBW_MANYLINUX_X86_64_IMAGE": "manylinux1",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -7,26 +7,26 @@ from .test_projects import TestProject
|
||||
|
||||
so_file_project = TestProject()
|
||||
|
||||
so_file_project.files['libnothing.so'] = ''
|
||||
so_file_project.files["libnothing.so"] = ""
|
||||
|
||||
so_file_project.files[
|
||||
'setup.py'
|
||||
] = '''
|
||||
"setup.py"
|
||||
] = """
|
||||
raise Exception('this build will fail')
|
||||
'''
|
||||
"""
|
||||
|
||||
|
||||
def test_failed_project_with_so_files(tmp_path, capfd):
|
||||
if utils.platform != 'linux':
|
||||
pytest.skip('this test is only relevant to the linux build')
|
||||
if utils.platform != "linux":
|
||||
pytest.skip("this test is only relevant to the linux build")
|
||||
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
so_file_project.generate(project_dir)
|
||||
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
utils.cibuildwheel_run(project_dir)
|
||||
|
||||
captured = capfd.readouterr()
|
||||
print('out', captured.out)
|
||||
print('err', captured.err)
|
||||
print("out", captured.out)
|
||||
print("err", captured.err)
|
||||
assert "NOTE: Shared object (.so) files found in this project." in captured.err
|
||||
|
||||
@@ -6,27 +6,27 @@ from . import test_projects, utils
|
||||
|
||||
project_with_unicode = test_projects.new_c_project(
|
||||
spam_c_function_add=textwrap.dedent(
|
||||
r'''
|
||||
r"""
|
||||
{
|
||||
Py_XDECREF(PyUnicode_FromStringAndSize("foo", 4));
|
||||
}
|
||||
'''
|
||||
"""
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def test(tmp_path):
|
||||
if utils.platform != 'linux':
|
||||
pytest.skip('the docker test is only relevant to the linux build')
|
||||
if utils.platform != "linux":
|
||||
pytest.skip("the docker test is only relevant to the linux build")
|
||||
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir = tmp_path / "project"
|
||||
project_with_unicode.generate(project_dir)
|
||||
|
||||
# build the wheels
|
||||
actual_wheels = utils.cibuildwheel_run(
|
||||
project_dir, add_env={'CIBW_TEST_COMMAND': 'python -c "import spam"'}
|
||||
project_dir, add_env={"CIBW_TEST_COMMAND": 'python -c "import spam"'}
|
||||
)
|
||||
|
||||
# check that the expected wheels are produced
|
||||
expected_wheels = utils.expected_wheels('spam', '0.1.0')
|
||||
expected_wheels = utils.expected_wheels("spam", "0.1.0")
|
||||
assert set(actual_wheels) == set(expected_wheels)
|
||||
|
||||
+58
-58
@@ -1,8 +1,8 @@
|
||||
'''
|
||||
"""
|
||||
Utility functions used by the cibuildwheel tests.
|
||||
|
||||
This file is added to the PYTHONPATH in the test runner at bin/run_test.py.
|
||||
'''
|
||||
"""
|
||||
|
||||
import os
|
||||
import platform as pm
|
||||
@@ -14,16 +14,16 @@ from tempfile import mkdtemp
|
||||
|
||||
platform: str
|
||||
|
||||
if 'CIBW_PLATFORM' in os.environ:
|
||||
platform = os.environ['CIBW_PLATFORM']
|
||||
elif sys.platform.startswith('linux'):
|
||||
platform = 'linux'
|
||||
elif sys.platform.startswith('darwin'):
|
||||
platform = 'macos'
|
||||
elif sys.platform in ['win32', 'cygwin']:
|
||||
platform = 'windows'
|
||||
if "CIBW_PLATFORM" in os.environ:
|
||||
platform = os.environ["CIBW_PLATFORM"]
|
||||
elif sys.platform.startswith("linux"):
|
||||
platform = "linux"
|
||||
elif sys.platform.startswith("darwin"):
|
||||
platform = "macos"
|
||||
elif sys.platform in ["win32", "cygwin"]:
|
||||
platform = "windows"
|
||||
else:
|
||||
raise Exception('Unsupported platform')
|
||||
raise Exception("Unsupported platform")
|
||||
|
||||
|
||||
# Python 2 does not have a tempfile.TemporaryDirectory context manager
|
||||
@@ -38,23 +38,23 @@ def TemporaryDirectoryIfNone(path):
|
||||
|
||||
|
||||
def cibuildwheel_get_build_identifiers(project_path, env=None):
|
||||
'''
|
||||
"""
|
||||
Returns the list of build identifiers that cibuildwheel will try to build
|
||||
for the current platform.
|
||||
'''
|
||||
"""
|
||||
cmd_output = subprocess.run(
|
||||
[sys.executable, '-m', 'cibuildwheel', '--print-build-identifiers', str(project_path)],
|
||||
[sys.executable, "-m", "cibuildwheel", "--print-build-identifiers", str(project_path)],
|
||||
universal_newlines=True,
|
||||
env=env,
|
||||
check=True,
|
||||
stdout=subprocess.PIPE,
|
||||
).stdout
|
||||
|
||||
return cmd_output.strip().split('\n')
|
||||
return cmd_output.strip().split("\n")
|
||||
|
||||
|
||||
def cibuildwheel_run(project_path, package_dir='.', env=None, add_env=None, output_dir=None):
|
||||
'''
|
||||
def cibuildwheel_run(project_path, package_dir=".", env=None, add_env=None, output_dir=None):
|
||||
"""
|
||||
Runs cibuildwheel as a subprocess, building the project at project_path.
|
||||
|
||||
Uses the current Python interpreter.
|
||||
@@ -67,11 +67,11 @@ def cibuildwheel_run(project_path, package_dir='.', env=None, add_env=None, outp
|
||||
:param output_dir: directory where wheels are saved. If None, a temporary
|
||||
directory will be used for the duration of the command.
|
||||
:return: list of built wheels (file names).
|
||||
'''
|
||||
"""
|
||||
if env is None:
|
||||
env = os.environ.copy()
|
||||
# If present in the host environment, remove the MACOSX_DEPLOYMENT_TARGET for consistency
|
||||
env.pop('MACOSX_DEPLOYMENT_TARGET', None)
|
||||
env.pop("MACOSX_DEPLOYMENT_TARGET", None)
|
||||
|
||||
if add_env is not None:
|
||||
env.update(add_env)
|
||||
@@ -80,9 +80,9 @@ def cibuildwheel_run(project_path, package_dir='.', env=None, add_env=None, outp
|
||||
subprocess.run(
|
||||
[
|
||||
sys.executable,
|
||||
'-m',
|
||||
'cibuildwheel',
|
||||
'--output-dir',
|
||||
"-m",
|
||||
"cibuildwheel",
|
||||
"--output-dir",
|
||||
str(_output_dir),
|
||||
str(package_dir),
|
||||
],
|
||||
@@ -95,14 +95,14 @@ def cibuildwheel_run(project_path, package_dir='.', env=None, add_env=None, outp
|
||||
|
||||
|
||||
def _get_arm64_macosx_deployment_target(macosx_deployment_target: str) -> str:
|
||||
'''
|
||||
"""
|
||||
The first version of macOS that supports arm is 11.0. So the wheel tag
|
||||
cannot contain an earlier deployment target, even if
|
||||
MACOSX_DEPLOYMENT_TARGET sets it.
|
||||
'''
|
||||
version_tuple = tuple(map(int, macosx_deployment_target.split('.')))
|
||||
"""
|
||||
version_tuple = tuple(map(int, macosx_deployment_target.split(".")))
|
||||
if version_tuple <= (11, 0):
|
||||
return '11.0'
|
||||
return "11.0"
|
||||
else:
|
||||
return macosx_deployment_target
|
||||
|
||||
@@ -111,14 +111,14 @@ def expected_wheels(
|
||||
package_name,
|
||||
package_version,
|
||||
manylinux_versions=None,
|
||||
macosx_deployment_target='10.9',
|
||||
macosx_deployment_target="10.9",
|
||||
machine_arch=None,
|
||||
*,
|
||||
exclude_27=platform == 'windows',
|
||||
exclude_27=platform == "windows",
|
||||
):
|
||||
'''
|
||||
"""
|
||||
Returns a list of expected wheels from a run of cibuildwheel.
|
||||
'''
|
||||
"""
|
||||
# per PEP 425 (https://www.python.org/dev/peps/pep-0425/), wheel files shall have name of the form
|
||||
# {distribution}-{version}(-{build tag})?-{python tag}-{abi tag}-{platform tag}.whl
|
||||
# {python tag} and {abi tag} are closely related to the python interpreter used to build the wheel
|
||||
@@ -128,55 +128,55 @@ def expected_wheels(
|
||||
machine_arch = pm.machine()
|
||||
|
||||
if manylinux_versions is None:
|
||||
if machine_arch == 'x86_64':
|
||||
manylinux_versions = ['manylinux1', 'manylinux2010']
|
||||
if machine_arch == "x86_64":
|
||||
manylinux_versions = ["manylinux1", "manylinux2010"]
|
||||
else:
|
||||
manylinux_versions = ['manylinux2014']
|
||||
manylinux_versions = ["manylinux2014"]
|
||||
|
||||
python_abi_tags = ['cp35-cp35m', 'cp36-cp36m', 'cp37-cp37m', 'cp38-cp38', 'cp39-cp39']
|
||||
python_abi_tags = ["cp35-cp35m", "cp36-cp36m", "cp37-cp37m", "cp38-cp38", "cp39-cp39"]
|
||||
|
||||
if machine_arch in ['x86_64', 'AMD64', 'x86']:
|
||||
python_abi_tags += ['cp27-cp27m', 'pp27-pypy_73', 'pp36-pypy36_pp73', 'pp37-pypy37_pp73']
|
||||
if machine_arch in ["x86_64", "AMD64", "x86"]:
|
||||
python_abi_tags += ["cp27-cp27m", "pp27-pypy_73", "pp36-pypy36_pp73", "pp37-pypy37_pp73"]
|
||||
|
||||
if platform == 'linux':
|
||||
python_abi_tags.append('cp27-cp27mu') # python 2.7 has 2 different ABI on manylinux
|
||||
if platform == "linux":
|
||||
python_abi_tags.append("cp27-cp27mu") # python 2.7 has 2 different ABI on manylinux
|
||||
|
||||
if platform == 'macos' and get_macos_version() >= (10, 16):
|
||||
if platform == "macos" and get_macos_version() >= (10, 16):
|
||||
# 10.16 is sometimes reported as the macOS version on macOS 11.
|
||||
# CPython 3.5 doesn't work on macOS 11.
|
||||
python_abi_tags.remove('cp35-cp35m')
|
||||
python_abi_tags.remove("cp35-cp35m")
|
||||
# pypy not supported on macOS 11.
|
||||
python_abi_tags = [t for t in python_abi_tags if not t.startswith('pp')]
|
||||
python_abi_tags = [t for t in python_abi_tags if not t.startswith("pp")]
|
||||
|
||||
if platform == 'macos' and machine_arch == 'arm64':
|
||||
if platform == "macos" and machine_arch == "arm64":
|
||||
# currently, arm64 macs are only supported by cp39
|
||||
python_abi_tags = ['cp39-cp39']
|
||||
python_abi_tags = ["cp39-cp39"]
|
||||
|
||||
wheels = []
|
||||
|
||||
for python_abi_tag in python_abi_tags:
|
||||
platform_tags = []
|
||||
|
||||
if platform == 'linux':
|
||||
if platform == "linux":
|
||||
architectures = [machine_arch]
|
||||
|
||||
if machine_arch == 'x86_64' and python_abi_tag.startswith('cp'):
|
||||
architectures.append('i686')
|
||||
if machine_arch == "x86_64" and python_abi_tag.startswith("cp"):
|
||||
architectures.append("i686")
|
||||
|
||||
platform_tags = [
|
||||
f'{manylinux_version}_{architecture}'
|
||||
f"{manylinux_version}_{architecture}"
|
||||
for architecture in architectures
|
||||
for manylinux_version in manylinux_versions
|
||||
]
|
||||
|
||||
elif platform == 'windows':
|
||||
if python_abi_tag.startswith('cp'):
|
||||
platform_tags = ['win32', 'win_amd64']
|
||||
elif platform == "windows":
|
||||
if python_abi_tag.startswith("cp"):
|
||||
platform_tags = ["win32", "win_amd64"]
|
||||
else:
|
||||
platform_tags = ['win32']
|
||||
platform_tags = ["win32"]
|
||||
|
||||
elif platform == 'macos':
|
||||
if python_abi_tag == 'cp39-cp39' and machine_arch == 'arm64':
|
||||
elif platform == "macos":
|
||||
if python_abi_tag == "cp39-cp39" and machine_arch == "arm64":
|
||||
arm64_macosx_deployment_target = _get_arm64_macosx_deployment_target(
|
||||
macosx_deployment_target
|
||||
)
|
||||
@@ -190,26 +190,26 @@ def expected_wheels(
|
||||
]
|
||||
|
||||
else:
|
||||
raise Exception('unsupported platform')
|
||||
raise Exception("unsupported platform")
|
||||
|
||||
for platform_tag in platform_tags:
|
||||
wheels.append(f'{package_name}-{package_version}-{python_abi_tag}-{platform_tag}.whl')
|
||||
wheels.append(f"{package_name}-{package_version}-{python_abi_tag}-{platform_tag}.whl")
|
||||
|
||||
# Travis on Windows does not support using the default Python 2.7 compiler,
|
||||
# so we support skipping here.
|
||||
if exclude_27:
|
||||
wheels = [w for w in wheels if '-cp27-' not in w and '-pp2' not in w]
|
||||
wheels = [w for w in wheels if "-cp27-" not in w and "-pp2" not in w]
|
||||
|
||||
return wheels
|
||||
|
||||
|
||||
def get_macos_version():
|
||||
'''
|
||||
"""
|
||||
Returns the macOS major/minor version, as a tuple, e.g. (10, 15) or (11, 0)
|
||||
|
||||
These tuples can be used in comparisons, e.g.
|
||||
(10, 14) <= (11, 0) == True
|
||||
(11, 2) <= (11, 0) != True
|
||||
'''
|
||||
"""
|
||||
version_str, _, _ = pm.mac_ver()
|
||||
return tuple(map(int, version_str.split(".")[:2]))
|
||||
|
||||
Reference in New Issue
Block a user