|
3 | 3 | import json |
4 | 4 | from collections.abc import Iterable, Mapping, Sequence |
5 | 5 | from dataclasses import dataclass, field, replace |
6 | | -from typing import TYPE_CHECKING, Any, Literal, NotRequired, TypedDict, TypeGuard, cast |
| 6 | +from typing import TYPE_CHECKING, Any, Final, Literal, NotRequired, TypeGuard, cast |
| 7 | + |
| 8 | +from typing_extensions import TypedDict |
7 | 9 |
|
8 | 10 | from zarr.abc.codec import ArrayArrayCodec, ArrayBytesCodec, BytesBytesCodec, Codec |
9 | 11 | from zarr.abc.metadata import Metadata |
@@ -136,10 +138,11 @@ def parse_storage_transformers(data: object) -> tuple[dict[str, JSON], ...]: |
136 | 138 | ) |
137 | 139 |
|
138 | 140 |
|
139 | | -class AllowedExtraField(TypedDict): |
| 141 | +class AllowedExtraField(TypedDict, extra_items=JSON): # type: ignore[call-arg] |
140 | 142 | """ |
141 | 143 | This class models allowed extra fields in array metadata. |
142 | | - They are ignored by Zarr Python. |
| 144 | + They must have ``must_understand`` set to ``False``, and may contain |
| 145 | + arbitrary additional JSON data. |
143 | 146 | """ |
144 | 147 |
|
145 | 148 | must_understand: Literal[False] |
@@ -411,25 +414,43 @@ def parse_chunk_grid( |
411 | 414 | raise ValueError(f"Unknown chunk grid name: {name!r}") |
412 | 415 |
|
413 | 416 |
|
414 | | -class ArrayMetadataJSON_V3(TypedDict): |
| 417 | +class ArrayMetadataJSON_V3(TypedDict, extra_items=AllowedExtraField): # type: ignore[call-arg] |
415 | 418 | """ |
416 | | - A typed dictionary model for zarr v3 metadata. |
| 419 | + A typed dictionary model for zarr v3 array metadata. |
| 420 | +
|
| 421 | + Extra keys are permitted if they conform to ``AllowedExtraField`` |
| 422 | + (i.e. they are mappings with ``must_understand: false``). |
417 | 423 | """ |
418 | 424 |
|
419 | 425 | zarr_format: Literal[3] |
420 | 426 | node_type: Literal["array"] |
421 | | - data_type: str | NamedConfig[str, Mapping[str, object]] |
| 427 | + data_type: str | NamedConfig[str, Mapping[str, JSON]] |
422 | 428 | shape: tuple[int, ...] |
423 | | - chunk_grid: NamedConfig[str, Mapping[str, object]] |
424 | | - chunk_key_encoding: NamedConfig[str, Mapping[str, object]] |
425 | | - fill_value: object |
426 | | - codecs: tuple[str | NamedConfig[str, Mapping[str, object]], ...] |
| 429 | + chunk_grid: str | NamedConfig[str, Mapping[str, JSON]] |
| 430 | + chunk_key_encoding: str | NamedConfig[str, Mapping[str, JSON]] |
| 431 | + fill_value: JSON |
| 432 | + codecs: tuple[str | NamedConfig[str, Mapping[str, JSON]], ...] |
427 | 433 | attributes: NotRequired[Mapping[str, JSON]] |
428 | | - storage_transformers: NotRequired[tuple[NamedConfig[str, Mapping[str, object]], ...]] |
429 | | - dimension_names: NotRequired[tuple[str | None]] |
430 | | - |
431 | | - |
432 | | -ARRAY_METADATA_KEYS = set(ArrayMetadataJSON_V3.__annotations__.keys()) |
| 434 | + storage_transformers: NotRequired[tuple[str | NamedConfig[str, Mapping[str, JSON]], ...]] |
| 435 | + dimension_names: NotRequired[tuple[str | None, ...]] |
| 436 | + |
| 437 | + |
| 438 | +""" |
| 439 | +The names of the fields of the array metadata document defined in the zarr V3 spec. |
| 440 | +""" |
| 441 | +ARRAY_METADATA_KEYS: Final[set[str]] = { |
| 442 | + "zarr_format", |
| 443 | + "node_type", |
| 444 | + "data_type", |
| 445 | + "shape", |
| 446 | + "chunk_grid", |
| 447 | + "chunk_key_encoding", |
| 448 | + "fill_value", |
| 449 | + "codecs", |
| 450 | + "attributes", |
| 451 | + "storage_transformers", |
| 452 | + "dimension_names", |
| 453 | +} |
433 | 454 |
|
434 | 455 |
|
435 | 456 | @dataclass(frozen=True, kw_only=True) |
@@ -617,8 +638,8 @@ def from_dict(cls, data: dict[str, JSON]) -> Self: |
617 | 638 |
|
618 | 639 | return cls( |
619 | 640 | shape=_data_typed["shape"], |
620 | | - chunk_grid=_data_typed["chunk_grid"], |
621 | | - chunk_key_encoding=_data_typed["chunk_key_encoding"], |
| 641 | + chunk_grid=_data_typed["chunk_grid"], # type: ignore[arg-type] |
| 642 | + chunk_key_encoding=_data_typed["chunk_key_encoding"], # type: ignore[arg-type] |
622 | 643 | codecs=_data_typed["codecs"], |
623 | 644 | attributes=_data_typed.get("attributes", {}), # type: ignore[arg-type] |
624 | 645 | dimension_names=_data_typed.get("dimension_names", None), |
|
0 commit comments