From 60fdf8689b43ea8200040c38b526966d765570bb Mon Sep 17 00:00:00 2001 From: Fabian Isensee Date: Fri, 6 Nov 2026 16:35:41 +0100 Subject: [PATCH] Release the input buffer when SChunk(data=...) fails The squash of #765 resolved the conflict in SChunk.__init__() from main's side, which releases the input buffer only when c-blosc2 returns an error. When _store_buffer() raises (a chunk larger than BLOSC2_MAX_BUFFERSIZE), the buffer stayed exported. The loop is back in a try/finally. test_data_writes_reach_prefilter() also runs with set_releasegil(True) now: since #766 the writes keep the GIL for Python prefilters. Co-Authored-By: Claude Opus 5.5 --- src/blosc2/blosc2_ext.pyx | 21 +++++++++++---------- tests/test_schunk_data_writes.py | 4 ++-- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/blosc2/blosc2_ext.pyx b/src/blosc2/blosc2_ext.pyx index de90e254c..3b99798e0 100644 --- a/src/blosc2/blosc2_ext.pyx +++ b/src/blosc2/blosc2_ext.pyx @@ -4184,16 +4184,17 @@ cdef class SChunk: len_data = buf.len nchunks = (len_data + chunksize - 1) // chunksize if len_data > 0 else 0 len_chunk = chunksize - for i in range(nchunks): - if i == (nchunks - 1): - len_chunk = len_data - i * chunksize - index = i * chunksize - rc = _store_buffer(self.schunk, _WRITE_APPEND, i, buf_ptr + index, len_chunk) - if rc < 0: - PyBuffer_Release(&buf) - _raise_callback_error() - raise RuntimeError("Could not compress and append the chunk") - PyBuffer_Release(&buf) + try: + for i in range(nchunks): + if i == (nchunks - 1): + len_chunk = len_data - i * chunksize + index = i * chunksize + rc = _store_buffer(self.schunk, _WRITE_APPEND, i, buf_ptr + index, len_chunk) + if rc < 0: + _raise_callback_error() + raise RuntimeError("Could not compress and append the chunk") + finally: + PyBuffer_Release(&buf) @property def c_schunk(self): diff --git a/tests/test_schunk_data_writes.py b/tests/test_schunk_data_writes.py index 887689daf..147bcc2ac 100644 --- a/tests/test_schunk_data_writes.py +++ b/tests/test_schunk_data_writes.py @@ -77,9 +77,9 @@ def test_data_writes(storage, releasegil): np.testing.assert_array_equal(got, exp) -def test_data_writes_reach_prefilter(storage): +def test_data_writes_reach_prefilter(storage, releasegil): # The prefilter computes each item from its position, so it must see the right chunk number. - # With the GIL held only: Python prefilters crash with set_releasegil(True). + # It runs Python, so the writes keep the GIL even with set_releasegil(True). schunk = new_schunk(storage, nthreads=1) @schunk.prefilter(np.int32, np.int32)