From 34c171bc51ce1c7dcb2e1e8cbb79a903afd7bd90 Mon Sep 17 00:00:00 2001 From: Ruben Vorderman Date: Mon, 15 Sep 2025 08:14:04 +0200 Subject: [PATCH 1/3] Fix a spelling and copy paste error. Thanks @ellert --- tests/test_gzip_compliance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_gzip_compliance.py b/tests/test_gzip_compliance.py index 8ad5441..64ea4b7 100644 --- a/tests/test_gzip_compliance.py +++ b/tests/test_gzip_compliance.py @@ -809,7 +809,7 @@ def test_decompress_stdin_stdout(self): # If the env_vars argument to assert_python_failure or assert_python_ok # is empty the test will run in isolated mode (-I) which means that the # PYTHONPATH environment variable will be ignored and the test fails - # because the isal module can not be found, or the test is run usung the + # because the zlib_ng module can not be found, or the test is run using the # system installed version of the module instead of the newly built # module that should be tested. # From 07c7f5f5ce0eee0290bf388bd1bfdd5c6cb30891 Mon Sep 17 00:00:00 2001 From: Finn Womack Date: Wed, 3 Dec 2025 01:48:13 -0800 Subject: [PATCH 2/3] Add windows arm64 wheelbuilding (#73) * add arm64 builds & tests, run workflow * skip cp39 and cp310 on arm64 windows * add v5 python-setup for arm64 windows Updated Python setup action for Windows ARM architecture. * fix typo * print env variables for windows to debug * fix pwsh command before build * run SET * Specify architecture for MSVC developer prompt * add arch option to msvc action * remove SET * uncomment skipped sections, remove fork branch trigger * update CHANGELOG.rst Added version 1.0.1-dev section with a note about Windows arm64 wheel support. --- .github/workflows/ci.yml | 15 +++++++++++++-- CHANGELOG.rst | 4 ++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e2bc13d..e1ce7ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,6 +69,8 @@ jobs: python-version: "3.10" - os: "windows-latest" python-version: "3.10" + - os: "windows-11-arm" + python-version: "3.11" steps: - uses: actions/checkout@v4 with: @@ -83,6 +85,8 @@ jobs: - name: Set MSVC developer prompt uses: ilammy/msvc-dev-cmd@v1 if: runner.os == 'Windows' + with: + arch: ${{ matrix.os == 'windows-11-arm' && 'arm64' || 'x64' }} - name: Install build dependencies (MacOS) run: brew install make if: runner.os == 'macOS' @@ -170,6 +174,7 @@ jobs: - macos-13 - macos-latest - windows-latest + - windows-11-arm cibw_archs_linux: ["x86_64"] build_sdist: [true] include: @@ -180,7 +185,11 @@ jobs: with: submodules: recursive fetch-depth: 0 # Fetch everything to get accurately versioned tag. - - uses: actions/setup-python@v2 # Some issues where caused by higher versions. + - if: ${{ matrix.os == 'windows-11-arm' }} + uses: actions/setup-python@v5 + name: Install Python + - if: ${{ matrix.os != 'windows-11-arm' }} + uses: actions/setup-python@v2 # Some issues where caused by higher versions. name: Install Python - name: Install cibuildwheel twine build run: python -m pip install cibuildwheel twine build @@ -190,6 +199,8 @@ jobs: - name: Set MSVC developer prompt uses: ilammy/msvc-dev-cmd@v1 if: runner.os == 'Windows' + with: + arch: ${{ matrix.os == 'windows-11-arm' && 'arm64' || 'x64' }} - name: Set up QEMU if: ${{runner.os == 'Linux' && matrix.cibw_archs_linux == 'aarch64'}} uses: docker/setup-qemu-action@v3 @@ -199,7 +210,7 @@ jobs: run: cibuildwheel --output-dir dist env: # Skip 32 bit, macosx_arm64 causes issues on cpython 3.9 - CIBW_SKIP: "*-win32 *-manylinux_i686 cp38-macosx_arm64" + CIBW_SKIP: "*-win32 *-manylinux_i686 cp38-macosx_arm64 cp39-win_arm64 cp310-win_arm64" CIBW_ARCHS_LINUX: ${{ matrix.cibw_archs_linux }} CIBW_TEST_REQUIRES: "pytest" # Simple tests that requires the project to be build correctly diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c067325..6357ca6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -7,6 +7,10 @@ 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.0.1-dev +----------------- ++ Wheels are now built for Windows arm64 architectures. + version 1.0.0 ----------------- The library has been running without issues as a dependency in quite a few From 10d2ffd6e97dca906da84d59c5b39fad915b5262 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez=20Mondrag=C3=B3n?= <16805946+edgarrmondragon@users.noreply.github.com> Date: Fri, 3 Jul 2026 01:02:25 -0600 Subject: [PATCH 3/3] Fix a crash when calling ``copy()`` on a flushed compress object on Python 3.15 (#80) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix a crash when calling `copy()` on a flushed compress object on Python 3.15 Signed-off-by: Edgar Ramírez Mondragón * test: Address Pytest 9.1 warnings Signed-off-by: Edgar Ramírez Mondragón * chore: Allow usage of ` tox -e 3.15 -- ` Signed-off-by: Edgar Ramírez Mondragón * ci: Add Python 3.15 and 3.15t to CI matrix Signed-off-by: Edgar Ramírez Mondragón * ci: Replace `macos-13` runner with `macos-15-intel` Signed-off-by: Edgar Ramírez Mondragón --------- Signed-off-by: Edgar Ramírez Mondragón --- .github/workflows/ci.yml | 8 +++++--- CHANGELOG.rst | 5 +++++ src/zlib_ng/zlib_ngmodule.c | 3 ++- tests/test_compat.py | 24 ++++++++++++------------ tests/test_gzip_ng.py | 2 +- tests/test_gzip_ng_threaded.py | 4 ++-- tox.ini | 2 +- 7 files changed, 28 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e1ce7ff..f3954ad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,13 +59,15 @@ jobs: - "3.13" - "3.14" - "3.14t" + - "3.15" + - "3.15t" - "pypy-3.10" - "pypy-3.11" os: ["ubuntu-latest"] include: - os: "macos-latest" # For m1 macos python-version: "3.12" - - os: "macos-13" # for x86 macos + - os: "macos-15-intel" # for x86 macos python-version: "3.10" - os: "windows-latest" python-version: "3.10" @@ -133,7 +135,7 @@ jobs: matrix: os: - "ubuntu-latest" - - "macos-13" + - "macos-15-intel" - "macos-latest" - "windows-latest" python_version: [ "python" ] @@ -171,7 +173,7 @@ jobs: matrix: os: - ubuntu-latest - - macos-13 + - macos-15-intel - macos-latest - windows-latest - windows-11-arm diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6357ca6..ca11abb 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -10,6 +10,11 @@ Changelog version 1.0.1-dev ----------------- + Wheels are now built for Windows arm64 architectures. ++ Fix a crash when calling ``copy()`` on a flushed compress object on Python + 3.15. Python 3.15 changed + (`gh-134745 `__) + ``PyThread_release_lock`` to use ``PyMutex`` internally, which now raises a + fatal error when releasing a lock that was never acquired. version 1.0.0 ----------------- diff --git a/src/zlib_ng/zlib_ngmodule.c b/src/zlib_ng/zlib_ngmodule.c index ea71d53..c8c2a32 100644 --- a/src/zlib_ng/zlib_ngmodule.c +++ b/src/zlib_ng/zlib_ngmodule.c @@ -801,7 +801,8 @@ zlib_Compress_copy(compobject *self, PyObject *Py_UNUSED(ignored)) if (!self->is_initialised) { PyErr_SetString(PyExc_ValueError, "Cannot copy flushed objects."); - goto error; + Py_DECREF(return_value); + return NULL; } /* Copy the zstream state diff --git a/tests/test_compat.py b/tests/test_compat.py index 12dda97..871bf84 100644 --- a/tests/test_compat.py +++ b/tests/test_compat.py @@ -64,21 +64,21 @@ def limited_zlib_tests(strategies=ZLIB_STRATEGIES): @pytest.mark.parametrize(["data_size", "value"], - itertools.product(DATA_SIZES, SEEDS)) + list(itertools.product(DATA_SIZES, SEEDS))) def test_crc32(data_size, value): data = DATA[:data_size] assert zlib.crc32(data, value) == zlib_ng.crc32(data, value) @pytest.mark.parametrize(["data_size", "value"], - itertools.product(DATA_SIZES, SEEDS)) + list(itertools.product(DATA_SIZES, SEEDS))) def test_adler32(data_size, value): data = DATA[:data_size] assert zlib.adler32(data, value) == zlib_ng.adler32(data, value) @pytest.mark.parametrize(["data_size", "level", "wbits"], - itertools.product(DATA_SIZES, range(10), WBITS_RANGE)) + list(itertools.product(DATA_SIZES, range(10), WBITS_RANGE))) def test_compress(data_size, level, wbits): data = DATA[:data_size] compressed = zlib_ng.compress(data, level=level, wbits=wbits) @@ -87,7 +87,7 @@ def test_compress(data_size, level, wbits): @pytest.mark.parametrize(["data_size", "level"], - itertools.product(DATA_SIZES, range(10))) + list(itertools.product(DATA_SIZES, range(10)))) def test_decompress_zlib(data_size, level): data = DATA[:data_size] compressed = zlib.compress(data, level=level) @@ -96,7 +96,7 @@ def test_decompress_zlib(data_size, level): @pytest.mark.parametrize(["data_size", "level", "wbits", "memLevel", "strategy"], - limited_zlib_tests(ZLIB_STRATEGIES)) + list(limited_zlib_tests(ZLIB_STRATEGIES))) def test_decompress_wbits(data_size, level, wbits, memLevel, strategy): data = DATA[:data_size] compressobj = zlib.compressobj(level=level, wbits=wbits, memLevel=memLevel, @@ -107,7 +107,7 @@ def test_decompress_wbits(data_size, level, wbits, memLevel, strategy): @pytest.mark.parametrize(["data_size", "level", "wbits"], - itertools.product([128 * 1024], range(10), WBITS_RANGE),) + list(itertools.product([128 * 1024], range(10), WBITS_RANGE),)) def test_decompress_zlib_ng(data_size, level, wbits): data = DATA[:data_size] compressed = zlib_ng.compress(data, level=level, wbits=wbits) @@ -116,7 +116,7 @@ def test_decompress_zlib_ng(data_size, level, wbits): @pytest.mark.parametrize(["data_size", "level", "wbits", "memLevel", "strategy"], - limited_zlib_tests(ZLIBNG_STRATEGIES)) + list(limited_zlib_tests(ZLIBNG_STRATEGIES))) def test_compress_compressobj(data_size, level, wbits, memLevel, strategy): data = DATA[:data_size] compressobj = zlib_ng.compressobj(level=level, @@ -129,7 +129,7 @@ def test_compress_compressobj(data_size, level, wbits, memLevel, strategy): @pytest.mark.parametrize(["data_size", "level", "wbits", "memLevel", "strategy"], - limited_zlib_tests(ZLIB_STRATEGIES)) + list(limited_zlib_tests(ZLIB_STRATEGIES))) def test_decompress_decompressobj(data_size, level, wbits, memLevel, strategy): data = DATA[:data_size] compressobj = zlib.compressobj(level=level, wbits=wbits, memLevel=memLevel, @@ -151,7 +151,7 @@ def test_decompressobj_unconsumed_tail(): @pytest.mark.parametrize(["data_size", "level"], - itertools.product(DATA_SIZES, range(10))) + list(itertools.product(DATA_SIZES, range(10)))) def test_gzip_ng_compress(data_size, level): data = DATA[:data_size] compressed = gzip_ng.compress(data, compresslevel=level) @@ -159,7 +159,7 @@ def test_gzip_ng_compress(data_size, level): @pytest.mark.parametrize(["data_size", "level"], - itertools.product(DATA_SIZES, range(10))) + list(itertools.product(DATA_SIZES, range(10)))) def test_decompress_gzip(data_size, level): data = DATA[:data_size] compressed = gzip.compress(data, compresslevel=level) @@ -168,7 +168,7 @@ def test_decompress_gzip(data_size, level): @pytest.mark.parametrize(["data_size", "level"], - itertools.product(DATA_SIZES, range(10))) + list(itertools.product(DATA_SIZES, range(10)))) def test_decompress_gzip_ng(data_size, level): data = DATA[:data_size] compressed = gzip_ng.compress(data, compresslevel=level) @@ -177,7 +177,7 @@ def test_decompress_gzip_ng(data_size, level): @pytest.mark.parametrize(["unused_size", "wbits"], - itertools.product([26], [-15, 15, 31])) + list(itertools.product([26], [-15, 15, 31]))) def test_unused_data(unused_size, wbits): unused_data = b"abcdefghijklmnopqrstuvwxyz"[:unused_size] compressor = zlib.compressobj(wbits=wbits) diff --git a/tests/test_gzip_ng.py b/tests/test_gzip_ng.py index abfd283..6c9d3c6 100644 --- a/tests/test_gzip_ng.py +++ b/tests/test_gzip_ng.py @@ -65,7 +65,7 @@ def test_GzipNGFile_read_truncated(): "reached") -@pytest.mark.parametrize("level", range(1, 10)) +@pytest.mark.parametrize("level", list(range(1, 10))) def test_decompress_stdin_stdout(capsysbinary, level): """Test if the command line can decompress data that has been compressed by gzip at all levels.""" diff --git a/tests/test_gzip_ng_threaded.py b/tests/test_gzip_ng_threaded.py index b976419..a587193 100644 --- a/tests/test_gzip_ng_threaded.py +++ b/tests/test_gzip_ng_threaded.py @@ -31,7 +31,7 @@ def test_threaded_read(): @pytest.mark.parametrize(["mode", "threads"], - itertools.product(["wb", "wt"], [1, 3, -1])) + list(itertools.product(["wb", "wt"], [1, 3, -1]))) def test_threaded_write(mode, threads): with tempfile.NamedTemporaryFile("wb", delete=False) as tmp: # Use a small block size to simulate many writes. @@ -216,7 +216,7 @@ def test_threaded_writer_does_not_close_stream(): @pytest.mark.timeout(5) @pytest.mark.parametrize( - ["mode", "threads"], itertools.product(["rb", "wb"], [1, 2])) + ["mode", "threads"], list(itertools.product(["rb", "wb"], [1, 2]))) def test_threaded_program_can_exit_on_error(tmp_path, mode, threads): program = tmp_path / "no_context_manager.py" test_file = tmp_path / "output.gz" diff --git a/tox.ini b/tox.ini index 14409e4..dfefd90 100644 --- a/tox.ini +++ b/tox.ini @@ -15,7 +15,7 @@ setenv= PYTHONDEVMODE=1 commands = # Create HTML coverage report for humans and xml coverage report for external services. - coverage run --branch --source=zlib_ng -m pytest tests + coverage run --branch --source=zlib_ng -m pytest {posargs:tests} # Ignore errors during report generation. Pypy does not generate proper coverage reports. coverage html -i coverage xml -i