From 4a2900164908d019329eca677912dbab5569f3a0 Mon Sep 17 00:00:00 2001 From: Davis Vann Bennett Date: Fri, 9 Oct 2026 17:35:35 +0200 Subject: [PATCH] feat: export the metadata classes and ArraySpec from public modules Array.metadata and Group.metadata return ArrayV2Metadata, ArrayV3Metadata, and GroupMetadata, and every zarr.abc.codec method takes an ArraySpec, but all of them were importable only from zarr.core. Export them from zarr.metadata and zarr.abc.codec, and document a narrow member list for each so their internals stay free to change. Assisted-by: ClaudeCode:claude-opus-5-5 --- changes/4502.feature.md | 1 + docs/api/zarr/abc/codec.md | 18 ++++++++++ docs/api/zarr/metadata.md | 66 +++++++++++++++++++++++++++++++++++ src/zarr/abc/codec.py | 3 +- src/zarr/metadata/__init__.py | 18 ++++++++++ tests/test_public_exports.py | 45 ++++++++++++++++++++++++ 6 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 changes/4502.feature.md create mode 100644 tests/test_public_exports.py diff --git a/changes/4502.feature.md b/changes/4502.feature.md new file mode 100644 index 0000000000..0cd1108349 --- /dev/null +++ b/changes/4502.feature.md @@ -0,0 +1 @@ +Added public import paths for the metadata classes that `Array.metadata` and `Group.metadata` return: `zarr.metadata.ArrayV2Metadata`, `ArrayV3Metadata`, `ArrayMetadata`, `GroupMetadata`, and `ConsolidatedMetadata`. Added `zarr.abc.codec.ArraySpec`, the chunk description passed to codec methods. The API reference lists the members of each class that are public; construct the metadata classes with `from_dict`. diff --git a/docs/api/zarr/abc/codec.md b/docs/api/zarr/abc/codec.md index d4eaecabe9..619891591c 100644 --- a/docs/api/zarr/abc/codec.md +++ b/docs/api/zarr/abc/codec.md @@ -3,3 +3,21 @@ title: codec --- ::: zarr.abc.codec + options: + filters: + - "!^_[^_]" + - "!^ArraySpec$" + +Codecs receive an `ArraySpec` describing the chunk they encode or decode. The members +listed below are its public API. Its other attributes and its constructor may change +without a deprecation cycle. + +::: zarr.abc.codec.ArraySpec + options: + members: + - shape + - dtype + - fill_value + - ndim + - order + - prototype diff --git a/docs/api/zarr/metadata.md b/docs/api/zarr/metadata.md index 12eb909086..0d5128078b 100644 --- a/docs/api/zarr/metadata.md +++ b/docs/api/zarr/metadata.md @@ -3,4 +3,70 @@ title: metadata --- ::: zarr.metadata + options: + members: false + +The members listed for each class below are its public API. Other attributes and +methods, and the class constructors, may change without a deprecation cycle; build +these objects with `from_dict`. + +::: zarr.metadata.ArrayMetadata + +::: zarr.metadata.ArrayV3Metadata + options: + members: + - shape + - data_type + - dtype + - ndim + - chunks + - shards + - fill_value + - codecs + - attributes + - dimension_names + - storage_transformers + - zarr_format + - node_type + - from_dict + - to_dict + +::: zarr.metadata.ArrayV2Metadata + options: + members: + - shape + - chunks + - shards + - dtype + - ndim + - fill_value + - order + - filters + - compressor + - dimension_separator + - attributes + - zarr_format + - from_dict + - to_dict + +::: zarr.metadata.GroupMetadata + options: + members: + - attributes + - zarr_format + - node_type + - consolidated_metadata + - from_dict + - to_dict + +::: zarr.metadata.ConsolidatedMetadata + options: + members: + - metadata + - flattened_metadata + - kind + - must_understand + - from_dict + - to_dict + ::: zarr.metadata.migrate_v3 diff --git a/src/zarr/abc/codec.py b/src/zarr/abc/codec.py index c5e753d120..a2c4d97e0a 100644 --- a/src/zarr/abc/codec.py +++ b/src/zarr/abc/codec.py @@ -7,6 +7,7 @@ from typing_extensions import ReadOnly, TypedDict from zarr.abc.metadata import Metadata +from zarr.core.array_spec import ArraySpec from zarr.core.buffer import Buffer, NDBuffer from zarr.core.common import NamedConfig, concurrent_map from zarr.core.config import config @@ -16,7 +17,6 @@ from typing import Self from zarr.abc.store import ByteGetter, ByteSetter, Store - from zarr.core.array_spec import ArraySpec from zarr.core.dtype.wrapper import TBaseDType, TBaseScalar, ZDType from zarr.core.indexing import SelectorTuple from zarr.core.metadata import ArrayMetadata @@ -27,6 +27,7 @@ "ArrayBytesCodec", "ArrayBytesCodecPartialDecodeMixin", "ArrayBytesCodecPartialEncodeMixin", + "ArraySpec", "BaseCodec", "BytesBytesCodec", "CodecInput", diff --git a/src/zarr/metadata/__init__.py b/src/zarr/metadata/__init__.py index e69de29bb2..d63afa0c10 100644 --- a/src/zarr/metadata/__init__.py +++ b/src/zarr/metadata/__init__.py @@ -0,0 +1,18 @@ +"""Models of the metadata documents that describe Zarr arrays and groups. + +`zarr.Array.metadata` is an `ArrayV2Metadata` or an `ArrayV3Metadata`, and +`zarr.Group.metadata` is a `GroupMetadata`. Construct these objects with `from_dict`. +""" + +from zarr.core.group import ConsolidatedMetadata, GroupMetadata +from zarr.core.metadata import ArrayMetadata +from zarr.core.metadata.v2 import ArrayV2Metadata +from zarr.core.metadata.v3 import ArrayV3Metadata + +__all__ = [ + "ArrayMetadata", + "ArrayV2Metadata", + "ArrayV3Metadata", + "ConsolidatedMetadata", + "GroupMetadata", +] diff --git a/tests/test_public_exports.py b/tests/test_public_exports.py new file mode 100644 index 0000000000..a842f5e137 --- /dev/null +++ b/tests/test_public_exports.py @@ -0,0 +1,45 @@ +"""Public import paths for types that the public API returns or passes to extensions.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + +import pytest + +import zarr.abc.codec +import zarr.metadata +from zarr.core.array_spec import ArraySpec +from zarr.core.group import ConsolidatedMetadata, GroupMetadata +from zarr.core.metadata import ArrayMetadata +from zarr.core.metadata.v2 import ArrayV2Metadata +from zarr.core.metadata.v3 import ArrayV3Metadata + +if TYPE_CHECKING: + from zarr.types import ZarrFormat + + +@pytest.mark.parametrize( + ("public", "private"), + [ + (zarr.metadata.ArrayMetadata, ArrayMetadata), + (zarr.metadata.ArrayV2Metadata, ArrayV2Metadata), + (zarr.metadata.ArrayV3Metadata, ArrayV3Metadata), + (zarr.metadata.ConsolidatedMetadata, ConsolidatedMetadata), + (zarr.metadata.GroupMetadata, GroupMetadata), + (zarr.abc.codec.ArraySpec, ArraySpec), + ], +) +def test_public_path_is_the_implementation(public: Any, private: Any) -> None: + """Each public name is the object zarr itself uses, so isinstance checks agree.""" + assert public is private + + +@pytest.mark.parametrize("zarr_format", [2, 3]) +def test_array_and_group_metadata_types(zarr_format: ZarrFormat) -> None: + """The metadata of arrays and groups is an instance of a public metadata type.""" + store: dict[str, Any] = {} + group = zarr.group(store=store, zarr_format=zarr_format) + array = group.create_array("a", shape=(2,), dtype="i4") + expected = zarr.metadata.ArrayV2Metadata if zarr_format == 2 else zarr.metadata.ArrayV3Metadata + assert isinstance(array.metadata, expected) + assert isinstance(group.metadata, zarr.metadata.GroupMetadata)