diff --git a/src/zarr/config.py b/src/zarr/config.py index 7c5b48a16..e711a98cb 100644 --- a/src/zarr/config.py +++ b/src/zarr/config.py @@ -11,6 +11,7 @@ "array": {"order": "C"}, "async": {"concurrency": None, "timeout": None}, "codec_pipeline": {"batch_size": 1}, + "json_indent": 2, } ], ) diff --git a/src/zarr/group.py b/src/zarr/group.py index 4bb4b6b4d..e6e2ac183 100644 --- a/src/zarr/group.py +++ b/src/zarr/group.py @@ -25,6 +25,7 @@ ChunkCoords, ZarrFormat, ) +from zarr.config import config from zarr.store import StoreLike, StorePath, make_store_path from zarr.sync import SyncMixin, sync @@ -79,14 +80,21 @@ class GroupMetadata(Metadata): node_type: Literal["group"] = field(default="group", init=False) def to_buffer_dict(self) -> dict[str, Buffer]: + json_indent = config.get("json_indent") if self.zarr_format == 3: - return {ZARR_JSON: Buffer.from_bytes(json.dumps(self.to_dict()).encode())} + return { + ZARR_JSON: Buffer.from_bytes( + json.dumps(self.to_dict(), indent=json_indent).encode() + ) + } else: return { ZGROUP_JSON: Buffer.from_bytes( - json.dumps({"zarr_format": self.zarr_format}).encode() + json.dumps({"zarr_format": self.zarr_format}, indent=json_indent).encode() + ), + ZATTRS_JSON: Buffer.from_bytes( + json.dumps(self.attributes, indent=json_indent).encode() ), - ZATTRS_JSON: Buffer.from_bytes(json.dumps(self.attributes).encode()), } def __init__(self, attributes: dict[str, Any] | None = None, zarr_format: ZarrFormat = 3): diff --git a/src/zarr/metadata.py b/src/zarr/metadata.py index 8329bd920..c6a71c00b 100644 --- a/src/zarr/metadata.py +++ b/src/zarr/metadata.py @@ -16,6 +16,7 @@ from zarr.chunk_grids import ChunkGrid, RegularChunkGrid from zarr.chunk_key_encodings import ChunkKeyEncoding, parse_separator from zarr.codecs._v2 import V2Compressor, V2Filters +from zarr.config import config if TYPE_CHECKING: from typing_extensions import Self @@ -272,8 +273,11 @@ def _json_convert(o: np.dtype[Any] | Enum | Codec) -> str | dict[str, Any]: return config raise TypeError + json_indent = config.get("json_indent") return { - ZARR_JSON: Buffer.from_bytes(json.dumps(self.to_dict(), default=_json_convert).encode()) + ZARR_JSON: Buffer.from_bytes( + json.dumps(self.to_dict(), default=_json_convert, indent=json_indent).encode() + ) } @classmethod @@ -394,9 +398,12 @@ def _json_convert( assert isinstance(zarray_dict, dict) zattrs_dict = zarray_dict.pop("attributes", {}) assert isinstance(zattrs_dict, dict) + json_indent = config.get("json_indent") return { - ZARRAY_JSON: Buffer.from_bytes(json.dumps(zarray_dict, default=_json_convert).encode()), - ZATTRS_JSON: Buffer.from_bytes(json.dumps(zattrs_dict).encode()), + ZARRAY_JSON: Buffer.from_bytes( + json.dumps(zarray_dict, default=_json_convert, indent=json_indent).encode() + ), + ZATTRS_JSON: Buffer.from_bytes(json.dumps(zattrs_dict, indent=json_indent).encode()), } @classmethod diff --git a/tests/v3/test_config.py b/tests/v3/test_config.py index aed9775d1..684ab0dfc 100644 --- a/tests/v3/test_config.py +++ b/tests/v3/test_config.py @@ -1,19 +1,32 @@ +from typing import Any + +import pytest + from zarr.config import config -def test_config_defaults_set(): +def test_config_defaults_set() -> None: # regression test for available defaults assert config.defaults == [ { "array": {"order": "C"}, "async": {"concurrency": None, "timeout": None}, "codec_pipeline": {"batch_size": 1}, + "json_indent": 2, } ] assert config.get("array.order") == "C" + assert config.get("async.concurrency") is None + assert config.get("async.timeout") is None + assert config.get("codec_pipeline.batch_size") == 1 + assert config.get("json_indent") == 2 -def test_config_defaults_can_be_overridden(): - assert config.get("array.order") == "C" - with config.set({"array.order": "F"}): - assert config.get("array.order") == "F" +@pytest.mark.parametrize( + "key, old_val, new_val", + [("array.order", "C", "F"), ("async.concurrency", None, 10), ("json_indent", 2, 0)], +) +def test_config_defaults_can_be_overridden(key: str, old_val: Any, new_val: Any) -> None: + assert config.get(key) == old_val + with config.set({key: new_val}): + assert config.get(key) == new_val