Skip to content

Regenerate Cython outputs with 3.2.4 for CPython 3.14 support#69

Draft
yokofly wants to merge 6 commits intodevelopfrom
yokofly/cp314t-cython-3.2
Draft

Regenerate Cython outputs with 3.2.4 for CPython 3.14 support#69
yokofly wants to merge 6 commits intodevelopfrom
yokofly/cp314t-cython-3.2

Conversation

@yokofly
Copy link
Copy Markdown

@yokofly yokofly commented Apr 14, 2026

CPython 3.14 changed the signature of _PyLong_AsByteArray (added an endianness argument). The .c files checked into this repo were generated with Cython 3.0.11 and no longer compile against 3.14 headers:

bufferedreader.c:15818: error: too few arguments to function
'_PyLong_AsByteArray'

Regenerating the .pyx -> .c outputs with Cython 3.2.4 emits code that handles the new signature. No .pyx changes, no runtime behavior change for Python <= 3.13.

Free-threaded (cp314t) compatibility: the resulting extensions build and import on cp314t, but the runtime auto-re-enables the GIL for each .so because the modules do not yet declare Py_MOD_GIL_NOT_USED. That's a separate audit + opt-in change; functionality is preserved.

Verified locally:
python3.14t -m pip wheel . --no-deps # builds
python3.14t -c "import proton_driver; ..." # imports, functional

yokofly and others added 6 commits April 14, 2026 02:01
CPython 3.14 changed the signature of _PyLong_AsByteArray (added an
endianness argument). The .c files checked into this repo were generated
with Cython 3.0.11 and no longer compile against 3.14 headers:

  bufferedreader.c:15818: error: too few arguments to function
  '_PyLong_AsByteArray'

Regenerating the .pyx -> .c outputs with Cython 3.2.4 emits code that
handles the new signature. No .pyx changes, no runtime behavior change
for Python <= 3.13.

Free-threaded (cp314t) compatibility: the resulting extensions build
and import on cp314t, but the runtime auto-re-enables the GIL for each
.so because the modules do not yet declare Py_MOD_GIL_NOT_USED. That's
a separate audit + opt-in change; functionality is preserved.

Verified locally:
  python3.14t -m pip wheel . --no-deps  # builds
  python3.14t -c "import proton_driver; ..."  # imports, functional

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cython 3.1+ default-emits a compressed module string table that's
decompressed at import time via `zlib` / `bz2` / `compression.zstd`.
On minimal/embedded CPython builds that omit those stdlib modules,
the regenerated extensions now fail to import — a regression
relative to the pre-Cython-3.2 checked-in C.

The generated C keeps an uncompressed `#else /* compression: none */`
fallback guarded by the C macro CYTHON_COMPRESS_STRINGS (default 1).
Pass -DCYTHON_COMPRESS_STRINGS=0 via each Extension's define_macros
so the fallback branch is selected and no compression module is
imported. Verified on CPython 3.12 by artificially blocking zlib/bz2/
compression.zstd before import: all four extensions load cleanly and
no blocked module leaks into sys.modules.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Bump pypa/cibuildwheel from v2.21.3 to v3.4.1. v2.21.3 predates
  Python 3.14 support; v3.x adds cp314 across macOS/Windows/manylinux/
  musllinux and cp314t on every Tier-1 platform, so without this pin
  the release job silently skipped 3.14 and would never produce
  free-threaded wheels.
- Bump runner images (ubuntu-20.04 → ubuntu-22.04, windows-2019 →
  windows-2022, macos-12 → macos-13). ubuntu-20.04 and macos-12 are
  retired on GitHub Actions and would refuse to schedule.
- Upgrade actions/upload-artifact and actions/download-artifact from
  v3 (deprecated) to v4. v4 needs unique artifact names per matrix
  job, so uploads are now scoped by matrix.os and the publish job
  merges them via pattern + merge-multiple.
- Add a cibuildwheel test-command that installs each built wheel into
  a fresh env and imports every compiled extension. Catches runtime
  ABI or stdlib-dependency regressions at release time instead of on
  user machines (the recent Cython 3.2 zlib/bz2/zstd import-time
  dependency would have been caught here).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- test.yml: add "3.14" to the main driver test matrix.
- test.yml: add a dedicated smoke-ft job that builds the Cython
  extensions under free-threaded 3.14 (setup-python "3.14t") and
  asserts every compiled extension imports. The full driver test
  matrix is not run under 3.14t on purpose: the generated module
  init still emits Py_MOD_GIL_USED, so a real FT run would just
  prove the driver falls back to GIL mode. Running a real
  free-threading audit is out of scope for this PR; the smoke job
  is there to lock in "still importable" and catch regressions
  from future Cython regens.
- README.rst: include 3.14 (+ note 3.14t) in the supported list.
- setup.py: add the 3.14 trove classifier.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The earlier smoke checks only did plain imports on runners that already
ship zlib / bz2 / compression.zstd / lzma, so a future regression to
Cython's default compressed string tables (CYTHON_COMPRESS_STRINGS != 0
in setup.py) would have slipped through silently.

Move the actual invariant check into tests/smoke_no_compression.py:
install a sys.meta_path finder that raises ImportError for the four
stdlib compression modules, then import proton_driver and every
compiled extension. Verified locally to round-trip:

  - setup.py CYTHON_COMPRESS_STRINGS=1 (the reviewer-flagged
    regression): smoke rc=1, error "Failed to import 'zlib.decompress'
    - cannot initialise module strings. String compression was
    configured with the C macro 'CYTHON_COMPRESS_STRINGS=1'."
  - setup.py CYTHON_COMPRESS_STRINGS=0 (current): smoke rc=0,
    "proton_driver imports cleanly on Python 3.x with {zlib, bz2,
    compression.zstd, lzma} blocked".

Wire it into both invocation paths:
  - pyproject.toml test-command runs the script on every built wheel
    inside cibuildwheel, against the freshly-installed wheel in a
    clean env.
  - .github/workflows/test.yml smoke-ft job installs the driver into
    site-packages (pip install .) under free-threaded 3.14t and runs
    the same script, so the resolution is unambiguous regardless of
    cwd.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The previous wording read "3.14 (including the free-threaded 3.14t
build)", which implies the driver runs without the GIL on 3.14t. It
doesn't — the generated module init still calls
PyUnstable_Module_SetGIL(..., Py_MOD_GIL_USED), so importing the
driver into a Py_GIL_DISABLED interpreter flips that interpreter back
to GIL-enabled at import time.

Describe the posture accurately: extensions build and import cleanly
on cp314t; the driver re-enables the GIL; a real Py_MOD_GIL_NOT_USED
audit is a separate track.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant