diff --git a/docs/release.md b/docs/release.md index 1f439a9c..3ef8aaf4 100644 --- a/docs/release.md +++ b/docs/release.md @@ -19,6 +19,10 @@ * Allow building against a system Zlib. Note, this is only required if blosc is still vendored, and a vendored Zlib is no longer built if blosc is not. By {user}`Elliott Sales de Andrade `, {issue}`860` +* `Blosc` can now encode an array whose dtype has an itemsize of 0 (e.g. a structured + dtype with a zero-length field), which failed with a `RuntimeError` (or crashed with a + floating point exception with older bundled c-blosc versions). + By {user}`Raashish Aggarwal `, {issue}`516` ## 0.17.0 diff --git a/src/numcodecs/blosc.pyx b/src/numcodecs/blosc.pyx index 8c52dd95..b3a6540d 100644 --- a/src/numcodecs/blosc.pyx +++ b/src/numcodecs/blosc.pyx @@ -267,6 +267,11 @@ def compress(source, char* cname, int clevel, int shuffle=SHUFFLE, itemsize = typesize else: itemsize = source_pb.itemsize + if itemsize == 0: + # blosc does not accept a typesize of 0 (older versions crashed on it), + # which zero-size dtypes such as a structured dtype with a zero-length + # field give; the buffer is empty in that case, so any typesize works + itemsize = 1 # determine shuffle if shuffle == AUTOSHUFFLE: diff --git a/tests/test_blosc.py b/tests/test_blosc.py index b920f03e..eb48035e 100644 --- a/tests/test_blosc.py +++ b/tests/test_blosc.py @@ -326,6 +326,19 @@ def test_typesize_less_than_1(): compressor.encode(arr.tobytes()) +@pytest.mark.parametrize( + "shuffle", [Blosc.NOSHUFFLE, Blosc.SHUFFLE, Blosc.BITSHUFFLE, Blosc.AUTOSHUFFLE] +) +def test_zero_itemsize(shuffle): + # a structured dtype with a zero-length field has itemsize 0, which blosc + # rejects as a typesize (and older versions crashed on, #516) + arr = np.zeros((5,), dtype=[("foo", int, (0,))]) + assert arr.dtype.itemsize == 0 + enc = Blosc(shuffle=shuffle).encode(arr) + nbytes, _, _ = blosc._cbuffer_sizes(enc) + assert nbytes == 0 + + def test_config_no_typesize(): codec = Blosc(shuffle=Blosc.SHUFFLE, typesize=5) config = codec.get_config()