Repository navigation
Conversation
Dev-iL
marked this pull request as draft
November 5, 2026 04:54
Regular CPython builds compile against the Python 3.11 Limited API and produce one cp311-abi3 wheel. Unbounded output grows in PyMem storage and is copied once into its final bytes object; a first allocation that equals a finite output limit is returned directly. Free-threaded CPython and PyPy keep the full API, version-specific wheels and bytes resizing; PyPy keeps its static types. Factory types are owned by module state. Codec state uses libc malloc/free only where the 3.11 ABI lacks PyMem_RawMalloc. Decoding and encoding loops stop at the end of the stream instead of growing the output once more. CI builds and audits the abi3 wheel on Linux, macOS (Intel and ARM) and Windows (x64 and arm64), tests that same wheel on 3.11-3.15, audits the released abi3 wheels, and keeps the existing per-version jobs. benchmark_scripts/benchmark_abi3.py compares installed wheels and regenerates the report summaries from raw results. Fixed on the way (present before this change): - PyArg_Parse* failures in crc32_combine, _ParallelCompress, _GzipReader.seek and read raised SystemError instead of TypeError. - _GzipReader and _ParallelCompress were named after isal_zlib. - _ZlibDecompressor dropped unconsumed input when the output limit was reached during an input chunk over 4 GiB. - _ZlibDecompressor raised SystemError for streams with a preset dictionary instead of applying zdict or raising zlib_ng.error. - _GzipReader turned errors from the read attribute lookup into TypeError. - Module initialization ignored failures, leaked the module and the gzip module reference. - Py_UNREACHABLE was redefined on PyPy; the sanitizer job, the license entry and gzip_ng.open's docstring named python-isal/ISA-L files; cibuildwheel skipped stale cp38-cp310 patterns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dev-iL
force-pushed
the
2611/stable-abi
branch
from
November 5, 2026 06:38
6488941 to
f018acc
Compare
Dev-iL
marked this pull request as ready for review
November 5, 2026 06:39
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Regular CPython releases currently require new version-specific wheels. This change builds
cp311-abi3wheels while retaining version-specific full-API wheels for free-threaded CPython and PyPy. It addresses #95, parallels pycompression/python-isal#240, and follows the Python 3.11 floor/native-buffer guidance in pycompression/xopen#182 (comment).Growing codec output uses native allocation/reallocation followed by a final bytes copy. CPython types use heap specifications and public accessors. The two factory types are owned by module state with traverse/clear hooks. Allocation, reference replacement and failure cleanup preserve the original ownership rules. Metadata now matches the already documented 3.11 support floor.
Benchmarks
Nine randomized paired rounds, 128 cases, original and final installed wheels, baseline-again controls, CPython 3.11.15, GCC 15.2 and identical pinned zlib-ng 2.3.3. Linux x86_64/i7-3770 without AVX2, CPU 1 pinned. Four corpora and four sizes include irregular output lengths. Ratios are candidate CPU time / original CPU time; above 1 is slower. Control absolute p95 is 2.88%, maximum 5.31%.
The worst tested cases are
zeros/1048713/raw-decompress2.810x;zeros/1048713/decompress2.296x;zeros/1048713/stream-decompress2.265x. The copy/allocation cost remains material for unbounded decoding. Compression, checksums and ordinary gzip chunk reads generally stay near baseline; small differences within the control range are inconclusive. These results do not promise universal parity.Full methodology, case results, raw runs and reproduction are committed. The JSON/CSV preserve CPU and wall timings, iteration counts, input hashes and interpreter/extension paths. Build metadata records source, wheel and native-archive hashes. Results are from one Linux host, with other platforms covered by CI configuration rather than local measurements.
Relationship to the maintainer's design
PyBytes_FromStringAndSize, and explicit measurement of the cost.readintowrites to the caller's buffer.Py_GIL_DISABLEDmacro. Further free-threaded performance work belongs in a follow-up.PyMem_RawMalloc/RawFreeonly entered the Stable ABI in 3.13;PyMem_Mallocis inappropriate in those callbacks. Attached output-buffer paths still use PyMem allocation/reallocation. Native callback memory may be absent from tracemalloc.PyObject_Newwith pairedPyObject_Free, avoiding unnecessary zeroing of large structures. Factory type references use module state; existing process-global exception behavior remains. This does not claim new per-interpreter module isolation.Earlier attempts and considered approaches
Alternative buffer strategies: benchmarks and reasons for ruling them out
These are separate prototype experiments, rather than the final installed-wheel comparison above. Nine randomized paired rounds compare each strategy with a full-API baseline containing the same EOF-stop correction. The table summarizes 24 large irregular-output decode cases: four corpora, two sizes (1 MiB + 137 and 16 MiB + 137), and three decoder APIs. Ratios are paired CPU time divided by baseline time; above 1 means slower. Ranges are across case medians, not confidence intervals. Across the full 72-case strategy study, baseline-again control variation has an inclusive p95 of 8.20% and a maximum of 8.74%.
BytesIObacking storageBytesIOcreated on the first growthBytesIO: a 1.373x median does not recover the native-buffer cost. Python calls, writable buffer exports and factory ownership add work and state.BytesIO: promotion on first growth reduces some eager-creation overhead, but the 1.368x median remains worse than native buffers and individual cases reach 1.921x. It was not adopted as a general replacement.The selected implementation follows the native-buffer/final-copy design for growing output and retains a direct bytes path for filled finite allocations. Free-threaded CPython/PyPy keep their full-API bytes-resize path. Per-case strategy summary and the full benchmark report retain the evidence. These prototype ratios should not be compared directly with the final-wheel table above.
Validation
The actual final wheels pass 14,588 tests plus 18 subtests on system CPython 3.14 (3 skips), 14,450 tests on free-threaded 3.13 with the GIL disabled (1 skip; two stdlib compliance files unavailable), and 14,576 tests plus 18 subtests on PyPy 3.11 (15 skips). The identical ABI3 wheel passes the new ownership/boundary tests on CPython 3.11–3.15. Strict
abi3auditpasses. New tests preserve type lifetimes, copying, immutable/factory-only types, output boundaries, failed initialization and default-GIL import behavior. Full flake8/mypy, strict Sphinx, YAML/embedded Python/link checks, wheel/sdist builds and twine checks pass; the committed report records the core build and validation evidence.CI builds/audits one 3.11 ABI3 wheel per Linux/macOS Intel/macOS ARM/Windows platform and tests that same wheel on 3.11–3.15. Windows 3.14t exercises its build macro. Existing sanitizer jobs remain. Missing optional stdlib compliance modules are detected explicitly. Remote CI, non-Linux execution and ASan/TSan remain to be verified; local timings do not cover those platforms.
Checklist