Skip to content

Commit 0dc7805

Browse files
committed
prepare for 1.16.0rc1
* add support for python 3.12 * mask reimport warning noise in tests * fix/skip/xfail tests broken by Python 3.12 * xfail broken Python 3.8 tests broken by newer macOS releases * drop support for EOL Pythons (< 3.8) * declare python_requires metadata for 3.8+ (allows unsupported Pythons to continue using previous sdist/wheel releases indefinitely) * fix musllinux 1.1 tests * add boilerplate pyproject.toml for basic PEP517 build support * add explicit build-time dependency on setuptools * shim runtime setuptools/distutils imports to provide more prescriptive error messages when missing or broken * update CI configurations * add .gitignore to prepare for move to GitHub
1 parent d146646 commit 0dc7805

18 files changed

+209
-114
lines changed

.github/workflows/ci.yaml

+71-55
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ jobs:
55
runs-on: ubuntu-20.04
66
steps:
77
- name: clone repo
8-
uses: actions/checkout@v2
8+
uses: actions/checkout@v4
99

1010
- name: build sdist
1111
run: |
@@ -14,48 +14,55 @@ jobs:
1414
python -m build --sdist
1515
1616
- name: upload sdist artifact
17-
uses: actions/upload-artifact@v2
17+
uses: actions/upload-artifact@v3
1818
with:
1919
path: dist
2020
if-no-files-found: error
2121

2222
linux:
2323
runs-on: ubuntu-20.04
2424
strategy:
25+
fail-fast: false
2526
matrix:
2627
include:
27-
- spec: cp27-manylinux_x86_64
28-
cibw_version: cibuildwheel<2.0 # py2.7 is not supported on CIBW 2.0+
29-
manylinux_img: manylinux1 # build really old Pythons on manylinux1
30-
- spec: cp36-manylinux_x86_64
31-
manylinux_img: manylinux1 # build really old Pythons on manylinux1
32-
- spec: cp37-manylinux_x86_64
3328
- spec: cp38-manylinux_x86_64
3429
- spec: cp39-manylinux_x86_64
3530
- spec: cp310-manylinux_x86_64
3631
- spec: cp311-manylinux_x86_64
37-
- spec: cp27-manylinux_i686
38-
cibw_version: cibuildwheel<2.0 # py2.7 is not supported on CIBW 2.0+
39-
manylinux_img: manylinux1 # build really old Pythons on manylinux1
40-
- spec: cp36-manylinux_i686
41-
manylinux_img: manylinux1 # build really old Pythons on manylinux1
42-
- spec: cp37-manylinux_i686
32+
- spec: cp312-manylinux_x86_64
33+
4334
- spec: cp38-manylinux_i686
4435
- spec: cp39-manylinux_i686
4536
- spec: cp310-manylinux_i686
4637
- spec: cp311-manylinux_i686
38+
- spec: cp312-manylinux_i686
39+
4740
- spec: cp39-musllinux_x86_64
4841
- spec: cp310-musllinux_x86_64
4942
- spec: cp311-musllinux_x86_64
43+
- spec: cp312-musllinux_x86_64
44+
5045
- spec: cp39-musllinux_i686
5146
- spec: cp310-musllinux_i686
5247
- spec: cp311-musllinux_i686
53-
- spec: cp36-manylinux_ppc64le
48+
#- spec: cp312-musllinux_i686 # busted as of 9/22/23
49+
50+
- spec: cp38-manylinux_aarch64
51+
foreign_arch: true
52+
test_args: '{project}/c'
53+
- spec: cp39-manylinux_aarch64
54+
foreign_arch: true
55+
test_args: '{project}/c'
56+
- spec: cp310-manylinux_aarch64
57+
foreign_arch: true
58+
test_args: '{project}/c'
59+
- spec: cp311-manylinux_aarch64
5460
foreign_arch: true
5561
test_args: '{project}/c'
56-
- spec: cp37-manylinux_ppc64le
62+
- spec: cp312-manylinux_aarch64
5763
foreign_arch: true
5864
test_args: '{project}/c'
65+
5966
- spec: cp38-manylinux_ppc64le
6067
foreign_arch: true
6168
test_args: '{project}/c'
@@ -68,9 +75,29 @@ jobs:
6875
- spec: cp311-manylinux_ppc64le
6976
foreign_arch: true
7077
test_args: '{project}/c'
78+
- spec: cp312-manylinux_ppc64le
79+
foreign_arch: true
80+
test_args: '{project}/c'
81+
82+
- spec: cp38-manylinux_s390x
83+
foreign_arch: true
84+
test_args: '{project}/c'
85+
- spec: cp39-manylinux_s390x
86+
foreign_arch: true
87+
test_args: '{project}/c'
88+
- spec: cp310-manylinux_s390x
89+
foreign_arch: true
90+
test_args: '{project}/c'
91+
- spec: cp311-manylinux_s390x
92+
foreign_arch: true
93+
test_args: '{project}/c'
94+
- spec: cp312-manylinux_s390x
95+
foreign_arch: true
96+
test_args: '{project}/c'
97+
7198
steps:
7299
- name: clone repo
73-
uses: actions/checkout@v2
100+
uses: actions/checkout@v4
74101

75102
- name: configure docker foreign arch support
76103
uses: docker/setup-qemu-action@v1
@@ -94,7 +121,7 @@ jobs:
94121
CIBW_MANYLINUX_X86_64_IMAGE: ${{ matrix.manylinux_img || '' }}
95122
CIBW_MANYLINUX_I686_IMAGE: ${{ matrix.manylinux_img || '' }}
96123
CIBW_PRERELEASE_PYTHONS: 'True'
97-
CIBW_TEST_REQUIRES: pytest
124+
CIBW_TEST_REQUIRES: pytest setuptools # 3.12+ no longer includes distutils, just always ensure setuptools is present
98125
CIBW_TEST_COMMAND: PYTHONUNBUFFERED=1 python -m pytest ${{ matrix.test_args || '{project}' }} # default to test all
99126
run: |
100127
python -m pip install --upgrade "${{ matrix.cibw_version || 'cibuildwheel' }}"
@@ -104,7 +131,7 @@ jobs:
104131
105132
106133
- name: upload artifacts
107-
uses: actions/upload-artifact@v2
134+
uses: actions/upload-artifact@v3
108135
with:
109136
path: dist
110137
if-no-files-found: error
@@ -114,21 +141,19 @@ jobs:
114141
defaults:
115142
run:
116143
shell: ${{ matrix.run_wrapper || 'bash --noprofile --norc -eo pipefail {0}' }}
117-
runs-on: ${{ matrix.runs_on || 'macos-10.15' }}
144+
runs-on: ${{ matrix.runs_on || 'macos-11' }}
118145
strategy:
146+
fail-fast: false
119147
matrix:
120148
include:
121149
# build for x86_64 under the default hosted macOS 10.x x86_64 runner
122-
- spec: cp27-macosx_x86_64
123-
cibw_version: cibuildwheel<2.0 # py2.7 is not supported on CIBW 2.0+
124-
- spec: cp36-macosx_x86_64
125-
- spec: cp37-macosx_x86_64
126150
- spec: cp38-macosx_x86_64
127151
- spec: cp39-macosx_x86_64
128152
- spec: cp310-macosx_x86_64
129153
- spec: cp311-macosx_x86_64
130-
# build for arm64 under a hacked macOS 12 self-hosted x86_64-on-arm64 runner until arm64 is fully supported
131-
# 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)
154+
- spec: cp312-macosx_x86_64
155+
# # build for arm64 under a hacked macOS 12 self-hosted x86_64-on-arm64 runner until arm64 is fully supported
156+
# # 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)
132157
- spec: cp39-macosx_arm64
133158
deployment_target: '11.0'
134159
runs_on: [self-hosted, macOS]
@@ -147,9 +172,16 @@ jobs:
147172
run_wrapper: arch -arm64 bash --noprofile --norc -eo pipefail {0}
148173
sdkroot: macosx11.3
149174

175+
- spec: cp312-macosx_arm64
176+
deployment_target: '11.0'
177+
runs_on: [self-hosted, macOS]
178+
run_wrapper: arch -arm64 bash --noprofile --norc -eo pipefail {0}
179+
sdkroot: macosx11.3
180+
150181

151182
steps:
152183
- name: clone repo
184+
# need to use v2 until we can upgrade the runners on our private Apple Silicon build infra to one that supports node20
153185
uses: actions/checkout@v2
154186

155187
- name: build wheel prereqs
@@ -161,7 +193,7 @@ jobs:
161193
env:
162194
CIBW_BUILD: ${{ matrix.spec }}
163195
CIBW_PRERELEASE_PYTHONS: 'True'
164-
CIBW_TEST_REQUIRES: pytest
196+
CIBW_TEST_REQUIRES: pytest setuptools
165197
CIBW_TEST_COMMAND: pip install pip --upgrade; cd {project}; PYTHONUNBUFFERED=1 pytest
166198
run: |
167199
if [[ -n "${{ matrix.deployment_target || '' }}" ]]
@@ -177,6 +209,7 @@ jobs:
177209
/usr/bin/python3 -m cibuildwheel --output-dir dist
178210
179211
- name: upload artifacts
212+
# need to use v2 until we can upgrade the runners on our private Apple Silicon build infra to one that supports node20
180213
uses: actions/upload-artifact@v2
181214
with:
182215
path: dist
@@ -185,56 +218,39 @@ jobs:
185218
windows:
186219
runs-on: windows-2019
187220
strategy:
221+
fail-fast: false
188222
matrix:
189223
include:
190-
- spec: cp27-win_amd64
191-
cibw_version: cibuildwheel==1.10 # last release with proper py2.7 Windows support
192-
- spec: cp36-win_amd64
193-
- spec: cp37-win_amd64
194224
- spec: cp38-win_amd64
195225
- spec: cp39-win_amd64
196226
- spec: cp310-win_amd64
197227
- spec: cp311-win_amd64
198-
- spec: cp27-win32
199-
cibw_version: cibuildwheel==1.10 # last release with proper py2.7 Windows support
200-
- spec: cp36-win32
201-
- spec: cp37-win32
228+
- spec: cp312-win_amd64
202229
- spec: cp38-win32
203230
- spec: cp39-win32
204231
- spec: cp310-win32
205232
- spec: cp311-win32
233+
- spec: cp312-win32
234+
206235
steps:
207236
- name: clone repo
208-
uses: actions/checkout@v2
209-
210-
# HACK: MS killed this SDK support package and removed downloads, as did chocolatey, install from a private archive
211-
- name: install Windows Python 2.7 SDK
212-
run: |
213-
$msiPath = Join-Path ([IO.Path]::GetTempPath()) 'VCForPython27.msi'
214-
[Net.WebClient]::new().DownloadFile('https://raw.githubusercontent.com/nitzmahone/VCPython27/master/VCForPython27.msi', $msiPath)
215-
Start-Process -FilePath msiexec.exe -Wait -ArgumentList @(
216-
'/i',
217-
$msiPath,
218-
'/qn',
219-
'/norestart'
220-
)
221-
shell: powershell
222-
if: ${{ contains(matrix.spec, 'cp27') }}
223-
237+
uses: actions/checkout@v4
224238
- name: build/test wheels
225239
env:
226240
CIBW_BUILD: ${{ matrix.spec }}
227241
CIBW_PRERELEASE_PYTHONS: 'True'
242+
CIBW_TEST_REQUIRES: pytest setuptools
243+
CIBW_TEST_COMMAND: 'python -m pytest {project}/c'
244+
# FIXME: /testing takes ~45min on Windows and has some failures...
245+
# CIBW_TEST_COMMAND='python -m pytest {project}/c {project}/testing'
228246
run: |
229247
python -m pip install --upgrade pip
230248
pip install "${{ matrix.cibw_version || 'cibuildwheel'}}"
231-
# FIXME: /testing takes ~45min on Windows and has some failures...
232-
# CIBW_TEST_REQUIRES=pytest CIBW_TEST_COMMAND='python -m pytest {project}/c {project}/testing' cibuildwheel --output-dir dist .
233-
CIBW_TEST_REQUIRES=pytest CIBW_TEST_COMMAND='python -m pytest {project}/c' cibuildwheel --output-dir dist .
249+
python -m cibuildwheel --output-dir dist .
234250
shell: bash
235251

236252
- name: upload artifacts
237-
uses: actions/upload-artifact@v2
253+
uses: actions/upload-artifact@v3
238254
with:
239255
path: dist
240256
if-no-files-found: error

.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
build/
2+
/dist/
3+
*.py[cod]
4+
__pycache__/
5+
*.egg-info/
6+
*.so

c/test_c.py

+2
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ def find_and_load_library(name, flags=RTLD_NOW):
7575
path = None
7676
else:
7777
path = ctypes.util.find_library(name)
78+
if path is None and sys.platform == 'darwin' and sys.version_info[:2] == (3, 8):
79+
pytest.xfail("find_library usually broken on MacOS Python 3.8")
7880
if path is None and name == 'c':
7981
assert sys.platform == 'win32'
8082
assert (sys.version_info >= (3,) or

cffi/_shimmed_dist_utils/__init__.py

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
"""
2+
Temporary shim module to indirect the bits of distutils we need from setuptools/distutils while providing useful
3+
error messages beyond `No module named 'distutils' on Python >= 3.12, or when setuptools' vendored distutils is broken.
4+
5+
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.
6+
"""
7+
import sys
8+
9+
try:
10+
# import setuptools first; this is the most robust way to ensure its embedded distutils is available
11+
# (the .pth shim should usually work, but this is even more robust)
12+
import setuptools
13+
except Exception as ex:
14+
if sys.version_info >= (3, 12):
15+
# Python 3.12 has no built-in distutils to fall back on, so any import problem is fatal
16+
raise Exception("This CFFI feature requires setuptools on Python >= 3.12. The setuptools module is missing or non-functional.") from ex
17+
18+
# silently ignore on older Pythons (support fallback to stdlib distutils where available)
19+
else:
20+
del setuptools
21+
22+
try:
23+
# bring in just the bits of distutils we need, whether they really came from setuptools or stdlib-embedded distutils
24+
from distutils import log, sysconfig
25+
from distutils.ccompiler import CCompiler
26+
from distutils.command.build_ext import build_ext
27+
from distutils.core import Distribution, Extension
28+
from distutils.dir_util import mkpath
29+
from distutils.errors import DistutilsSetupError, CompileError, LinkError
30+
from distutils.log import set_threshold, set_verbosity
31+
32+
if sys.platform == 'win32':
33+
from distutils.msvc9compiler import MSVCCompiler
34+
except Exception as ex:
35+
if sys.version_info >= (3, 12):
36+
raise Exception("This CFFI feature requires setuptools on Python >= 3.12. Please install the setuptools package.") from ex
37+
38+
# anything older, just let the underlying distutils import error fly
39+
raise Exception("This CFFI feature requires distutils. Please install the distutils or setuptools package.") from ex
40+
41+
del sys

cffi/api.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -622,7 +622,7 @@ def ensure(key, value):
622622
try:
623623
import sysconfig
624624
except ImportError: # 2.6
625-
from distutils import sysconfig
625+
from cffi._shimmed_dist_utils import sysconfig
626626
template = "python%d.%d"
627627
if sysconfig.get_config_var('DEBUG_EXT'):
628628
template += sysconfig.get_config_var('DEBUG_EXT')
@@ -658,7 +658,7 @@ def set_source_pkgconfig(self, module_name, pkgconfig_libs, source,
658658
self.set_source(module_name, source, source_extension, **kwds)
659659

660660
def distutils_extension(self, tmpdir='build', verbose=True):
661-
from distutils.dir_util import mkpath
661+
from cffi._shimmed_dist_utils import mkpath
662662
from .recompiler import recompile
663663
#
664664
if not hasattr(self, '_assigned_source'):

cffi/ffiplatform.py

+7-21
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66
'extra_objects', 'depends']
77

88
def get_extension(srcfilename, modname, sources=(), **kwds):
9-
_hack_at_distutils()
10-
from distutils.core import Extension
9+
from cffi._shimmed_dist_utils import Extension
1110
allsources = [srcfilename]
1211
for src in sources:
1312
allsources.append(os.path.normpath(src))
@@ -16,7 +15,6 @@ def get_extension(srcfilename, modname, sources=(), **kwds):
1615
def compile(tmpdir, ext, compiler_verbose=0, debug=None):
1716
"""Compile a C extension module using distutils."""
1817

19-
_hack_at_distutils()
2018
saved_environ = os.environ.copy()
2119
try:
2220
outputfilename = _build(tmpdir, ext, compiler_verbose, debug)
@@ -31,9 +29,8 @@ def compile(tmpdir, ext, compiler_verbose=0, debug=None):
3129

3230
def _build(tmpdir, ext, compiler_verbose=0, debug=None):
3331
# XXX compact but horrible :-(
34-
from distutils.core import Distribution
35-
import distutils.errors, distutils.log
36-
#
32+
from cffi._shimmed_dist_utils import Distribution, CompileError, LinkError, set_threshold, set_verbosity
33+
3734
dist = Distribution({'ext_modules': [ext]})
3835
dist.parse_config_files()
3936
options = dist.get_option_dict('build_ext')
@@ -45,16 +42,15 @@ def _build(tmpdir, ext, compiler_verbose=0, debug=None):
4542
options['build_temp'] = ('ffiplatform', tmpdir)
4643
#
4744
try:
48-
old_level = distutils.log.set_threshold(0) or 0
45+
old_level = set_threshold(0) or 0
4946
try:
50-
distutils.log.set_verbosity(compiler_verbose)
47+
set_verbosity(compiler_verbose)
5148
dist.run_command('build_ext')
5249
cmd_obj = dist.get_command_obj('build_ext')
5350
[soname] = cmd_obj.get_outputs()
5451
finally:
55-
distutils.log.set_threshold(old_level)
56-
except (distutils.errors.CompileError,
57-
distutils.errors.LinkError) as e:
52+
set_threshold(old_level)
53+
except (CompileError, LinkError) as e:
5854
raise VerificationError('%s: %s' % (e.__class__.__name__, e))
5955
#
6056
return soname
@@ -115,13 +111,3 @@ def flatten(x):
115111
f = cStringIO.StringIO()
116112
_flatten(x, f)
117113
return f.getvalue()
118-
119-
def _hack_at_distutils():
120-
# Windows-only workaround for some configurations: see
121-
# https://bugs.python.org/issue23246 (Python 2.7 with
122-
# a specific MS compiler suite download)
123-
if sys.platform == "win32":
124-
try:
125-
import setuptools # for side-effects, patches distutils
126-
except ImportError:
127-
pass

0 commit comments

Comments
 (0)