diff --git a/changes/3395.bugfix.rst b/changes/3395.bugfix.rst new file mode 100644 index 0000000000..73627c174d --- /dev/null +++ b/changes/3395.bugfix.rst @@ -0,0 +1 @@ +Raise a Zarr-specific error class when a codec can't be found by name when deserializing the given codecs. This avoids hiding this error behind a "not part of a zarr hierarchy" warning. diff --git a/src/zarr/core/metadata/v3.py b/src/zarr/core/metadata/v3.py index e17edb999c..d1420b1ddd 100644 --- a/src/zarr/core/metadata/v3.py +++ b/src/zarr/core/metadata/v3.py @@ -34,7 +34,7 @@ ) from zarr.core.config import config from zarr.core.metadata.common import parse_attributes -from zarr.errors import MetadataValidationError, NodeTypeValidationError +from zarr.errors import MetadataValidationError, NodeTypeValidationError, UnknownCodecError from zarr.registry import get_codec_class @@ -63,7 +63,11 @@ def parse_codecs(data: object) -> tuple[Codec, ...]: out += (c,) else: name_parsed, _ = parse_named_configuration(c, require_configuration=False) - out += (get_codec_class(name_parsed).from_dict(c),) + + try: + out += (get_codec_class(name_parsed).from_dict(c),) + except KeyError as e: + raise UnknownCodecError(f"Unknown codec: {e.args[0]!r}") from e return out diff --git a/src/zarr/errors.py b/src/zarr/errors.py index 867e801e18..472199ff1b 100644 --- a/src/zarr/errors.py +++ b/src/zarr/errors.py @@ -101,6 +101,14 @@ class MetadataValidationError(BaseZarrError): _msg = "Invalid value for '{}'. Expected '{}'. Got '{}'." +class UnknownCodecError(BaseZarrError): + """ + Raised when a unknown codec was used. + """ + + _msg = "{}" + + class NodeTypeValidationError(MetadataValidationError): """ Specialized exception when the node_type of the metadata document is incorrect. diff --git a/tests/test_metadata/test_v3.py b/tests/test_metadata/test_v3.py index 2093696454..4fdcce7b6b 100644 --- a/tests/test_metadata/test_v3.py +++ b/tests/test_metadata/test_v3.py @@ -17,10 +17,11 @@ from zarr.core.group import GroupMetadata, parse_node_type from zarr.core.metadata.v3 import ( ArrayV3Metadata, + parse_codecs, parse_dimension_names, parse_zarr_format, ) -from zarr.errors import MetadataValidationError, NodeTypeValidationError +from zarr.errors import MetadataValidationError, NodeTypeValidationError, UnknownCodecError if TYPE_CHECKING: from collections.abc import Sequence @@ -323,3 +324,17 @@ async def test_special_float_fill_values(fill_value: str) -> None: elif fill_value == "-Infinity": assert np.isneginf(m.fill_value) assert d["fill_value"] == "-Infinity" + + +def test_parse_codecs_unknown_codec_raises(monkeypatch: pytest.MonkeyPatch) -> None: + from collections import defaultdict + + import zarr.registry + from zarr.registry import Registry + + # to make sure the codec is always unknown (not sure if that's necessary) + monkeypatch.setattr(zarr.registry, "__codec_registries", defaultdict(Registry)) + + codecs = [{"name": "unknown"}] + with pytest.raises(UnknownCodecError): + parse_codecs(codecs)