Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add support for
py3-none-{platform}
wheels (#1151)
* feature: add support for `py3-none-{platform}` wheels This extends the mechanism introduced in #1091 for `abi3` wheels. Most of the mentions to `abi3` have been removed and replaced by a more generic `compatible_wheel`. This allows to build a wheel `foo-0.1-py3-none-win_amd64.whl` only once and still test with every configured python. * Add integration test for py3-none abi wheels * Fix expected_wheels for py3-none abi * Limit test to three pythons and check for certain log messages * chore: add some comments to explain filter process Co-authored-by: Joe Rickerby <joerick@mac.com> Co-authored-by: Henry Schreiner <henryschreineriii@gmail.com>
- Loading branch information
1 parent
0757924
commit 9a53751
Showing
9 changed files
with
284 additions
and
100 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
import textwrap | ||
|
||
from . import test_projects, utils | ||
|
||
limited_api_project = test_projects.new_c_project( | ||
setup_py_add=textwrap.dedent( | ||
r""" | ||
cmdclass = {} | ||
extension_kwargs = {} | ||
if sys.version_info[:2] >= (3, 8): | ||
from wheel.bdist_wheel import bdist_wheel as _bdist_wheel | ||
class bdist_wheel_abi3(_bdist_wheel): | ||
def finalize_options(self): | ||
_bdist_wheel.finalize_options(self) | ||
self.root_is_pure = False | ||
def get_tag(self): | ||
python, abi, plat = _bdist_wheel.get_tag(self) | ||
return python, "abi3", plat | ||
cmdclass["bdist_wheel"] = bdist_wheel_abi3 | ||
extension_kwargs["define_macros"] = [("Py_LIMITED_API", "0x03080000")] | ||
extension_kwargs["py_limited_api"] = True | ||
""" | ||
), | ||
setup_py_extension_args_add="**extension_kwargs", | ||
setup_py_setup_args_add="cmdclass=cmdclass", | ||
) | ||
|
||
|
||
def test_abi3(tmp_path): | ||
project_dir = tmp_path / "project" | ||
limited_api_project.generate(project_dir) | ||
|
||
# build the wheels | ||
actual_wheels = utils.cibuildwheel_run( | ||
project_dir, | ||
add_env={ | ||
"CIBW_SKIP": "pp* ", # PyPy does not have a Py_LIMITED_API equivalent | ||
}, | ||
) | ||
|
||
# check that the expected wheels are produced | ||
expected_wheels = [ | ||
w.replace("cp38-cp38", "cp38-abi3") | ||
for w in utils.expected_wheels("spam", "0.1.0") | ||
if "-pp" not in w and "-cp39" not in w and "-cp310" not in w and "-cp311" not in w | ||
] | ||
assert set(actual_wheels) == set(expected_wheels) | ||
|
||
|
||
ctypes_project = test_projects.TestProject() | ||
ctypes_project.files["setup.py"] = textwrap.dedent( | ||
""" | ||
from setuptools import setup, Extension | ||
from distutils.command.build_ext import build_ext as _build_ext | ||
class CTypesExtension(Extension): pass | ||
class build_ext(_build_ext): | ||
def build_extension(self, ext): | ||
self._ctypes = isinstance(ext, CTypesExtension) | ||
return super().build_extension(ext) | ||
def get_export_symbols(self, ext): | ||
if self._ctypes: | ||
return ext.export_symbols | ||
return super().get_export_symbols(ext) | ||
def get_ext_filename(self, ext_name): | ||
if self._ctypes: | ||
return ext_name + '.so' | ||
return super().get_ext_filename(ext_name) | ||
from wheel.bdist_wheel import bdist_wheel as _bdist_wheel | ||
class bdist_wheel_abi_none(_bdist_wheel): | ||
def finalize_options(self): | ||
_bdist_wheel.finalize_options(self) | ||
self.root_is_pure = False | ||
def get_tag(self): | ||
python, abi, plat = _bdist_wheel.get_tag(self) | ||
return "py3", "none", plat | ||
setup( | ||
name="ctypesexample", | ||
version="1.0.0", | ||
py_modules = ["ctypesexample.summing"], | ||
ext_modules=[ | ||
CTypesExtension( | ||
"ctypesexample.csumlib", | ||
["ctypesexample/csumlib.c"], | ||
), | ||
], | ||
cmdclass={'build_ext': build_ext, 'bdist_wheel': bdist_wheel_abi_none}, | ||
) | ||
""" | ||
) | ||
ctypes_project.files["ctypesexample/csumlib.c"] = textwrap.dedent( | ||
""" | ||
#ifdef _WIN32 | ||
#define LIBRARY_API __declspec(dllexport) | ||
#else | ||
#define LIBRARY_API | ||
#endif | ||
#include <stdlib.h> | ||
LIBRARY_API double *add_vec3(double *a, double *b) | ||
{ | ||
double *res = malloc(sizeof(double) * 3); | ||
for (int i = 0; i < 3; ++i) | ||
{ | ||
res[i] = a[i] + b[i]; | ||
} | ||
return res; | ||
} | ||
""" | ||
) | ||
ctypes_project.files["ctypesexample/summing.py"] = textwrap.dedent( | ||
""" | ||
import ctypes | ||
import pathlib | ||
# path of the shared library | ||
libfile = pathlib.Path(__file__).parent / "csumlib.so" | ||
csumlib = ctypes.CDLL(str(libfile)) | ||
type_vec3 = ctypes.POINTER(ctypes.c_double * 3) | ||
csumlib.add_vec3.restype = type_vec3 | ||
csumlib.add_vec3.argtypes = [type_vec3, type_vec3] | ||
def add(a: list, b: list) -> list: | ||
a_p = (ctypes.c_double * 3)(*a) | ||
b_p = (ctypes.c_double * 3)(*b) | ||
r_p = csumlib.add_vec3(a_p,b_p) | ||
return [l for l in r_p.contents] | ||
""" | ||
) | ||
|
||
ctypes_project.files["test/add_test.py"] = textwrap.dedent( | ||
""" | ||
import ctypesexample.summing | ||
def test(): | ||
a = [1, 2, 3] | ||
b = [4, 5, 6] | ||
assert ctypesexample.summing.add(a, b) == [5, 7, 9] | ||
""" | ||
) | ||
|
||
|
||
def test_abi_none(tmp_path, capfd): | ||
project_dir = tmp_path / "project" | ||
ctypes_project.generate(project_dir) | ||
|
||
# build the wheels | ||
actual_wheels = utils.cibuildwheel_run( | ||
project_dir, | ||
add_env={ | ||
"CIBW_TEST_REQUIRES": "pytest", | ||
"CIBW_TEST_COMMAND": "pytest {project}/test", | ||
# limit the number of builds for test performance reasons | ||
"CIBW_BUILD": "cp38-* cp310-* pp39-*", | ||
}, | ||
) | ||
|
||
# check that the expected wheels are produced | ||
expected_wheels = utils.expected_wheels("ctypesexample", "1.0.0", python_abi_tags=["py3-none"]) | ||
assert set(actual_wheels) == set(expected_wheels) | ||
|
||
# check that each wheel was built once, and reused | ||
captured = capfd.readouterr() | ||
assert "Building wheel..." in captured.out | ||
assert "Found previously built wheel" in captured.out |
Oops, something went wrong.