|
1 | 1 | # zarr-metadata |
2 | 2 |
|
3 | | -Python type definitions for Zarr v2 and v3 metadata. |
| 3 | +Python types, models, and validators for Zarr v2 and v3 metadata. |
4 | 4 |
|
5 | 5 | ## What this is |
6 | 6 |
|
7 | | -A typed-data package: `TypedDict` definitions and `Literal` aliases for the |
8 | | -JSON shapes specified by the [Zarr v2](https://zarr-specs.readthedocs.io/en/latest/v2/v2.0.html) |
9 | | -and [Zarr v3](https://zarr-specs.readthedocs.io/en/latest/v3/core/index.html) |
10 | | -specifications, plus types for [`zarr-extensions`](https://github.com/zarr-developers/zarr-extensions/) |
11 | | -and a few widely-used-but-unspecified entities (e.g. consolidated metadata). |
| 7 | +Two layers and an optional integration: |
| 8 | + |
| 9 | +- **Typed JSON shapes**: `TypedDict` definitions and `Literal` aliases for the |
| 10 | + JSON documents specified by the [Zarr v2](https://zarr-specs.readthedocs.io/en/latest/v2/v2.0.html) |
| 11 | + and [Zarr v3](https://zarr-specs.readthedocs.io/en/latest/v3/core/index.html) |
| 12 | + specifications, plus types for [`zarr-extensions`](https://github.com/zarr-developers/zarr-extensions/) |
| 13 | + and a few widely-used-but-unspecified entities (e.g. consolidated metadata). |
| 14 | +- **Document models** (`zarr_metadata.model`): canonical frozen-dataclass |
| 15 | + models of whole metadata documents, with structural validators, loc-aware |
| 16 | + parsers, and store-key (de)serialization. A document produced by `to_json` |
| 17 | + shares no mutable state with the model that produced it. |
| 18 | +- **Optional Pydantic integration** (`zarr_metadata.pydantic`, requires |
| 19 | + Pydantic 2.13 or newer): each model as a Pydantic field type that validates |
| 20 | + raw documents through the same strict parser. |
12 | 21 |
|
13 | 22 | ## What this is for |
14 | 23 |
|
15 | | -These types describe the JSON shape of Zarr metadata. They are |
16 | | -intended for libraries that **read, write, validate, or transform** |
17 | | -Zarr metadata. Pair them with a runtime validator like |
18 | | -[pydantic](https://docs.pydantic.dev/) to check JSON loaded from disk: |
| 24 | +The public `TypedDict` definitions describe the static JSON shape of Zarr |
| 25 | +metadata. For strict, loc-aware validation of JSON loaded from disk, use the |
| 26 | +model parser: |
19 | 27 |
|
20 | 28 | ```python |
21 | 29 | import json |
22 | | -from pydantic import TypeAdapter |
23 | | -from zarr_metadata.v3.array import ArrayMetadataV3 |
| 30 | +from zarr_metadata.model import ZarrV3ArrayMetadata |
24 | 31 |
|
25 | 32 | with open("zarr.json", "rb") as f: |
26 | 33 | raw = json.load(f) |
27 | 34 |
|
28 | | -metadata = TypeAdapter(ArrayMetadataV3).validate_python(raw) |
| 35 | +metadata = ZarrV3ArrayMetadata.from_json(raw) |
| 36 | +``` |
| 37 | + |
| 38 | +The optional Pydantic integration delegates raw input to the same strict |
| 39 | +parser and returns the same normalized model class: |
| 40 | + |
| 41 | +```python |
| 42 | +from pydantic import TypeAdapter |
| 43 | +import zarr_metadata.pydantic as zmp |
| 44 | + |
| 45 | +metadata = TypeAdapter(zmp.ZarrV3ArrayMetadata).validate_python(raw) |
| 46 | +encoded = metadata.to_key_value()["zarr.json"] |
29 | 47 | ``` |
30 | 48 |
|
31 | | -## What this is *not* |
| 49 | +A bare `TypeAdapter` over a public document `TypedDict` is a coercive shape |
| 50 | +adapter, not a Zarr conformance validator; it may coerce values or discard |
| 51 | +members that the strict model parser rejects. |
| 52 | + |
| 53 | +## Validation boundary |
32 | 54 |
|
33 | | -- Not a parser or builder. There are no `make_array_metadata(...)` factories — |
34 | | - that surface belongs to consumer libraries. |
35 | | -- Not a runtime validator on its own. Pair with `pydantic`, `msgspec`, or |
36 | | - similar to enforce shapes at decode time. |
| 55 | +The model validators enforce the declared document structure and a small set |
| 56 | +of context-free consistency rules, including fixed format literals, finite |
| 57 | +JSON numbers, non-negative dimensions, non-empty v3 codec pipelines, and one |
| 58 | +`dimension_names` entry per array dimension. They do not interpret extension |
| 59 | +names or configurations, resolve codec pipelines, or decide whether a data |
| 60 | +type, chunk grid, codec, or storage transformer is supported. Those decisions |
| 61 | +belong to consumer implementations. |
37 | 62 |
|
38 | | -Even with a runtime validator, these types only describe **structural** |
39 | | -shape — they will not flag *semantically* invalid metadata, like a 3D v3 |
40 | | -array whose `dimension_names` has 4 entries instead of 3. That's a job |
41 | | -for downstream validator routines. |
| 63 | +The Pydantic integration's generated JSON Schemas express independently |
| 64 | +checkable document structure and field constraints, but they are not a |
| 65 | +replacement for runtime model validation. Standard JSON Schema treats a |
| 66 | +mathematically integral number such as `1.0` as an integer, while the runtime |
| 67 | +boundary requires Python `int` values, and it cannot express arbitrary |
| 68 | +same-length relations such as `dimension_names` versus `shape` or v2 `chunks` |
| 69 | +versus `shape`. Consumers should run the model parser after schema validation. |
42 | 70 |
|
43 | 71 | ## Scope |
44 | 72 |
|
45 | 73 | At minimum, this library supports what Zarr-Python needs: the complete |
46 | 74 | Zarr v2 and v3 specs, consolidated metadata, and a subset of the metadata |
47 | 75 | defined in `zarr-extensions`. We are generally open to contributions that |
48 | | -add types for Zarr metadata with a published spec. |
| 76 | +add types, models, or structural validation for Zarr metadata with a |
| 77 | +published spec. |
| 78 | + |
| 79 | +Runtime array behavior is out of scope: nothing here encodes or decodes |
| 80 | +chunks, resolves codec or data type names to implementations, or performs |
| 81 | +store I/O. The models begin and end at the metadata documents themselves — |
| 82 | +`from_key_value` / `to_key_value` map documents to store keys and bytes, |
| 83 | +and everything past that belongs to consumer libraries. |
49 | 84 |
|
50 | 85 | ## Releasing |
51 | 86 |
|
|
0 commit comments