Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
6488941
Build stable ABI wheels for CPython 3.11 and newer
Dev-iL Nov 4, 2026
e68acd7
Pin the direct return of filled bounded output
Dev-iL Nov 5, 2026
c820004
Raise argument errors from crc32_combine, seek and read
Dev-iL Nov 5, 2026
a7dca65
Name _GzipReader and _ParallelCompress after zlib_ng
Dev-iL Nov 5, 2026
0bb3996
Drop trailing whitespace from the renamed issue URL
Dev-iL Nov 5, 2026
d94cb5c
Keep unconsumed input when _ZlibDecompressor hits its output limit
Dev-iL Nov 5, 2026
1954f7d
Propagate errors from _GzipReader's read attribute lookup
Dev-iL Nov 5, 2026
7c540b9
Report every module initialization failure
Dev-iL Nov 5, 2026
e692065
Keep PyPy's own Py_UNREACHABLE
Dev-iL Nov 5, 2026
9e2dc69
Use the raw Python allocator for codec state outside the 3.11 ABI
Dev-iL Nov 5, 2026
d7b8e06
Restore the _ParallelCompress docstring on heap types
Dev-iL Nov 5, 2026
1ddd4bf
Sweep allocation failures through the output paths
Dev-iL Nov 5, 2026
f51b727
Test factory type ownership and _GzipReader.readinto
Dev-iL Nov 5, 2026
515070b
Test that a stream ending at a full buffer stops growing
Dev-iL Nov 5, 2026
758e880
Name zlib-ng's license file as it is spelled
Dev-iL Nov 5, 2026
e2ccb50
Name zlib-ng in the sanitizer job
Dev-iL Nov 5, 2026
cd6aedb
Drop stale wheel skips and test the stable ABI in cibuildwheel
Dev-iL Nov 5, 2026
cdf4f03
Restore the regular CPython test-static jobs
Dev-iL Nov 5, 2026
a557497
Test the Windows arm64 stable ABI wheel on every version
Dev-iL Nov 5, 2026
7c5af43
Audit the released stable ABI wheels before upload
Dev-iL Nov 5, 2026
ae43c23
Type the deliberately wrong arguments in the parsing test
Dev-iL Nov 5, 2026
fe93d66
Rerun module initialization without the import system's locks
Dev-iL Nov 5, 2026
1fc3f80
Regenerate benchmark report summaries from raw results
Dev-iL Nov 5, 2026
f603f0c
Apply or request the preset dictionary in _ZlibDecompressor
Dev-iL Nov 5, 2026
925524a
Name zlib-ng in gzip_ng.open's docstring
Dev-iL Nov 5, 2026
6d05653
Refresh stable ABI benchmark evidence for the repaired candidate
Dev-iL Nov 5, 2026
80c3fdb
Update the stable ABI report, changelog and docs for the repaired can…
Dev-iL Nov 5, 2026
99b8c49
Keep input when a preset dictionary meets a zero output limit
Dev-iL Nov 5, 2026
8f6408f
Keep unread input beyond 4 GiB in decompressobj()
Dev-iL Nov 5, 2026
22cc3ad
Check that failed and invalid decodes release their output
Dev-iL Nov 5, 2026
936ab8f
Reject read-only buffers in _GzipReader.readinto()
Dev-iL Nov 5, 2026
85fb4a0
Re-time the stable ABI benchmark on the final candidate
Dev-iL Nov 5, 2026
9d43df2
Update the stable ABI report and changelog for the final candidate
Dev-iL Nov 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 91 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,80 @@ jobs:
- name: Run tox -e ${{ matrix.tox_env }}
run: tox -e ${{ matrix.tox_env }}

build-abi3-test-wheel:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: ["ubuntu-latest", "macos-15-intel", "macos-latest", "windows-latest",
"windows-11-arm"]
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v7
with:
submodules: recursive
fetch-depth: 0
- uses: actions/setup-python@v7
with:
python-version: "3.11"
- name: Install build dependencies (macOS)
if: runner.os == 'macOS'
run: brew install make
- uses: ilammy/msvc-dev-cmd@v1
if: runner.os == 'Windows'
with:
arch: ${{ matrix.os == 'windows-11-arm' && 'arm64' || 'x64' }}
- name: Build and audit the stable ABI wheel
run: |
python -m pip install build abi3audit
python -m build --wheel --outdir wheelhouse
python -m abi3audit --strict wheelhouse/*-cp311-abi3-*.whl
- uses: actions/upload-artifact@v4
with:
name: abi3-test-${{ matrix.os }}
path: wheelhouse/*.whl

test-abi3-wheel:
needs: build-abi3-test-wheel
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: ["ubuntu-latest", "macos-15-intel", "macos-latest", "windows-latest",
"windows-11-arm"]
python-version: ["3.11", "3.12", "3.13", "3.14", "3.15"]
defaults:
run:
shell: bash
env:
PYTHONDEVMODE: "1"
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
- uses: actions/download-artifact@v4
with:
name: abi3-test-${{ matrix.os }}
path: wheelhouse
- name: Install the same wheel on each Python version
run: |
python -m pip install pytest pytest-timeout
python -m pip install --no-index --find-links wheelhouse zlib-ng
- name: Run the tests available in this interpreter
run: |
python - <<'PYTEST'
import importlib.util
import subprocess
import sys
command = [sys.executable, "-m", "pytest", "tests"]
if importlib.util.find_spec("test") is None:
command += ["--ignore=tests/test_zlib_compliance.py",
"--ignore=tests/test_gzip_compliance.py"]
raise SystemExit(subprocess.call(command))
PYTEST

test-static:
runs-on: ${{ matrix.os }}
strategy:
Expand All @@ -70,6 +144,8 @@ jobs:
python-version: "3.11"
- os: "windows-latest"
python-version: "3.11"
- os: "windows-latest"
python-version: "3.14t"
- os: "windows-11-arm"
python-version: "3.11"
steps:
Expand Down Expand Up @@ -179,15 +255,15 @@ jobs:
submodules: recursive
- name: Install build dependencies
run: apt-get update && apt-get install -y cmake
- name: Install python-isal with ${{ matrix.sanitizer }} sanitizer
- name: Install python-zlib-ng with ${{ matrix.sanitizer }} sanitizer
# setuptools-scm needs git, and the container user does not own the
# repository.
run: |
git config --global --add safe.directory "$GITHUB_WORKSPACE"
python -m pip install . pytest pytest-timeout
env:
# The extension modules get -fsanitize from CPython. CFLAGS adds it
# to the C code of ISA-L.
# to the C code of zlib-ng.
CFLAGS: -fsanitize=${{ matrix.sanitizer }} -fno-omit-frame-pointer -g
- name: Run tests
# Do not set PYTHONDEVMODE. Its debug allocator pads each allocation,
Expand All @@ -205,6 +281,7 @@ jobs:
- lint
- package-checks
- test-static
- test-abi3-wheel
- test-dynamic
- test-arch
- test-sanitizers
Expand All @@ -231,6 +308,7 @@ jobs:
- lint
- package-checks
- test-static
- test-abi3-wheel
- test-dynamic
- test-arch
- test-sanitizers
Expand Down Expand Up @@ -273,24 +351,27 @@ jobs:
run: cibuildwheel --output-dir dist
env:
CIBW_ENABLE: "pypy"
# Skip 32 bit, macosx_arm64 causes issues on cpython 3.9
CIBW_SKIP: "*-win32 *-manylinux_i686 cp38-macosx_arm64 cp39-win_arm64 cp310-win_arm64"
# Skip 32 bit
CIBW_SKIP: "*-win32 *-manylinux_i686"
CIBW_ARCHS_LINUX: ${{ matrix.cibw_archs_linux }}
CIBW_TEST_REQUIRES: "pytest"
# Simple tests that requires the project to be build correctly
CIBW_TEST_COMMAND_LINUX: >-
pytest {project}/tests/test_zlib_compliance.py
{project}/tests/test_gzip_compliance.py
{project}/tests/test_gzip_ng.py
{project}/tests/test_stable_abi.py
CIBW_TEST_COMMAND_MACOS: >-
pytest {project}/tests/test_zlib_compliance.py
{project}/tests/test_gzip_compliance.py
{project}/tests/test_gzip_ng.py
{project}/tests/test_stable_abi.py
# Windows does not have the test module in the included python.
# Run compatibility tests instead.
CIBW_TEST_COMMAND_WINDOWS: >-
pytest {project}/tests/test_compat.py
{project}/tests/test_gzip_ng.py
{project}/tests/test_stable_abi.py
CIBW_ENVIRONMENT_LINUX: >-
PYTHON_ZLIB_NG_BUILD_CACHE=True
PYTHON_ZLIB_NG_BUILD_CACHE_FILE=/tmp/build_cache
Expand All @@ -302,6 +383,12 @@ jobs:
PYTHON_ZLIB_NG_BUILD_CACHE=True
PYTHON_ZLIB_NG_BUILD_CACHE_FILE=${{ runner.temp }}/build_cache
CFLAGS="-O3 -DNDEBUG"
- name: Audit the stable ABI wheels
# bash expands the wheel glob on Windows too.
shell: bash
run: |
python -m pip install abi3audit
python -m abi3audit --strict dist/*-cp311-abi3-*.whl
- uses: actions/upload-artifact@v7
with:
name: "cibw-${{ runner.os }}-${{ runner.arch }}-${{ matrix.cibw_archs_linux }}"
Expand Down
44 changes: 44 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,50 @@ Changelog
.. This document is user facing. Please word the changes in such a way
.. that users understand how the changes affect the new version.

version 1.1.1-dev
-----------------
+ Regular CPython 3.11 and newer share one stable ABI wheel per platform, so
new CPython releases no longer need new wheels. PyPy and free-threaded
CPython keep their interpreter-specific wheels.
+ On the stable ABI wheels, calls whose output size is not known in advance
copy their result once more and briefly hold that extra copy in memory:
``zlib_ng.compress()``, ``zlib_ng.decompress()``, ``compressobj()`` output,
and ``decompressobj().decompress()`` and ``_ZlibDecompressor.decompress()``
without ``max_length``. In the project's benchmark, decompressing 16 MiB took
up to 19% longer, and the worst case, 1 MiB of zeros, took 2.74 times as
long; compression times did not change measurably. ``gzip_ng`` file reads
avoid the copy, and so does ``_ZlibDecompressor.decompress(data,
max_length)`` when the output fills a ``max_length`` of at most 16 MiB. A
bounded call that returns less than its limit copies the shorter result
while still holding the full allocation. With a larger limit, the copy is
also made by ``_ZlibDecompressor.decompress(data, max_length)`` above 16 MiB
and by ``decompressobj().decompress(data, max_length)`` above 16 KiB, which
briefly holds up to twice ``max_length``. PyPy and free-threaded CPython are
not affected.
+ Compression or decompression whose output ends exactly at the size of its
current output buffer no longer grows that buffer once more before
returning.
+ ``crc32_combine()`` and the internal ``_GzipReader.read()`` and
``_GzipReader.seek()`` raise ``TypeError`` instead of ``SystemError`` for
arguments of the wrong type.
+ ``_ZlibDecompressor`` uses the ``zdict`` it was given for a stream that
needs a preset dictionary, and otherwise raises ``zlib_ng.error``, instead
of raising ``SystemError`` in both cases.
+ ``_ZlibDecompressor.decompress()`` no longer loses input when given more than
4 GiB of data and a ``max_length`` that stops it early; the bytes are kept
for the next call or in ``unused_data``.
+ ``decompressobj().decompress()`` no longer loses unread input beyond the
first 4 GiB of one call when the output limit or the end of the stream is
reached; it is kept in ``unconsumed_tail`` or ``unused_data``.
+ The internal ``_GzipReader.readinto()`` raises ``TypeError`` for a read-only
buffer instead of writing into it, which crashed on a read-only ``mmap``.
+ Reading with ``gzip_ng.open()`` from a file object whose ``read`` attribute
lookup raises an error other than ``AttributeError`` now raises that error
instead of an unrelated ``TypeError``.
+ A failure while importing ``zlib_ng``, such as running out of memory, is
reported as that error instead of ``SystemError`` and no longer leaks the
partially created module.

version 1.1.0
-----------------
+ Python 3.10 and PyPy 3.10 are no longer supported. Added support for PyPy
Expand Down
Loading