diff --git a/changes/3535.bugfix.md b/changes/3535.bugfix.md new file mode 100644 index 0000000000..7e1ce8f834 --- /dev/null +++ b/changes/3535.bugfix.md @@ -0,0 +1,2 @@ +Fixed a bug where the `"consolidated_metadata"` key was written to metadata documents even when +consolidated metadata was not used, resulting in invalid metadata documents. \ No newline at end of file diff --git a/src/zarr/core/group.py b/src/zarr/core/group.py index 492211d097..26aed4fd60 100644 --- a/src/zarr/core/group.py +++ b/src/zarr/core/group.py @@ -432,8 +432,11 @@ def from_dict(cls, data: dict[str, Any]) -> GroupMetadata: def to_dict(self) -> dict[str, Any]: result = asdict(replace(self, consolidated_metadata=None)) - if self.consolidated_metadata: + if self.consolidated_metadata is not None: result["consolidated_metadata"] = self.consolidated_metadata.to_dict() + else: + # Leave consolidated metadata unset if it's None + result.pop("consolidated_metadata") return result diff --git a/tests/test_metadata/test_v3.py b/tests/test_metadata/test_v3.py index 1405bf533b..f2c672a14e 100644 --- a/tests/test_metadata/test_v3.py +++ b/tests/test_metadata/test_v3.py @@ -7,6 +7,7 @@ import numpy as np import pytest +from zarr import consolidate_metadata, create_group from zarr.codecs.bytes import BytesCodec from zarr.core.buffer import default_buffer_prototype from zarr.core.chunk_key_encodings import DefaultChunkKeyEncoding, V2ChunkKeyEncoding @@ -21,7 +22,12 @@ parse_dimension_names, parse_zarr_format, ) -from zarr.errors import MetadataValidationError, NodeTypeValidationError, UnknownCodecError +from zarr.errors import ( + MetadataValidationError, + NodeTypeValidationError, + UnknownCodecError, + ZarrUserWarning, +) if TYPE_CHECKING: from collections.abc import Sequence @@ -338,3 +344,52 @@ def test_parse_codecs_unknown_codec_raises(monkeypatch: pytest.MonkeyPatch) -> N codecs = [{"name": "unknown"}] with pytest.raises(UnknownCodecError): parse_codecs(codecs) + + +@pytest.mark.parametrize("use_consolidated", [True, False]) +@pytest.mark.parametrize("attributes", [None, {"foo": "bar"}]) +def test_group_to_dict(use_consolidated: bool, attributes: None | dict[str, Any]) -> None: + """ + Test that the output of GroupMetadata.to_dict() is what we expect + """ + store: dict[str, object] = {} + if attributes is None: + expect_attributes = {} + else: + expect_attributes = attributes + + group = create_group(store, attributes=attributes, zarr_format=3) + group.create_group("foo") + if use_consolidated: + with pytest.warns( + ZarrUserWarning, + match="Consolidated metadata is currently not part in the Zarr format 3 specification.", + ): + group = consolidate_metadata(store) + meta = group.metadata + expect = { + "node_type": "group", + "zarr_format": 3, + "consolidated_metadata": { + "kind": "inline", + "must_understand": False, + "metadata": { + "foo": { + "attributes": {}, + "zarr_format": 3, + "node_type": "group", + "consolidated_metadata": { + "kind": "inline", + "metadata": {}, + "must_understand": False, + }, + } + }, + }, + "attributes": expect_attributes, + } + else: + meta = group.metadata + expect = {"node_type": "group", "zarr_format": 3, "attributes": expect_attributes} + + assert meta.to_dict() == expect