Skip to content

Commit 43307b3

Browse files
committed
Merge branch 'main' into default-compressor
# Conflicts: # tests/test_config.py
2 parents cdf5542 + f360fc6 commit 43307b3

File tree

2 files changed

+60
-27
lines changed

2 files changed

+60
-27
lines changed

src/zarr/registry.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ def get_codec_class(key: str, reload_config: bool = False) -> type[Codec]:
138138

139139
config_entry = config.get("codecs", {}).get(key)
140140
if config_entry is None:
141+
if len(codec_classes) == 1:
142+
return next(iter(codec_classes.values()))
141143
warnings.warn(
142144
f"Codec '{key}' not configured in config. Selecting any implementation.", stacklevel=2
143145
)

tests/test_config.py

Lines changed: 58 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ class MockEnvCodecPipeline(CodecPipeline):
164164
assert get_pipeline_class(reload_config=True) == MockEnvCodecPipeline
165165

166166

167+
@pytest.mark.filterwarnings("error")
167168
@pytest.mark.parametrize("store", ["local", "memory"], indirect=["store"])
168169
def test_config_codec_implementation(store: Store) -> None:
169170
# has default value
@@ -177,24 +178,29 @@ async def _encode_single(
177178
) -> CodecOutput | None:
178179
_mock.call()
179180

180-
config.set({"codecs.blosc": fully_qualified_name(MockBloscCodec)})
181181
register_codec("blosc", MockBloscCodec)
182-
assert get_codec_class("blosc") == MockBloscCodec
182+
with config.set({"codecs.blosc": fully_qualified_name(MockBloscCodec)}):
183+
assert get_codec_class("blosc") == MockBloscCodec
183184

184-
# test if codec is used
185-
arr = Array.create(
186-
store=store,
187-
shape=(100,),
188-
chunks=(10,),
189-
zarr_format=3,
190-
dtype="i4",
191-
codecs=[BytesCodec(), {"name": "blosc", "configuration": {}}],
192-
)
193-
arr[:] = range(100)
194-
_mock.call.assert_called()
185+
# test if codec is used
186+
arr = Array.create(
187+
store=store,
188+
shape=(100,),
189+
chunks=(10,),
190+
zarr_format=3,
191+
dtype="i4",
192+
codecs=[BytesCodec(), {"name": "blosc", "configuration": {}}],
193+
)
194+
arr[:] = range(100)
195+
_mock.call.assert_called()
195196

196-
with mock.patch.dict(os.environ, {"ZARR_CODECS__BLOSC": fully_qualified_name(BloscCodec)}):
197-
assert get_codec_class("blosc", reload_config=True) == BloscCodec
197+
# test set codec with environment variable
198+
class NewBloscCodec(BloscCodec):
199+
pass
200+
201+
register_codec("blosc", NewBloscCodec)
202+
with mock.patch.dict(os.environ, {"ZARR_CODECS__BLOSC": fully_qualified_name(NewBloscCodec)}):
203+
assert get_codec_class("blosc", reload_config=True) == NewBloscCodec
198204

199205

200206
@pytest.mark.parametrize("store", ["local", "memory"], indirect=["store"])
@@ -204,18 +210,17 @@ def test_config_ndbuffer_implementation(store: Store) -> None:
204210

205211
# set custom ndbuffer with TestNDArrayLike implementation
206212
register_ndbuffer(NDBufferUsingTestNDArrayLike)
207-
config.set({"ndbuffer": fully_qualified_name(NDBufferUsingTestNDArrayLike)})
208-
assert get_ndbuffer_class() == NDBufferUsingTestNDArrayLike
209-
arr = Array.create(
210-
store=store,
211-
shape=(100,),
212-
chunks=(10,),
213-
zarr_format=3,
214-
dtype="i4",
215-
)
216-
got = arr[:]
217-
print(type(got))
218-
assert isinstance(got, TestNDArrayLike)
213+
with config.set({"ndbuffer": fully_qualified_name(NDBufferUsingTestNDArrayLike)}):
214+
assert get_ndbuffer_class() == NDBufferUsingTestNDArrayLike
215+
arr = Array.create(
216+
store=store,
217+
shape=(100,),
218+
chunks=(10,),
219+
zarr_format=3,
220+
dtype="i4",
221+
)
222+
got = arr[:]
223+
assert isinstance(got, TestNDArrayLike)
219224

220225

221226
def test_config_buffer_implementation() -> None:
@@ -255,6 +260,32 @@ def test_config_buffer_implementation() -> None:
255260
assert np.array_equal(arr_Crc32c[:], data2d)
256261

257262

263+
@pytest.mark.filterwarnings("error")
264+
def test_warning_on_missing_codec_config() -> None:
265+
class NewCodec(BytesCodec):
266+
pass
267+
268+
class NewCodec2(BytesCodec):
269+
pass
270+
271+
# error if codec is not registered
272+
with pytest.raises(KeyError):
273+
get_codec_class("missing_codec")
274+
275+
# no warning if only one implementation is available
276+
register_codec("new_codec", NewCodec)
277+
get_codec_class("new_codec")
278+
279+
# warning because multiple implementations are available but none is selected in the config
280+
register_codec("new_codec", NewCodec2)
281+
with pytest.warns(UserWarning):
282+
get_codec_class("new_codec")
283+
284+
# no warning if multiple implementations are available and one is selected in the config
285+
with config.set({"codecs.new_codec": fully_qualified_name(NewCodec)}):
286+
get_codec_class("new_codec")
287+
288+
258289
@pytest.mark.parametrize(
259290
("dtype", "expected_codecs"),
260291
[

0 commit comments

Comments
 (0)