From cc77ffbd59c236be516e145484cb8bdc7400e889 Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 23 Oct 2026 00:11:12 -0700 Subject: [PATCH 1/2] Upgrade cibuildwheel to v4.3.3 and test wheels on Python 3.15 cibuildwheel v2.16.5 predates Python 3.15 and can't build or test on it. Upgrade to v4.3.3 and add cp315 to CIBW_BUILD. The wheel is abi3, so it is still built only once, on cp39; cibuildwheel reuses it for cp315 and only runs the tests there. Side effects of going from v2 to v4, from cibuildwheel's changelog: - Linux wheels are built on manylinux_2_28 instead of manylinux2014, so they need glibc 2.28 or newer. CentOS 7 and Amazon Linux 2 users would fall back to the sdist or the pure-Python wheel. Setting CIBW_MANYLINUX_{X86_64,AARCH64}_IMAGE to manylinux2014 keeps the old baseline. - Each abi3 wheel is checked with abi3audit after repair, and a failure fails the build. - Windows wheels are repaired with delvewheel, which bundles any DLLs the extension links against. - Wheels are built with `build` instead of `pip wheel`, in environments without setuptools and wheel preinstalled. Both come from pyproject.toml's build-system.requires instead. --- .github/workflows/publish.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 447f0796c..46ee2a421 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -116,13 +116,17 @@ jobs: platforms: all - name: Build and test wheels - uses: pypa/cibuildwheel@v2.16.5 + uses: pypa/cibuildwheel@v4.3.3 env: # configure cibuildwheel to build native archs ('auto'), and some # emulated ones CIBW_ARCHS_LINUX: "auto aarch64" CIBW_ARCHS_MACOS: "universal2" - CIBW_BUILD: "cp39-*" + # The wheel is abi3, so it is built once on cp39. cibuildwheel skips + # the build for cp315 because the abi3 wheel already covers it, and + # only reruns the tests there, so the oldest and newest supported + # interpreters both load the extension. + CIBW_BUILD: "cp39-* cp315-*" CIBW_SKIP: "pp* *-musllinux* *-manylinux_i686" CIBW_TEST_COMMAND: "pytest -v --pyargs singlestoredb.tests.test_basics" # xdist because pyproject.toml's addopts sets -n/--dist, and PYTHONPATH From b35194664b79decbcf68fc1ecbf41856513f7a98 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 29 Oct 2026 00:54:39 -0700 Subject: [PATCH 2/2] Make _PyUnicode_AsUTF8 static and pin manylinux2014 images abi3audit, which cibuildwheel v4 runs on abi3 wheels, rejected the extension because the non-static helper exported a _Py* symbol. cibuildwheel v3+ defaults to manylinux_2_28; pin manylinux2014 to keep the glibc 2.17 baseline so older distros still get the C extension. --- .github/workflows/publish.yml | 6 ++++++ accel.c | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 46ee2a421..26fe992bc 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -128,6 +128,12 @@ jobs: # interpreters both load the extension. CIBW_BUILD: "cp39-* cp315-*" CIBW_SKIP: "pp* *-musllinux* *-manylinux_i686" + # cibuildwheel v3+ builds on manylinux_2_28 (glibc 2.28) by default. + # Pin manylinux2014 (glibc 2.17) so CentOS/RHEL 7, Amazon Linux 2 and + # Ubuntu 18.04 still get the C extension instead of falling back to + # the pure-Python wheel without any warning. + CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014 + CIBW_MANYLINUX_AARCH64_IMAGE: manylinux2014 CIBW_TEST_COMMAND: "pytest -v --pyargs singlestoredb.tests.test_basics" # xdist because pyproject.toml's addopts sets -n/--dist, and PYTHONPATH # points --pyargs at the workspace, so that pyproject is the inifile diff --git a/accel.c b/accel.c index 075276287..dd53bd619 100644 --- a/accel.c +++ b/accel.c @@ -371,7 +371,7 @@ static PyObject *create_numpy_array(PyObject *py_memview, char *data_format, int // Returns a newly allocated UTF-8 copy of `unicode`; the caller owns it // and must free() it. -char *_PyUnicode_AsUTF8(PyObject *unicode) { +static char *_PyUnicode_AsUTF8(PyObject *unicode) { PyObject *bytes = PyUnicode_AsEncodedString(unicode, "utf-8", "strict"); if (!bytes) return NULL;