Skip to content

Commit c5cf0c5

Browse files
normanrzdstansby
andauthored
Update numcodecs tests and docs for zarr-python 3.0 (#675)
* update numcodecs tests and docs for zarr-python 3rc1 * release docs and repr test * debugging * pre-commit config --------- Co-authored-by: David Stansby <dstansby@gmail.com>
1 parent 7cdffa1 commit c5cf0c5

File tree

6 files changed

+87
-67
lines changed

6 files changed

+87
-67
lines changed

.github/workflows/ci.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ jobs:
2121
uses: actions/checkout@v4
2222
with:
2323
submodules: recursive
24+
fetch-depth: 0 # required for version resolution
2425

2526
- name: Set up Conda
2627
uses: conda-incubator/setup-miniconda@v3.1.0

.pre-commit-config.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,4 @@ repos:
3030
hooks:
3131
- id: mypy
3232
args: [--config-file, pyproject.toml]
33-
additional_dependencies: [numpy, pytest, crc32c, zfpy, 'zarr>=3.0.0b2']
33+
additional_dependencies: [numpy, pytest, crc32c, zfpy, 'zarr>=3.0.0rc1']

docs/release.rst

+2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ Fixes
2727
~~~~~
2828
* Fixes issue with ``Delta`` Zarr 3 codec not working with ``astype``.
2929
By :user:`Norman Rzepka <normanrz>`, :issue:`664`
30+
* Fixes issues with the upcoming ``zarr`` 3.0.0 release.
31+
By :user:`Norman Rzepka <normanrz>`, :issue:`675`
3032

3133
* Removed Version Check: The previous code included a check for the `NumPy` version
3234
and a warning if the version was incompatible with `zfpy`.

docs/zarr3.rst

+23-20
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ Zarr 3 codecs
55
.. automodule:: numcodecs.zarr3
66

77

8-
Bytes-to-bytes codecs
9-
---------------------
8+
Compressors (bytes-to-bytes codecs)
9+
-----------------------------------
1010
.. autoclass:: Blosc()
1111

1212
.. autoattribute:: codec_name
@@ -40,58 +40,61 @@ Bytes-to-bytes codecs
4040
.. autoattribute:: codec_name
4141

4242

43-
Array-to-array codecs
44-
---------------------
45-
.. autoclass:: Delta()
43+
Checksum codecs (bytes-to-bytes codecs)
44+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
45+
Need to be used as ``compressors`` in zarr-python.
46+
47+
.. autoclass:: CRC32()
4648

4749
.. autoattribute:: codec_name
4850

49-
.. autoclass:: BitRound()
51+
.. autoclass:: CRC32C()
5052

5153
.. autoattribute:: codec_name
5254

53-
.. autoclass:: FixedScaleOffset()
55+
.. autoclass:: Adler32()
5456

5557
.. autoattribute:: codec_name
5658

57-
.. autoclass:: Quantize()
59+
.. autoclass:: Fletcher32()
5860

5961
.. autoattribute:: codec_name
6062

61-
.. autoclass:: PackBits()
63+
.. autoclass:: JenkinsLookup3()
6264

6365
.. autoattribute:: codec_name
6466

65-
.. autoclass:: AsType()
6667

67-
.. autoattribute:: codec_name
68+
Filters (array-to-array codecs)
69+
-------------------------------
70+
.. autoclass:: Delta()
6871

72+
.. autoattribute:: codec_name
6973

70-
Bytes-to-bytes checksum codecs
71-
------------------------------
72-
.. autoclass:: CRC32()
74+
.. autoclass:: BitRound()
7375

7476
.. autoattribute:: codec_name
7577

76-
.. autoclass:: CRC32C()
78+
.. autoclass:: FixedScaleOffset()
7779

7880
.. autoattribute:: codec_name
7981

80-
.. autoclass:: Adler32()
82+
.. autoclass:: Quantize()
8183

8284
.. autoattribute:: codec_name
8385

84-
.. autoclass:: Fletcher32()
86+
.. autoclass:: PackBits()
8587

8688
.. autoattribute:: codec_name
8789

88-
.. autoclass:: JenkinsLookup3()
90+
.. autoclass:: AsType()
8991

9092
.. autoattribute:: codec_name
9193

9294

93-
Array-to-bytes codecs
94-
---------------------
95+
96+
Serializers (array-to-bytes codecs)
97+
-----------------------------------
9598
.. autoclass:: PCodec()
9699

97100
.. autoattribute:: codec_name

numcodecs/tests/test_zarr3.py

+48-41
Original file line numberDiff line numberDiff line change
@@ -66,17 +66,19 @@ def test_docstring(codec_class: type[numcodecs.zarr3._NumcodecsCodec]):
6666
numcodecs.zarr3.Shuffle,
6767
],
6868
)
69-
def test_generic_codec_class(store: StorePath, codec_class: type[numcodecs.zarr3._NumcodecsCodec]):
69+
def test_generic_compressor(
70+
store: StorePath, codec_class: type[numcodecs.zarr3._NumcodecsBytesBytesCodec]
71+
):
7072
data = np.arange(0, 256, dtype="uint16").reshape((16, 16))
7173

7274
with pytest.warns(UserWarning, match=EXPECTED_WARNING_STR):
73-
a = Array.create(
75+
a = zarr.create_array(
7476
store / "generic",
7577
shape=data.shape,
76-
chunk_shape=(16, 16),
78+
chunks=(16, 16),
7779
dtype=data.dtype,
7880
fill_value=0,
79-
codecs=[BytesCodec(), codec_class()],
81+
compressors=[codec_class()],
8082
)
8183

8284
a[:, :] = data.copy()
@@ -100,62 +102,61 @@ def test_generic_codec_class(store: StorePath, codec_class: type[numcodecs.zarr3
100102
)
101103
def test_generic_filter(
102104
store: StorePath,
103-
codec_class: type[numcodecs.zarr3._NumcodecsCodec],
105+
codec_class: type[numcodecs.zarr3._NumcodecsArrayArrayCodec],
104106
codec_config: dict[str, JSON],
105107
):
106108
data = np.linspace(0, 10, 256, dtype="float32").reshape((16, 16))
107109

108110
with pytest.warns(UserWarning, match=EXPECTED_WARNING_STR):
109-
a = Array.create(
111+
a = zarr.create_array(
110112
store / "generic",
111113
shape=data.shape,
112-
chunk_shape=(16, 16),
114+
chunks=(16, 16),
113115
dtype=data.dtype,
114116
fill_value=0,
115-
codecs=[
117+
filters=[
116118
codec_class(**codec_config),
117-
BytesCodec(),
118119
],
119120
)
120121

121122
a[:, :] = data.copy()
122-
a = Array.open(store / "generic")
123+
a = zarr.open_array(store / "generic", mode="r")
123124
np.testing.assert_array_equal(data, a[:, :])
124125

125126

126127
def test_generic_filter_bitround(store: StorePath):
127128
data = np.linspace(0, 1, 256, dtype="float32").reshape((16, 16))
128129

129130
with pytest.warns(UserWarning, match=EXPECTED_WARNING_STR):
130-
a = Array.create(
131+
a = zarr.create_array(
131132
store / "generic_bitround",
132133
shape=data.shape,
133-
chunk_shape=(16, 16),
134+
chunks=(16, 16),
134135
dtype=data.dtype,
135136
fill_value=0,
136-
codecs=[numcodecs.zarr3.BitRound(keepbits=3), BytesCodec()],
137+
filters=[numcodecs.zarr3.BitRound(keepbits=3)],
137138
)
138139

139140
a[:, :] = data.copy()
140-
a = Array.open(store / "generic_bitround")
141+
a = zarr.open_array(store / "generic_bitround", mode="r")
141142
assert np.allclose(data, a[:, :], atol=0.1)
142143

143144

144145
def test_generic_filter_quantize(store: StorePath):
145146
data = np.linspace(0, 10, 256, dtype="float32").reshape((16, 16))
146147

147148
with pytest.warns(UserWarning, match=EXPECTED_WARNING_STR):
148-
a = Array.create(
149+
a = zarr.create_array(
149150
store / "generic_quantize",
150151
shape=data.shape,
151-
chunk_shape=(16, 16),
152+
chunks=(16, 16),
152153
dtype=data.dtype,
153154
fill_value=0,
154-
codecs=[numcodecs.zarr3.Quantize(digits=3), BytesCodec()],
155+
filters=[numcodecs.zarr3.Quantize(digits=3)],
155156
)
156157

157158
a[:, :] = data.copy()
158-
a = Array.open(store / "generic_quantize")
159+
a = zarr.open_array(store / "generic_quantize", mode="r")
159160
assert np.allclose(data, a[:, :], atol=0.001)
160161

161162

@@ -164,27 +165,27 @@ def test_generic_filter_packbits(store: StorePath):
164165
data[0:4, :] = True
165166

166167
with pytest.warns(UserWarning, match=EXPECTED_WARNING_STR):
167-
a = Array.create(
168+
a = zarr.create_array(
168169
store / "generic_packbits",
169170
shape=data.shape,
170-
chunk_shape=(16, 16),
171+
chunks=(16, 16),
171172
dtype=data.dtype,
172173
fill_value=0,
173-
codecs=[numcodecs.zarr3.PackBits(), BytesCodec()],
174+
filters=[numcodecs.zarr3.PackBits()],
174175
)
175176

176177
a[:, :] = data.copy()
177-
a = Array.open(store / "generic_packbits")
178+
a = zarr.open_array(store / "generic_packbits", mode="r")
178179
np.testing.assert_array_equal(data, a[:, :])
179180

180181
with pytest.raises(ValueError, match=".*requires bool dtype.*"):
181-
Array.create(
182+
zarr.create_array(
182183
store / "generic_packbits_err",
183184
shape=data.shape,
184-
chunk_shape=(16, 16),
185+
chunks=(16, 16),
185186
dtype="uint32",
186187
fill_value=0,
187-
codecs=[numcodecs.zarr3.PackBits(), BytesCodec()],
188+
filters=[numcodecs.zarr3.PackBits()],
188189
)
189190

190191

@@ -198,26 +199,30 @@ def test_generic_filter_packbits(store: StorePath):
198199
numcodecs.zarr3.JenkinsLookup3,
199200
],
200201
)
201-
def test_generic_checksum(store: StorePath, codec_class: type[numcodecs.zarr3._NumcodecsCodec]):
202+
def test_generic_checksum(
203+
store: StorePath, codec_class: type[numcodecs.zarr3._NumcodecsBytesBytesCodec]
204+
):
202205
data = np.linspace(0, 10, 256, dtype="float32").reshape((16, 16))
203206

204207
with pytest.warns(UserWarning, match=EXPECTED_WARNING_STR):
205-
a = Array.create(
208+
a = zarr.create_array(
206209
store / "generic_checksum",
207210
shape=data.shape,
208-
chunk_shape=(16, 16),
211+
chunks=(16, 16),
209212
dtype=data.dtype,
210213
fill_value=0,
211-
codecs=[BytesCodec(), codec_class()],
214+
compressors=[codec_class()],
212215
)
213216

214217
a[:, :] = data.copy()
215-
a = Array.open(store / "generic_checksum")
218+
a = zarr.open_array(store / "generic_checksum", mode="r")
216219
np.testing.assert_array_equal(data, a[:, :])
217220

218221

219222
@pytest.mark.parametrize("codec_class", [numcodecs.zarr3.PCodec, numcodecs.zarr3.ZFPY])
220-
def test_generic_bytes_codec(store: StorePath, codec_class: type[numcodecs.zarr3._NumcodecsCodec]):
223+
def test_generic_bytes_codec(
224+
store: StorePath, codec_class: type[numcodecs.zarr3._NumcodecsArrayBytesCodec]
225+
):
221226
try:
222227
codec_class()._codec # noqa: B018
223228
except ValueError as e:
@@ -231,15 +236,13 @@ def test_generic_bytes_codec(store: StorePath, codec_class: type[numcodecs.zarr3
231236
data = np.arange(0, 256, dtype="float32").reshape((16, 16))
232237

233238
with pytest.warns(UserWarning, match=EXPECTED_WARNING_STR):
234-
a = Array.create(
239+
a = zarr.create_array(
235240
store / "generic",
236241
shape=data.shape,
237-
chunk_shape=(16, 16),
242+
chunks=(16, 16),
238243
dtype=data.dtype,
239244
fill_value=0,
240-
codecs=[
241-
codec_class(),
242-
],
245+
serializer=codec_class(),
243246
)
244247

245248
a[:, :] = data.copy()
@@ -250,18 +253,22 @@ def test_delta_astype(store: StorePath):
250253
data = np.linspace(0, 10, 256, dtype="i8").reshape((16, 16))
251254

252255
with pytest.warns(UserWarning, match=EXPECTED_WARNING_STR):
253-
a = Array.create(
256+
a = zarr.create_array(
254257
store / "generic",
255258
shape=data.shape,
256-
chunk_shape=(16, 16),
259+
chunks=(16, 16),
257260
dtype=data.dtype,
258261
fill_value=0,
259-
codecs=[
262+
filters=[
260263
numcodecs.zarr3.Delta(dtype="i8", astype="i2"), # type: ignore[arg-type]
261-
BytesCodec(),
262264
],
263265
)
264266

265267
a[:, :] = data.copy()
266-
a = Array.open(store / "generic")
268+
a = zarr.open_array(store / "generic", mode="r")
267269
np.testing.assert_array_equal(data, a[:, :])
270+
271+
272+
def test_repr():
273+
codec = numcodecs.zarr3.LZ4(level=5)
274+
assert repr(codec) == "LZ4(codec_name='numcodecs.lz4', codec_config={'level': 5})"

numcodecs/zarr3.py

+12-5
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@
88
>>> import zarr
99
>>> import numcodecs.zarr3
1010
>>>
11-
>>> codecs = [zarr.codecs.BytesCodec(), numcodecs.zarr3.BZ2(level=5)]
12-
>>> array = zarr.open(
13-
... "data.zarr", mode="w",
14-
... shape=(1024, 1024), chunks=(64, 64),
11+
>>> array = zarr.create_array(
12+
... store="data.zarr",
13+
... shape=(1024, 1024),
14+
... chunks=(64, 64),
1515
... dtype="uint32",
16-
... codecs=codecs)
16+
... filters=[numcodecs.zarr3.Delta()],
17+
... compressors=[numcodecs.zarr3.BZ2(level=5)])
1718
>>> array[:] = np.arange(*array.shape).astype(array.dtype)
1819
1920
.. note::
@@ -119,6 +120,12 @@ def to_dict(self) -> dict[str, JSON]:
119120
def compute_encoded_size(self, input_byte_length: int, chunk_spec: ArraySpec) -> int:
120121
raise NotImplementedError # pragma: no cover
121122

123+
# Override __repr__ because dynamically constructed classes don't seem to work otherwise
124+
def __repr__(self) -> str:
125+
codec_config = self.codec_config.copy()
126+
codec_config.pop("id", None)
127+
return f"{self.__class__.__name__}(codec_name={self.codec_name!r}, codec_config={codec_config!r})"
128+
122129

123130
class _NumcodecsBytesBytesCodec(_NumcodecsCodec, BytesBytesCodec):
124131
def __init__(self, **codec_config: JSON) -> None:

0 commit comments

Comments
 (0)