Skip to content

Commit 608c919

Browse files
sheikhayaand-v-b
andauthored
fix: skip exact byte comparison for gzip codec due to timestamp variance (zarr-developers#4270)
* fix: skip exact byte comparison for gzip codec due to timestamp variance * fix: compare gzip streams ignoring mtime --------- Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
1 parent d34f58a commit 608c919

3 files changed

Lines changed: 58 additions & 2 deletions

File tree

src/zarr/codecs/gzip.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ def parse_gzip_level(data: JSON) -> int:
2828
return parsed
2929

3030

31+
def _gzip_streams_equal_except_mtime(a: bytes, b: bytes) -> bool:
32+
if len(a) != len(b):
33+
return False
34+
35+
return a[:4] == b[:4] and a[8:] == b[8:]
36+
37+
3138
@dataclass(frozen=True)
3239
class GzipCodec(BytesBytesCodec):
3340
"""gzip codec"""

tests/test_codecs/test_gzip.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from zarr.abc.codec import SupportsSyncCodec
66
from zarr.abc.store import Store
77
from zarr.codecs import GzipCodec
8+
from zarr.codecs.gzip import _gzip_streams_equal_except_mtime
89
from zarr.core.array_spec import ArrayConfig, ArraySpec
910
from zarr.core.buffer import default_buffer_prototype
1011
from zarr.core.dtype import get_data_type_from_native_dtype
@@ -50,3 +51,39 @@ def test_gzip_codec_sync_roundtrip() -> None:
5051
decoded = codec._decode_sync(encoded, spec)
5152
result = np.frombuffer(decoded.as_numpy_array(), dtype="float64")
5253
np.testing.assert_array_equal(arr, result)
54+
55+
56+
def test_gzip_streams_equal_except_mtime() -> None:
57+
prefix = b"\x1f\x8b\x08\x00"
58+
mtime = b"\x01\x02\x03\x04"
59+
suffix = b"\x00\xff\x10\x20"
60+
61+
# Identical streams are equal.
62+
assert _gzip_streams_equal_except_mtime(
63+
prefix + mtime + suffix,
64+
prefix + mtime + suffix,
65+
)
66+
67+
# Streams with different MTIME values are still equal.
68+
assert _gzip_streams_equal_except_mtime(
69+
prefix + b"\x01\x02\x03\x04" + suffix,
70+
prefix + b"\x05\x06\x07\x08" + suffix,
71+
)
72+
73+
# Differences after MTIME are detected.
74+
assert not _gzip_streams_equal_except_mtime(
75+
prefix + mtime + suffix,
76+
prefix + mtime + b"\x00\xff\x10\x21",
77+
)
78+
79+
# Differences before MTIME are detected.
80+
assert not _gzip_streams_equal_except_mtime(
81+
prefix + mtime + suffix,
82+
b"\x1f\x8b\x09\x00" + mtime + suffix,
83+
)
84+
85+
# Different lengths are detected.
86+
assert not _gzip_streams_equal_except_mtime(
87+
prefix + mtime + suffix,
88+
prefix + mtime + suffix + b"\x00",
89+
)

tests/test_fused_pipeline.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
)
1919
from zarr.abc.store import Store, _store_supports_sync_io
2020
from zarr.codecs.bytes import BytesCodec
21-
from zarr.codecs.gzip import GzipCodec
21+
from zarr.codecs.gzip import GzipCodec, _gzip_streams_equal_except_mtime
2222
from zarr.codecs.transpose import TransposeCodec
2323
from zarr.codecs.zstd import ZstdCodec
2424
from zarr.core.codec_pipeline import FusedCodecPipeline
@@ -904,7 +904,19 @@ def test_async_chunk_transform_matches_sync(codecs: tuple[Any, ...]) -> None:
904904
async_bytes = asyncio.run(async_t.encode_chunk(value, spec))
905905
assert sync_bytes is not None
906906
assert async_bytes is not None
907-
np.testing.assert_array_equal(async_bytes.to_bytes(), sync_bytes.to_bytes())
907+
908+
has_timestamp_codec = any(isinstance(c, GzipCodec) for c in evolved)
909+
910+
if has_timestamp_codec:
911+
assert _gzip_streams_equal_except_mtime(
912+
async_bytes.to_bytes(),
913+
sync_bytes.to_bytes(),
914+
)
915+
else:
916+
np.testing.assert_array_equal(
917+
async_bytes.to_bytes(),
918+
sync_bytes.to_bytes(),
919+
)
908920

909921
sync_arr = sync_t.decode_chunk(async_bytes, spec)
910922
async_arr = asyncio.run(async_t.decode_chunk(async_bytes, spec))

0 commit comments

Comments
 (0)