diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 55cc1b1b..4a27735a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -72,25 +72,26 @@ jobs: matrix_yaml: | include: # x86_64 manylinux - - { spec: cp39-manylinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp310-manylinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp311-manylinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp312-manylinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp313-manylinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp314-manylinux_x86_64, arch: x86_64 } - - { spec: cp314t-manylinux_x86_64, arch: x86_64 } + - { spec: cp314-manylinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp314t-manylinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp315-manylinux_x86_64, arch: x86_64 } + - { spec: cp315t-manylinux_x86_64, arch: x86_64 } # x86_64 musllinux - - { spec: cp39-musllinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp310-musllinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp311-musllinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp312-musllinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp313-musllinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp314-musllinux_x86_64, arch: x86_64 } - - { spec: cp314t-musllinux_x86_64, arch: x86_64 } + - { spec: cp314-musllinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp314t-musllinux_x86_64, arch: x86_64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp315-musllinux_x86_64, arch: x86_64 } + - { spec: cp315t-musllinux_x86_64, arch: x86_64 } # i686 manylinux - - { spec: cp39-manylinux_i686, arch: i686, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp310-manylinux_i686, arch: i686, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp311-manylinux_i686, arch: i686, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp312-manylinux_i686, arch: i686, omit: ${{ env.skip_ci_redundant_jobs }} } @@ -98,46 +99,49 @@ jobs: # omit i686 releases > 3.13 # i686 musllinux - - { spec: cp39-musllinux_i686, arch: i686, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp310-musllinux_i686, arch: i686, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp311-musllinux_i686, arch: i686 } # omit i686 releases after 3.11 # aarch64 manylinux - - { spec: cp39-manylinux_aarch64, arch: aarch64 } - { spec: cp310-manylinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp311-manylinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp312-manylinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp313-manylinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp314-manylinux_aarch64, arch: aarch64 } - - { spec: cp314t-manylinux_aarch64, arch: aarch64 } + - { spec: cp314-manylinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp314t-manylinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp315-manylinux_aarch64, arch: aarch64 } + - { spec: cp315t-manylinux_aarch64, arch: aarch64 } # aarch64 musllinux - - { spec: cp39-musllinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp310-musllinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp311-musllinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp312-musllinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp313-musllinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp314-musllinux_aarch64, arch: aarch64 } - - { spec: cp314t-musllinux_aarch64, arch: aarch64 } + - { spec: cp314-musllinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp314t-musllinux_aarch64, arch: aarch64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp315-musllinux_aarch64, arch: aarch64 } + - { spec: cp315t-musllinux_aarch64, arch: aarch64 } # ppc64le manylinux - - { spec: cp39-manylinux_ppc64le, arch: ppc64le, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs }} } - - { spec: cp310-manylinux_ppc64le, arch: ppc64le, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } + - { spec: cp310-manylinux_ppc64le, arch: ppc64le, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs }} } - { spec: cp311-manylinux_ppc64le, arch: ppc64le, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } - { spec: cp312-manylinux_ppc64le, arch: ppc64le, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } - { spec: cp313-manylinux_ppc64le, arch: ppc64le, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } - - { spec: cp314-manylinux_ppc64le, arch: ppc64le, omit: ${{ env.skip_slow_jobs }} } - - { spec: cp314t-manylinux_ppc64le, arch: ppc64le, omit: ${{ env.skip_slow_jobs }} } + - { spec: cp314-manylinux_ppc64le, arch: ppc64le, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } + - { spec: cp314t-manylinux_ppc64le, arch: ppc64le, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } + - { spec: cp315-manylinux_ppc64le, arch: ppc64le, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs }} } + - { spec: cp315t-manylinux_ppc64le, arch: ppc64le, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs }} } # s390x manylinux - - { spec: cp39-manylinux_s390x, arch: s390x, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs }} } - - { spec: cp310-manylinux_s390x, arch: s390x, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } + - { spec: cp310-manylinux_s390x, arch: s390x, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs }} } - { spec: cp311-manylinux_s390x, arch: s390x, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } - { spec: cp312-manylinux_s390x, arch: s390x, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } - { spec: cp313-manylinux_s390x, arch: s390x, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } - - { spec: cp314-manylinux_s390x, arch: s390x, omit: ${{ env.skip_slow_jobs }} } - - { spec: cp314t-manylinux_s390x, arch: s390x, omit: ${{ env.skip_slow_jobs }} } + - { spec: cp314-manylinux_s390x, arch: s390x, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } + - { spec: cp314t-manylinux_s390x, arch: s390x, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs || env.skip_ci_redundant_jobs }} } + - { spec: cp315-manylinux_s390x, arch: s390x, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs }} } + - { spec: cp315t-manylinux_s390x, arch: s390x, test_args: '{package}/src/c', omit: ${{ env.skip_slow_jobs }} } linux: needs: [python_sdist, make_linux_matrix] @@ -163,6 +167,7 @@ jobs: CFLAGS: -Dffi_call=cffistatic_ffi_call # override name for ffi_call to break hard if we linked against someone else's libffi CIBW_ARCHS_LINUX: all CIBW_BUILD: ${{ matrix.spec }} + CIBW_ENABLE: cpython-prerelease CIBW_BEFORE_BUILD: | set -eux && \ curl -L -O https://github.com/libffi/libffi/archive/v3.4.6.tar.gz && \ @@ -218,22 +223,24 @@ jobs: matrix_yaml: | include: # x86_64 macos - - { spec: cp39-macosx_x86_64, runs_on: [macos-15-intel], omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp310-macosx_x86_64, runs_on: [macos-15-intel], omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp311-macosx_x86_64, runs_on: [macos-15-intel], omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp312-macosx_x86_64, runs_on: [macos-15-intel], omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp313-macosx_x86_64, runs_on: [macos-15-intel], omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp314-macosx_x86_64, runs_on: [macos-15-intel] } - - { spec: cp314t-macosx_x86_64, runs_on: [macos-15-intel] } + - { spec: cp314-macosx_x86_64, runs_on: [macos-15-intel], omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp314t-macosx_x86_64, runs_on: [macos-15-intel], omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp315-macosx_x86_64, runs_on: [macos-15-intel] } + - { spec: cp315t-macosx_x86_64, runs_on: [macos-15-intel] } # arm64 macos - - { spec: cp39-macosx_arm64, deployment_target: '11.0', run_wrapper: 'arch -arm64 bash --noprofile --norc -eo pipefail {0}', omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp310-macosx_arm64, deployment_target: '11.0', run_wrapper: 'arch -arm64 bash --noprofile --norc -eo pipefail {0}', omit: ${{ env.skip_ci_redundant_jobs}} } + - { spec: cp310-macosx_arm64, deployment_target: '11.0', run_wrapper: 'arch -arm64 bash --noprofile --norc -eo pipefail {0}', omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp311-macosx_arm64, deployment_target: '11.0', run_wrapper: 'arch -arm64 bash --noprofile --norc -eo pipefail {0}', omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp312-macosx_arm64, deployment_target: '11.0', run_wrapper: 'arch -arm64 bash --noprofile --norc -eo pipefail {0}', omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp313-macosx_arm64, deployment_target: '11.0', run_wrapper: 'arch -arm64 bash --noprofile --norc -eo pipefail {0}', omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp314-macosx_arm64, deployment_target: '11.0', run_wrapper: 'arch -arm64 bash --noprofile --norc -eo pipefail {0}' } - - { spec: cp314t-macosx_arm64, deployment_target: '11.0', run_wrapper: 'arch -arm64 bash --noprofile --norc -eo pipefail {0}' } + - { spec: cp314-macosx_arm64, deployment_target: '11.0', run_wrapper: 'arch -arm64 bash --noprofile --norc -eo pipefail {0}', omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp314t-macosx_arm64, deployment_target: '11.0', run_wrapper: 'arch -arm64 bash --noprofile --norc -eo pipefail {0}', omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp315-macosx_arm64, deployment_target: '11.0', run_wrapper: 'arch -arm64 bash --noprofile --norc -eo pipefail {0}' } + - { spec: cp315t-macosx_arm64, deployment_target: '11.0', run_wrapper: 'arch -arm64 bash --noprofile --norc -eo pipefail {0}' } macos: needs: [python_sdist, make_macos_matrix] @@ -268,6 +275,7 @@ jobs: id: build env: CIBW_BUILD: ${{ matrix.spec }} + CIBW_ENABLE: cpython-prerelease CIBW_TEST_REQUIRES: pytest setuptools CIBW_TEST_COMMAND: pip install pip --upgrade; cd {project}; PYTHONUNBUFFERED=1 pytest MACOSX_DEPLOYMENT_TARGET: ${{ matrix.deployment_target || '10.13' }} @@ -309,8 +317,10 @@ jobs: - { spec: cp311-win_amd64, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp312-win_amd64, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp313-win_amd64, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp314-win_amd64 } - - { spec: cp314t-win_amd64 } + - { spec: cp314-win_amd64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp314t-win_amd64, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp315-win_amd64 } + - { spec: cp315t-win_amd64 } # x86 windows - { spec: cp39-win32, omit: ${{ env.skip_ci_redundant_jobs }} } @@ -318,15 +328,19 @@ jobs: - { spec: cp311-win32, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp312-win32, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp313-win32, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp314-win32 } - - { spec: cp314t-win32 } + - { spec: cp314-win32, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp314t-win32, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp315-win32 } + - { spec: cp315t-win32 } # arm64 windows - { spec: cp311-win_arm64, runs_on: windows-11-arm, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp312-win_arm64, runs_on: windows-11-arm, omit: ${{ env.skip_ci_redundant_jobs }} } - { spec: cp313-win_arm64, runs_on: windows-11-arm, omit: ${{ env.skip_ci_redundant_jobs }} } - - { spec: cp314-win_arm64, runs_on: windows-11-arm } - - { spec: cp314t-win_arm64, runs_on: windows-11-arm } + - { spec: cp314-win_arm64, runs_on: windows-11-arm, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp314t-win_arm64, runs_on: windows-11-arm, omit: ${{ env.skip_ci_redundant_jobs }} } + - { spec: cp315-win_arm64, runs_on: windows-11-arm } + - { spec: cp315t-win_arm64, runs_on: windows-11-arm } windows: needs: [python_sdist, make_windows_matrix] @@ -351,6 +365,7 @@ jobs: id: build env: CIBW_BUILD: ${{ matrix.spec }} + CIBW_ENABLE: cpython-prerelease CIBW_TEST_REQUIRES: pytest setuptools CIBW_TEST_COMMAND: ${{ matrix.test_cmd || 'python -m pytest {package}/src/c' }} # FIXME: /testing takes ~45min on Windows and has some failures... @@ -393,10 +408,12 @@ jobs: # arm64 iOS device - { spec: cp313-ios_arm64_iphoneos, platform: 'iphoneos' } - { spec: cp314-ios_arm64_iphoneos, platform: 'iphoneos' } + - { spec: cp315-ios_arm64_iphoneos, platform: 'iphoneos' } # arm64 iOS simulator - { spec: cp313-ios_arm64_iphonesimulator, platform: 'iphonesimulator' } - { spec: cp314-ios_arm64_iphonesimulator, platform: 'iphonesimulator' } + - { spec: cp315-ios_arm64_iphonesimulator, platform: 'iphonesimulator' } ios: needs: [python_sdist, make_ios_matrix] @@ -504,9 +521,9 @@ jobs: with: matrix_yaml: | include: - - { runner: ubuntu-24.04, python-version: 3.14t } - - { runner: macos-26, python-version: 3.14t } - - { runner: windows-2025, python-version: 3.14t } + - { runner: ubuntu-24.04, python-version: 3.15t-dev } + - { runner: macos-26, python-version: 3.15t-dev } + - { runner: windows-2025, python-version: 3.15t-dev } pytest-run-parallel: needs: make_run_parallel_matrix @@ -536,7 +553,7 @@ jobs: clang_TSAN: runs-on: ubuntu-24.04 - container: ghcr.io/nascheme/numpy-tsan:3.14t + container: ghcr.io/nascheme/numpy-tsan:3.15t-dev steps: - uses: actions/checkout@v4 diff --git a/src/cffi/_cffi_include.h b/src/cffi/_cffi_include.h index c7186307..c8c6d343 100644 --- a/src/cffi/_cffi_include.h +++ b/src/cffi/_cffi_include.h @@ -28,8 +28,13 @@ #if !defined(_CFFI_USE_EMBEDDING) && !defined(Py_LIMITED_API) # ifdef _MSC_VER # if !defined(_DEBUG) && !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API) -# define Py_LIMITED_API +# if !defined(Py_GIL_DISABLED) +# define Py_LIMITED_API +# else +# define Py_LIMITED_API 0x030f0000 +# endif # endif + # include /* sanity-check: Py_LIMITED_API will cause crashes if any of these are also defined. Normally, the Python file PC/pyconfig.h does not @@ -49,7 +54,11 @@ # else # include # if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API) -# define Py_LIMITED_API +# if !defined(Py_GIL_DISABLED) +# define Py_LIMITED_API +# else +# define Py_LIMITED_API 0x030f0000 +# endif # endif # endif #endif diff --git a/src/cffi/recompiler.py b/src/cffi/recompiler.py index 83ee5c7d..6f2debe5 100644 --- a/src/cffi/recompiler.py +++ b/src/cffi/recompiler.py @@ -9,7 +9,7 @@ USE_LIMITED_API = ((sys.platform != 'win32' or sys.version_info < (3, 0) or sys.version_info >= (3, 5)) and - not sysconfig.get_config_var("Py_GIL_DISABLED")) # free-threaded doesn't yet support limited API + (not sysconfig.get_config_var("Py_GIL_DISABLED") or sys.version_info >= (3, 15))) # free-threaded doesn't yet support limited API class GlobalExpr: def __init__(self, name, address, type_op, size=0, check_value=0): diff --git a/src/cffi/setuptools_ext.py b/src/cffi/setuptools_ext.py index 5cdd246f..946afb45 100644 --- a/src/cffi/setuptools_ext.py +++ b/src/cffi/setuptools_ext.py @@ -105,10 +105,12 @@ def _set_py_limited_api(Extension, kwds): kwds['py_limited_api'] = True if sysconfig.get_config_var("Py_GIL_DISABLED"): - if kwds.get('py_limited_api'): - log.info("Ignoring py_limited_api=True for free-threaded build.") - - kwds['py_limited_api'] = False + if sys.version_info < (3, 15): + if kwds.get('py_limited_api'): + log.info("Ignoring py_limited_api=True for free-threaded build.") + kwds['py_limited_api'] = False + else: + kwds.setdefault("define_macros", []).append(("Py_TARGET_ABI3T", "0x030f0000")) if kwds.get('py_limited_api') is False: # avoid setting Py_LIMITED_API if py_limited_api=False diff --git a/testing/cffi0/test_zintegration.py b/testing/cffi0/test_zintegration.py index 69c3d01f..20436913 100644 --- a/testing/cffi0/test_zintegration.py +++ b/testing/cffi0/test_zintegration.py @@ -181,7 +181,10 @@ def test_set_py_limited_api(self): pytest.skip(str(e)) orig_version = setuptools.__version__ # free-threaded Python does not yet support limited API - expecting_limited_api = not hasattr(sys, 'gettotalrefcount') and not sysconfig.get_config_var("Py_GIL_DISABLED") + expecting_limited_api = ( + not hasattr(sys, 'gettotalrefcount') and not + (sysconfig.get_config_var("Py_GIL_DISABLED") and sys.version_info < (3, 15)) + ) try: setuptools.__version__ = '26.0.0' from setuptools import Extension diff --git a/testing/cffi1/test_verify1.py b/testing/cffi1/test_verify1.py index 479b164a..9483d913 100644 --- a/testing/cffi1/test_verify1.py +++ b/testing/cffi1/test_verify1.py @@ -781,6 +781,7 @@ def test_get_set_errno(): ffi = FFI() ffi.cdef("int foo(int);") lib = ffi.verify(""" + #include static int foo(int x) { errno += 1;