diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2ec36812..f14a12c5 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -5,7 +5,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: clone repo - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: build sdist run: | @@ -14,7 +14,7 @@ jobs: python -m build --sdist - name: upload sdist artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: path: dist if-no-files-found: error @@ -22,40 +22,47 @@ jobs: linux: runs-on: ubuntu-20.04 strategy: + fail-fast: false matrix: include: - - spec: cp27-manylinux_x86_64 - cibw_version: cibuildwheel<2.0 # py2.7 is not supported on CIBW 2.0+ - manylinux_img: manylinux1 # build really old Pythons on manylinux1 - - spec: cp36-manylinux_x86_64 - manylinux_img: manylinux1 # build really old Pythons on manylinux1 - - spec: cp37-manylinux_x86_64 - spec: cp38-manylinux_x86_64 - spec: cp39-manylinux_x86_64 - spec: cp310-manylinux_x86_64 - spec: cp311-manylinux_x86_64 - - spec: cp27-manylinux_i686 - cibw_version: cibuildwheel<2.0 # py2.7 is not supported on CIBW 2.0+ - manylinux_img: manylinux1 # build really old Pythons on manylinux1 - - spec: cp36-manylinux_i686 - manylinux_img: manylinux1 # build really old Pythons on manylinux1 - - spec: cp37-manylinux_i686 + - spec: cp312-manylinux_x86_64 + - spec: cp38-manylinux_i686 - spec: cp39-manylinux_i686 - spec: cp310-manylinux_i686 - spec: cp311-manylinux_i686 + - spec: cp312-manylinux_i686 + - spec: cp39-musllinux_x86_64 - spec: cp310-musllinux_x86_64 - spec: cp311-musllinux_x86_64 + - spec: cp312-musllinux_x86_64 + - spec: cp39-musllinux_i686 - spec: cp310-musllinux_i686 - spec: cp311-musllinux_i686 - - spec: cp36-manylinux_ppc64le + #- spec: cp312-musllinux_i686 # busted as of 9/22/23 + + - spec: cp38-manylinux_aarch64 + foreign_arch: true + test_args: '{project}/c' + - spec: cp39-manylinux_aarch64 + foreign_arch: true + test_args: '{project}/c' + - spec: cp310-manylinux_aarch64 + foreign_arch: true + test_args: '{project}/c' + - spec: cp311-manylinux_aarch64 foreign_arch: true test_args: '{project}/c' - - spec: cp37-manylinux_ppc64le + - spec: cp312-manylinux_aarch64 foreign_arch: true test_args: '{project}/c' + - spec: cp38-manylinux_ppc64le foreign_arch: true test_args: '{project}/c' @@ -68,9 +75,29 @@ jobs: - spec: cp311-manylinux_ppc64le foreign_arch: true test_args: '{project}/c' + - spec: cp312-manylinux_ppc64le + foreign_arch: true + test_args: '{project}/c' + + - spec: cp38-manylinux_s390x + foreign_arch: true + test_args: '{project}/c' + - spec: cp39-manylinux_s390x + foreign_arch: true + test_args: '{project}/c' + - spec: cp310-manylinux_s390x + foreign_arch: true + test_args: '{project}/c' + - spec: cp311-manylinux_s390x + foreign_arch: true + test_args: '{project}/c' + - spec: cp312-manylinux_s390x + foreign_arch: true + test_args: '{project}/c' + steps: - name: clone repo - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: configure docker foreign arch support uses: docker/setup-qemu-action@v1 @@ -94,7 +121,7 @@ jobs: CIBW_MANYLINUX_X86_64_IMAGE: ${{ matrix.manylinux_img || '' }} CIBW_MANYLINUX_I686_IMAGE: ${{ matrix.manylinux_img || '' }} CIBW_PRERELEASE_PYTHONS: 'True' - CIBW_TEST_REQUIRES: pytest + CIBW_TEST_REQUIRES: pytest setuptools # 3.12+ no longer includes distutils, just always ensure setuptools is present CIBW_TEST_COMMAND: PYTHONUNBUFFERED=1 python -m pytest ${{ matrix.test_args || '{project}' }} # default to test all run: | python -m pip install --upgrade "${{ matrix.cibw_version || 'cibuildwheel' }}" @@ -104,7 +131,7 @@ jobs: - name: upload artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: path: dist if-no-files-found: error @@ -114,21 +141,19 @@ jobs: defaults: run: shell: ${{ matrix.run_wrapper || 'bash --noprofile --norc -eo pipefail {0}' }} - runs-on: ${{ matrix.runs_on || 'macos-10.15' }} + runs-on: ${{ matrix.runs_on || 'macos-11' }} strategy: + fail-fast: false matrix: include: # build for x86_64 under the default hosted macOS 10.x x86_64 runner - - spec: cp27-macosx_x86_64 - cibw_version: cibuildwheel<2.0 # py2.7 is not supported on CIBW 2.0+ - - spec: cp36-macosx_x86_64 - - spec: cp37-macosx_x86_64 - spec: cp38-macosx_x86_64 - spec: cp39-macosx_x86_64 - spec: cp310-macosx_x86_64 - spec: cp311-macosx_x86_64 - # build for arm64 under a hacked macOS 12 self-hosted x86_64-on-arm64 runner until arm64 is fully supported - # FIXME: ? cp38-macosx_arm64 requires special handling and fails some test_zdist tests under cibw 2.1.2, skip it (so Apple's XCode python3 won't have a wheel) + - spec: cp312-macosx_x86_64 +# # build for arm64 under a hacked macOS 12 self-hosted x86_64-on-arm64 runner until arm64 is fully supported +# # FIXME: ? cp38-macosx_arm64 requires special handling and fails some test_zdist tests under cibw 2.1.2, skip it (so Apple's XCode python3 won't have a wheel) - spec: cp39-macosx_arm64 deployment_target: '11.0' runs_on: [self-hosted, macOS] @@ -147,9 +172,16 @@ jobs: run_wrapper: arch -arm64 bash --noprofile --norc -eo pipefail {0} sdkroot: macosx11.3 + - spec: cp312-macosx_arm64 + deployment_target: '11.0' + runs_on: [self-hosted, macOS] + run_wrapper: arch -arm64 bash --noprofile --norc -eo pipefail {0} + sdkroot: macosx11.3 + steps: - name: clone repo + # need to use v2 until we can upgrade the runners on our private Apple Silicon build infra to one that supports node20 uses: actions/checkout@v2 - name: build wheel prereqs @@ -161,7 +193,7 @@ jobs: env: CIBW_BUILD: ${{ matrix.spec }} CIBW_PRERELEASE_PYTHONS: 'True' - CIBW_TEST_REQUIRES: pytest + CIBW_TEST_REQUIRES: pytest setuptools CIBW_TEST_COMMAND: pip install pip --upgrade; cd {project}; PYTHONUNBUFFERED=1 pytest run: | if [[ -n "${{ matrix.deployment_target || '' }}" ]] @@ -177,6 +209,7 @@ jobs: /usr/bin/python3 -m cibuildwheel --output-dir dist - name: upload artifacts + # need to use v2 until we can upgrade the runners on our private Apple Silicon build infra to one that supports node20 uses: actions/upload-artifact@v2 with: path: dist @@ -185,56 +218,39 @@ jobs: windows: runs-on: windows-2019 strategy: + fail-fast: false matrix: include: - - spec: cp27-win_amd64 - cibw_version: cibuildwheel==1.10 # last release with proper py2.7 Windows support - - spec: cp36-win_amd64 - - spec: cp37-win_amd64 - spec: cp38-win_amd64 - spec: cp39-win_amd64 - spec: cp310-win_amd64 - spec: cp311-win_amd64 - - spec: cp27-win32 - cibw_version: cibuildwheel==1.10 # last release with proper py2.7 Windows support - - spec: cp36-win32 - - spec: cp37-win32 + - spec: cp312-win_amd64 - spec: cp38-win32 - spec: cp39-win32 - spec: cp310-win32 - spec: cp311-win32 + - spec: cp312-win32 + steps: - name: clone repo - uses: actions/checkout@v2 - - # HACK: MS killed this SDK support package and removed downloads, as did chocolatey, install from a private archive - - name: install Windows Python 2.7 SDK - run: | - $msiPath = Join-Path ([IO.Path]::GetTempPath()) 'VCForPython27.msi' - [Net.WebClient]::new().DownloadFile('https://raw.githubusercontent.com/nitzmahone/VCPython27/master/VCForPython27.msi', $msiPath) - Start-Process -FilePath msiexec.exe -Wait -ArgumentList @( - '/i', - $msiPath, - '/qn', - '/norestart' - ) - shell: powershell - if: ${{ contains(matrix.spec, 'cp27') }} - + uses: actions/checkout@v4 - name: build/test wheels env: CIBW_BUILD: ${{ matrix.spec }} CIBW_PRERELEASE_PYTHONS: 'True' + CIBW_TEST_REQUIRES: pytest setuptools + CIBW_TEST_COMMAND: 'python -m pytest {project}/c' + # FIXME: /testing takes ~45min on Windows and has some failures... + # CIBW_TEST_COMMAND='python -m pytest {project}/c {project}/testing' run: | python -m pip install --upgrade pip pip install "${{ matrix.cibw_version || 'cibuildwheel'}}" - # FIXME: /testing takes ~45min on Windows and has some failures... - # CIBW_TEST_REQUIRES=pytest CIBW_TEST_COMMAND='python -m pytest {project}/c {project}/testing' cibuildwheel --output-dir dist . - CIBW_TEST_REQUIRES=pytest CIBW_TEST_COMMAND='python -m pytest {project}/c' cibuildwheel --output-dir dist . + python -m cibuildwheel --output-dir dist . shell: bash - name: upload artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: path: dist if-no-files-found: error diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..052e8b6f --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +build/ +/dist/ +*.py[cod] +__pycache__/ +*.egg-info/ +*.so diff --git a/c/test_c.py b/c/test_c.py index 5fd670b9..e846d2f0 100644 --- a/c/test_c.py +++ b/c/test_c.py @@ -75,6 +75,8 @@ def find_and_load_library(name, flags=RTLD_NOW): path = None else: path = ctypes.util.find_library(name) + if path is None and sys.platform == 'darwin' and sys.version_info[:2] == (3, 8): + pytest.xfail("find_library usually broken on MacOS Python 3.8") if path is None and name == 'c': assert sys.platform == 'win32' assert (sys.version_info >= (3,) or diff --git a/cffi/_shimmed_dist_utils/__init__.py b/cffi/_shimmed_dist_utils/__init__.py new file mode 100644 index 00000000..611bf40f --- /dev/null +++ b/cffi/_shimmed_dist_utils/__init__.py @@ -0,0 +1,41 @@ +""" +Temporary shim module to indirect the bits of distutils we need from setuptools/distutils while providing useful +error messages beyond `No module named 'distutils' on Python >= 3.12, or when setuptools' vendored distutils is broken. + +This is a compromise to avoid a hard-dep on setuptools for Python >= 3.12, since many users don't need runtime compilation support from CFFI. +""" +import sys + +try: + # import setuptools first; this is the most robust way to ensure its embedded distutils is available + # (the .pth shim should usually work, but this is even more robust) + import setuptools +except Exception as ex: + if sys.version_info >= (3, 12): + # Python 3.12 has no built-in distutils to fall back on, so any import problem is fatal + raise Exception("This CFFI feature requires setuptools on Python >= 3.12. The setuptools module is missing or non-functional.") from ex + + # silently ignore on older Pythons (support fallback to stdlib distutils where available) +else: + del setuptools + +try: + # bring in just the bits of distutils we need, whether they really came from setuptools or stdlib-embedded distutils + from distutils import log, sysconfig + from distutils.ccompiler import CCompiler + from distutils.command.build_ext import build_ext + from distutils.core import Distribution, Extension + from distutils.dir_util import mkpath + from distutils.errors import DistutilsSetupError, CompileError, LinkError + from distutils.log import set_threshold, set_verbosity + + if sys.platform == 'win32': + from distutils.msvc9compiler import MSVCCompiler +except Exception as ex: + if sys.version_info >= (3, 12): + raise Exception("This CFFI feature requires setuptools on Python >= 3.12. Please install the setuptools package.") from ex + + # anything older, just let the underlying distutils import error fly + raise Exception("This CFFI feature requires distutils. Please install the distutils or setuptools package.") from ex + +del sys diff --git a/cffi/api.py b/cffi/api.py index 999a8aef..edeb7928 100644 --- a/cffi/api.py +++ b/cffi/api.py @@ -622,7 +622,7 @@ def ensure(key, value): try: import sysconfig except ImportError: # 2.6 - from distutils import sysconfig + from cffi._shimmed_dist_utils import sysconfig template = "python%d.%d" if sysconfig.get_config_var('DEBUG_EXT'): template += sysconfig.get_config_var('DEBUG_EXT') @@ -658,7 +658,7 @@ def set_source_pkgconfig(self, module_name, pkgconfig_libs, source, self.set_source(module_name, source, source_extension, **kwds) def distutils_extension(self, tmpdir='build', verbose=True): - from distutils.dir_util import mkpath + from cffi._shimmed_dist_utils import mkpath from .recompiler import recompile # if not hasattr(self, '_assigned_source'): diff --git a/cffi/ffiplatform.py b/cffi/ffiplatform.py index 85313460..adca28f1 100644 --- a/cffi/ffiplatform.py +++ b/cffi/ffiplatform.py @@ -6,8 +6,7 @@ 'extra_objects', 'depends'] def get_extension(srcfilename, modname, sources=(), **kwds): - _hack_at_distutils() - from distutils.core import Extension + from cffi._shimmed_dist_utils import Extension allsources = [srcfilename] for src in sources: allsources.append(os.path.normpath(src)) @@ -16,7 +15,6 @@ def get_extension(srcfilename, modname, sources=(), **kwds): def compile(tmpdir, ext, compiler_verbose=0, debug=None): """Compile a C extension module using distutils.""" - _hack_at_distutils() saved_environ = os.environ.copy() try: outputfilename = _build(tmpdir, ext, compiler_verbose, debug) @@ -31,9 +29,8 @@ def compile(tmpdir, ext, compiler_verbose=0, debug=None): def _build(tmpdir, ext, compiler_verbose=0, debug=None): # XXX compact but horrible :-( - from distutils.core import Distribution - import distutils.errors, distutils.log - # + from cffi._shimmed_dist_utils import Distribution, CompileError, LinkError, set_threshold, set_verbosity + dist = Distribution({'ext_modules': [ext]}) dist.parse_config_files() options = dist.get_option_dict('build_ext') @@ -45,16 +42,15 @@ def _build(tmpdir, ext, compiler_verbose=0, debug=None): options['build_temp'] = ('ffiplatform', tmpdir) # try: - old_level = distutils.log.set_threshold(0) or 0 + old_level = set_threshold(0) or 0 try: - distutils.log.set_verbosity(compiler_verbose) + set_verbosity(compiler_verbose) dist.run_command('build_ext') cmd_obj = dist.get_command_obj('build_ext') [soname] = cmd_obj.get_outputs() finally: - distutils.log.set_threshold(old_level) - except (distutils.errors.CompileError, - distutils.errors.LinkError) as e: + set_threshold(old_level) + except (CompileError, LinkError) as e: raise VerificationError('%s: %s' % (e.__class__.__name__, e)) # return soname @@ -115,13 +111,3 @@ def flatten(x): f = cStringIO.StringIO() _flatten(x, f) return f.getvalue() - -def _hack_at_distutils(): - # Windows-only workaround for some configurations: see - # https://bugs.python.org/issue23246 (Python 2.7 with - # a specific MS compiler suite download) - if sys.platform == "win32": - try: - import setuptools # for side-effects, patches distutils - except ImportError: - pass diff --git a/cffi/recompiler.py b/cffi/recompiler.py index 5d9d32d7..4167bc05 100644 --- a/cffi/recompiler.py +++ b/cffi/recompiler.py @@ -1483,13 +1483,13 @@ def _unpatch_meths(patchlist): def _patch_for_embedding(patchlist): if sys.platform == 'win32': # we must not remove the manifest when building for embedding! - from distutils.msvc9compiler import MSVCCompiler + from cffi._shimmed_dist_utils import MSVCCompiler _patch_meth(patchlist, MSVCCompiler, '_remove_visual_c_ref', lambda self, manifest_file: manifest_file) if sys.platform == 'darwin': # we must not make a '-bundle', but a '-dynamiclib' instead - from distutils.ccompiler import CCompiler + from cffi._shimmed_dist_utils import CCompiler def my_link_shared_object(self, *args, **kwds): if '-bundle' in self.linker_so: self.linker_so = list(self.linker_so) @@ -1501,7 +1501,7 @@ def my_link_shared_object(self, *args, **kwds): my_link_shared_object) def _patch_for_target(patchlist, target): - from distutils.command.build_ext import build_ext + from cffi._shimmed_dist_utils import build_ext # if 'target' is different from '*', we need to patch some internal # method to just return this 'target' value, instead of having it # built from module_name diff --git a/cffi/setuptools_ext.py b/cffi/setuptools_ext.py index 8fe36148..681b49d7 100644 --- a/cffi/setuptools_ext.py +++ b/cffi/setuptools_ext.py @@ -8,7 +8,7 @@ basestring = str def error(msg): - from distutils.errors import DistutilsSetupError + from cffi._shimmed_dist_utils import DistutilsSetupError raise DistutilsSetupError(msg) @@ -104,11 +104,9 @@ def _set_py_limited_api(Extension, kwds): return kwds def _add_c_module(dist, ffi, module_name, source, source_extension, kwds): - from distutils.core import Extension # We are a setuptools extension. Need this build_ext for py_limited_api. from setuptools.command.build_ext import build_ext - from distutils.dir_util import mkpath - from distutils import log + from cffi._shimmed_dist_utils import Extension, log, mkpath from cffi import recompiler allsources = ['$PLACEHOLDER'] @@ -150,10 +148,9 @@ def run(self): def _add_py_module(dist, ffi, module_name): - from distutils.dir_util import mkpath from setuptools.command.build_py import build_py from setuptools.command.build_ext import build_ext - from distutils import log + from cffi._shimmed_dist_utils import log, mkpath from cffi import recompiler def generate_mod(py_file): diff --git a/cffi/verifier.py b/cffi/verifier.py index a500c781..e392a2b7 100644 --- a/cffi/verifier.py +++ b/cffi/verifier.py @@ -117,7 +117,6 @@ def get_module_name(self): return basename def get_extension(self): - ffiplatform._hack_at_distutils() # backward compatibility hack if not self._has_source: with self.ffi._lock: if not self._has_source: diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..3db8907f --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,7 @@ +[build-system] +requires = [ + # first version that supports Python 3.12; older versions may work + # with previous Python versions, but are not tested + "setuptools >= 66.1" +] +build-backend = "setuptools.build_meta" diff --git a/setup.py b/setup.py index 71f9b089..ff783403 100644 --- a/setup.py +++ b/setup.py @@ -2,9 +2,9 @@ import subprocess import errno -# on Windows we give up and always import setuptools early to fix things for us -if sys.platform == "win32": - import setuptools +# the setuptools distutils shim should make distutils available, but this will definitely do +# it, since setuptools is now required at build-time +import setuptools sources = ['c/_cffi_backend.c'] @@ -65,8 +65,6 @@ def no_working_compiler_found(): no_compiler_found = True def get_config(): - if sys.version_info >= (3, 12): - import setuptools # makes 'distutils' available from distutils.core import Distribution from distutils.sysconfig import get_config_vars get_config_vars() # workaround for a bug of distutils, e.g. on OS/X @@ -180,14 +178,7 @@ def has_ext_modules(self): install_requires = [] if cpython: - if sys.version_info >= (2, 7): - install_requires.append('pycparser') - else: - install_requires.append('pycparser<2.19') - if sys.version_info >= (3, 12): - # this is to get the 'distutils' module. - # see https://foss.heptapod.net/pypy/cffi/-/issues/564 - install_requires.append('setuptools') + install_requires.append('pycparser') setup( name='cffi', @@ -205,6 +196,7 @@ def has_ext_modules(self): `Mailing list `_ """, version='1.15.1', + python_requires='>=3.8', packages=['cffi'] if cpython else [], package_data={'cffi': ['_cffi_include.h', 'parse_c_type.h', '_embedding.h', '_cffi_errors.h']} @@ -240,15 +232,12 @@ def has_ext_modules(self): classifiers=[ 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'License :: OSI Approved :: MIT License', diff --git a/testing/cffi0/test_verify.py b/testing/cffi0/test_verify.py index 31fcc6dd..ad7a04e3 100644 --- a/testing/cffi0/test_verify.py +++ b/testing/cffi0/test_verify.py @@ -5,6 +5,11 @@ from testing.support import * from testing.support import extra_compile_args, is_musl +# eliminate warning noise from common test modules that are repeatedly re-imported +pytestmark = [ + pytest.mark.filterwarnings("ignore:reimporting:UserWarning"), + #pytest.mark.filterwarnings("ignore:Deprecated:_DeprecatedConfig") +] lib_m = ['m'] if sys.platform == 'win32': @@ -85,6 +90,8 @@ def test_simple_case(): def _Wconversion(cdef, source, **kargs): if sys.platform in ('win32', 'darwin'): pytest.skip("needs GCC") + if '-Wno-error=sign-conversion' in extra_compile_args: + pytest.skip("gcc 9.2.0 compiler bug exposed by Python 3.12+ prevents compilation with sign-conversion warnings-as-errors") ffi = FFI() ffi.cdef(cdef) pytest.raises(VerificationError, ffi.verify, source, **kargs) diff --git a/testing/cffi0/test_verify2.py b/testing/cffi0/test_verify2.py index a4af6d66..25f1e3f5 100644 --- a/testing/cffi0/test_verify2.py +++ b/testing/cffi0/test_verify2.py @@ -1,5 +1,9 @@ +import pytest from .test_verify import * +# eliminate warning noise from common test modules that are repeatedly re-imported +pytestmark = pytest.mark.filterwarnings("ignore:reimporting:UserWarning") + # This test file runs normally after test_verify. We only clean up the .c # sources, to check that it also works when we have only the .so. The # tests should run much faster than test_verify. diff --git a/testing/cffi0/test_zintegration.py b/testing/cffi0/test_zintegration.py index ca2d4642..9fbbd91c 100644 --- a/testing/cffi0/test_zintegration.py +++ b/testing/cffi0/test_zintegration.py @@ -14,11 +14,28 @@ def create_venv(name): tmpdir = udir.join(name) try: + # FUTURE: we should probably update this to use venv for at least more modern Pythons, and + # install setuptools/pip/etc explicitly for the tests that require them (as venv has stopped including + # setuptools and wheel by default for newer versions). subprocess.check_call(['virtualenv', #'--never-download', <= could be added, but causes failures # in random cases on random machines '-p', os.path.abspath(sys.executable), str(tmpdir)]) + + # Python 3.12 venv/virtualenv no longer include setuptools and wheel by default, which + # breaks a number of these tests; ensure it's always present for 3.12+ + if sys.version_info >= (3, 12): + subprocess.check_call([ + os.path.join(tmpdir, 'bin/python'), + '-m', + 'pip', + 'install', + 'setuptools', + 'wheel', + '--upgrade' + ]) + except OSError as e: pytest.skip("Cannot execute virtualenv: %s" % (e,)) diff --git a/testing/cffi1/test_verify1.py b/testing/cffi1/test_verify1.py index f1a5fa14..cea15f2b 100644 --- a/testing/cffi1/test_verify1.py +++ b/testing/cffi1/test_verify1.py @@ -64,6 +64,8 @@ def test_simple_case(): def _Wconversion(cdef, source, **kargs): if sys.platform in ('win32', 'darwin'): pytest.skip("needs GCC") + if '-Wno-error=sign-conversion' in extra_compile_args: + pytest.skip("gcc 9.2.0 compiler bug exposed by Python 3.12+ prevents compilation with sign-conversion warnings-as-errors") ffi = FFI() ffi.cdef(cdef) pytest.raises(VerificationError, ffi.verify, source, **kargs) diff --git a/testing/cffi1/test_zdist.py b/testing/cffi1/test_zdist.py index b1013da1..9003f65d 100644 --- a/testing/cffi1/test_zdist.py +++ b/testing/cffi1/test_zdist.py @@ -289,13 +289,7 @@ def _make_distutils_api(self): with open("setup.py", "w") as f: f.write("""if 1: # https://bugs.python.org/issue23246 - import sys - if sys.platform == 'win32' or sys.version_info >= (3, 12): - try: - import setuptools - except ImportError: - pass - + import setuptools import cffi ffi = cffi.FFI() ffi.set_source("pack1.mymod", "/*code would be here*/") diff --git a/testing/conftest.py b/testing/conftest.py new file mode 100644 index 00000000..d02e127a --- /dev/null +++ b/testing/conftest.py @@ -0,0 +1,19 @@ +import pytest +import sys + +from ctypes import util + +# this problem was supposedly fixed in a newer Python 3.8 release, but after binary installer support expired +# https://github.com/python/cpython/pull/28054 +if sys.platform == 'darwin' and sys.version_info[:2] == (3, 8): + orig_find_library = util.find_library + + def hacked_find_library(*args, **kwargs): + res = orig_find_library(*args, **kwargs) + + if res is None: + pytest.xfail("busted find_library on MacOS Python 3.8") + + return res + + util.find_library = hacked_find_library diff --git a/testing/support.py b/testing/support.py index 666c351b..063e52cf 100644 --- a/testing/support.py +++ b/testing/support.py @@ -122,7 +122,16 @@ def typeof_disabled(*args, **kwds): if sys.platform == 'linux': try: from packaging.tags import platform_tags - is_musl = any(t.startswith('musllinux') for t in platform_tags()) - del platform_tags except ImportError: pass + else: + tagset = frozenset(platform_tags()) + is_musl = any(t.startswith('musllinux') for t in tagset) + if is_musl and sys.version_info >= (3, 12): + if any(t.startswith('musllinux_1_1_') for t in tagset) and not any(t.startswith('musllinux_1_2_') for t in tagset): + # gcc 9.2.0 in the musllinux_1_1 build container has a bug in its sign-conversion warning detection that + # bombs on the definition of _PyLong_CompactValue under Python 3.12; disable warnings-as-errors for that + # specific error on musl 1.1 + extra_compile_args.append('-Wno-error=sign-conversion') + + del platform_tags