Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/zarr/codecs/numcodecs/_codecs.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,6 @@ def __init__(self, **codec_config: JSON) -> None:
) # pragma: no cover

object.__setattr__(self, "codec_config", codec_config)
warn(
"Numcodecs codecs are not in the Zarr version 3 specification and "
"may not be supported by other zarr implementations.",
category=ZarrUserWarning,
stacklevel=2,
)

@cached_property
def _codec(self) -> Numcodec:
Expand All @@ -119,6 +113,12 @@ def from_dict(cls, data: dict[str, JSON]) -> Self:
return cls(**codec_config)

def to_dict(self) -> dict[str, JSON]:
warn(
"Numcodecs codecs are not in the Zarr version 3 specification and "
"may not be supported by other zarr implementations.",
category=ZarrUserWarning,
stacklevel=2,
)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@d-v-b - what do think about dropping this warning all together now?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could drop it!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, done. This seems reasonable to me, and makes the assumption that any future breaking changes will at least maintain read compatibility for previously written data. Which is good UX.

codec_config = self.codec_config.copy()
codec_config.pop("id", None)
return {
Expand Down
6 changes: 2 additions & 4 deletions tests/test_cli/test_migrate_v3.py
Original file line number Diff line number Diff line change
Expand Up @@ -524,8 +524,7 @@ def test_migrate_incorrect_filter(local_store: LocalStore) -> None:
fill_value=0,
)

with pytest.warns(UserWarning, match=NUMCODECS_USER_WARNING):
result = runner.invoke(cli.app, ["migrate", "v3", str(local_store.root)])
result = runner.invoke(cli.app, ["migrate", "v3", str(local_store.root)])

assert result.exit_code == 1
assert isinstance(result.exception, TypeError)
Expand All @@ -548,8 +547,7 @@ def test_migrate_incorrect_compressor(local_store: LocalStore) -> None:
fill_value=0,
)

with pytest.warns(UserWarning, match=NUMCODECS_USER_WARNING):
result = runner.invoke(cli.app, ["migrate", "v3", str(local_store.root)])
result = runner.invoke(cli.app, ["migrate", "v3", str(local_store.root)])

assert result.exit_code == 1
assert isinstance(result.exception, TypeError)
Expand Down
82 changes: 50 additions & 32 deletions tests/test_codecs/test_numcodecs.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import contextlib
import pickle
import warnings
from typing import TYPE_CHECKING, Any

import numpy as np
Expand Down Expand Up @@ -164,8 +165,7 @@ def test_generic_filter(

a[:, :] = data.copy()
with codec_conf():
with pytest.warns(ZarrUserWarning, match=EXPECTED_WARNING_STR):
b = open_array(a.store, mode="r")
b = open_array(a.store, mode="r")
np.testing.assert_array_equal(data, b[:, :])


Expand All @@ -183,8 +183,7 @@ def test_generic_filter_bitround() -> None:
)

a[:, :] = data.copy()
with pytest.warns(ZarrUserWarning, match=EXPECTED_WARNING_STR):
b = open_array(a.store, mode="r")
b = open_array(a.store, mode="r")
assert np.allclose(data, b[:, :], atol=0.1)


Expand All @@ -202,8 +201,7 @@ def test_generic_filter_quantize() -> None:
)

a[:, :] = data.copy()
with pytest.warns(ZarrUserWarning, match=EXPECTED_WARNING_STR):
b = open_array(a.store, mode="r")
b = open_array(a.store, mode="r")
assert np.allclose(data, b[:, :], atol=0.001)


Expand All @@ -222,20 +220,18 @@ def test_generic_filter_packbits() -> None:
)

a[:, :] = data.copy()
with pytest.warns(ZarrUserWarning, match=EXPECTED_WARNING_STR):
b = open_array(a.store, mode="r")
b = open_array(a.store, mode="r")
np.testing.assert_array_equal(data, b[:, :])

with pytest.warns(ZarrUserWarning, match=EXPECTED_WARNING_STR):
with pytest.raises(ValueError, match=".*requires bool dtype.*"):
create_array(
{},
shape=data.shape,
chunks=(16, 16),
dtype="uint32",
fill_value=0,
filters=[_numcodecs.PackBits()],
)
with pytest.raises(ValueError, match=".*requires bool dtype.*"):
create_array(
{},
shape=data.shape,
chunks=(16, 16),
dtype="uint32",
fill_value=0,
filters=[_numcodecs.PackBits()],
)


@pytest.mark.parametrize(
Expand All @@ -251,8 +247,7 @@ def test_generic_filter_packbits() -> None:
def test_generic_checksum(codec_class: type[_numcodecs._NumcodecsBytesBytesCodec]) -> None:
# Check if the codec is available in numcodecs
try:
with pytest.warns(ZarrUserWarning, match=EXPECTED_WARNING_STR):
codec_class()._codec # noqa: B018
codec_class()._codec # noqa: B018
except UnknownCodecError as e: # pragma: no cover
pytest.skip(f"{codec_class.codec_name} is not available in numcodecs: {e}")

Expand All @@ -270,16 +265,14 @@ def test_generic_checksum(codec_class: type[_numcodecs._NumcodecsBytesBytesCodec

a[:, :] = data.copy()
with codec_conf():
with pytest.warns(ZarrUserWarning, match=EXPECTED_WARNING_STR):
b = open_array(a.store, mode="r")
b = open_array(a.store, mode="r")
np.testing.assert_array_equal(data, b[:, :])


@pytest.mark.parametrize("codec_class", [_numcodecs.PCodec, _numcodecs.ZFPY])
def test_generic_bytes_codec(codec_class: type[_numcodecs._NumcodecsArrayBytesCodec]) -> None:
try:
with pytest.warns(ZarrUserWarning, match=EXPECTED_WARNING_STR):
codec_class()._codec # noqa: B018
codec_class()._codec # noqa: B018
except ValueError as e: # pragma: no cover
if "codec not available" in str(e):
pytest.xfail(f"{codec_class.codec_name} is not available: {e}")
Expand Down Expand Up @@ -321,21 +314,47 @@ def test_delta_astype() -> None:

a[:, :] = data.copy()
with codec_conf():
with pytest.warns(ZarrUserWarning, match=EXPECTED_WARNING_STR):
b = open_array(a.store, mode="r")
b = open_array(a.store, mode="r")
np.testing.assert_array_equal(data, b[:, :])


def test_repr() -> None:
with pytest.warns(ZarrUserWarning, match=EXPECTED_WARNING_STR):
codec = _numcodecs.LZ4(level=5)
codec = _numcodecs.LZ4(level=5)
assert repr(codec) == "LZ4(codec_name='numcodecs.lz4', codec_config={'level': 5})"


def test_to_dict() -> None:
codec = _numcodecs.LZ4(level=5)
with pytest.warns(ZarrUserWarning, match=EXPECTED_WARNING_STR):
assert codec.to_dict() == {"name": "numcodecs.lz4", "configuration": {"level": 5}}


def test_warn_on_write_not_read() -> None:
data = np.arange(0, 256, dtype="uint16").reshape((16, 16))

with pytest.warns(ZarrUserWarning, match=EXPECTED_WARNING_STR):
codec = _numcodecs.LZ4(level=5)
assert codec.to_dict() == {"name": "numcodecs.lz4", "configuration": {"level": 5}}
a = create_array(
{},
shape=data.shape,
chunks=(16, 16),
dtype=data.dtype,
fill_value=0,
compressors=[_numcodecs.Zstd(level=1)],
)

a[:, :] = data.copy()
with codec_conf():
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
b = open_array(a.store, mode="r")

np.testing.assert_array_equal(data, b[:, :])
assert not [
warning
for warning in caught
if issubclass(warning.category, ZarrUserWarning)
and "Numcodecs codecs are not in the Zarr version 3 specification" in str(warning.message)
]


@pytest.mark.parametrize(
Expand Down Expand Up @@ -367,8 +386,7 @@ def test_to_dict() -> None:
def test_codecs_pickleable(codec_cls: type[_numcodecs._NumcodecsCodec]) -> None:
# Check if the codec is available in numcodecs
try:
with pytest.warns(ZarrUserWarning, match=EXPECTED_WARNING_STR):
codec = codec_cls()
codec = codec_cls()
except UnknownCodecError as e: # pragma: no cover
pytest.skip(f"{codec_cls.codec_name} is not available in numcodecs: {e}")

Expand Down