|
2 | 2 |
|
3 | 3 | from abc import abstractmethod |
4 | 4 | from collections.abc import Mapping |
5 | | -from typing import TYPE_CHECKING, Generic, TypeGuard, TypeVar |
| 5 | +from typing import ( |
| 6 | + TYPE_CHECKING, |
| 7 | + Generic, |
| 8 | + Literal, |
| 9 | + TypedDict, |
| 10 | + TypeVar, |
| 11 | + overload, |
| 12 | +) |
6 | 13 |
|
7 | | -from typing_extensions import ReadOnly, TypedDict |
| 14 | +from typing_extensions import ReadOnly |
8 | 15 |
|
9 | 16 | from zarr.abc.metadata import Metadata |
10 | 17 | from zarr.core.buffer import Buffer, NDBuffer |
11 | | -from zarr.core.common import ChunkCoords, NamedConfig, concurrent_map |
| 18 | +from zarr.core.common import ChunkCoords, NamedConfig, ZarrFormat, concurrent_map |
12 | 19 | from zarr.core.config import config |
13 | 20 |
|
14 | 21 | if TYPE_CHECKING: |
|
41 | 48 |
|
42 | 49 |
|
43 | 50 | class CodecJSON_V2(TypedDict, Generic[TName]): |
44 | | - """The JSON representation of a codec for Zarr V2""" |
45 | | - |
46 | 51 | id: ReadOnly[TName] |
47 | 52 |
|
48 | 53 |
|
49 | | -def _check_codecjson_v2(data: object) -> TypeGuard[CodecJSON_V2[str]]: |
50 | | - return isinstance(data, Mapping) and "id" in data and isinstance(data["id"], str) |
51 | | - |
| 54 | +CodecConfig_V3 = NamedConfig[str, Mapping[str, object]] |
52 | 55 |
|
53 | | -CodecJSON_V3 = str | NamedConfig[str, Mapping[str, object]] |
54 | | -"""The JSON representation of a codec for Zarr V3.""" |
| 56 | +CodecJSON_V3 = str | CodecConfig_V3 |
55 | 57 |
|
56 | | -# The widest type we will *accept* for a codec JSON |
| 58 | +# The widest type we will accept for a codec JSON |
57 | 59 | # This covers v2 and v3 |
58 | 60 | CodecJSON = str | Mapping[str, object] |
59 | | -"""The widest type of JSON-like input that could specify a codec.""" |
60 | 61 |
|
61 | 62 |
|
62 | 63 | class BaseCodec(Metadata, Generic[CodecInput, CodecOutput]): |
@@ -181,6 +182,34 @@ async def encode( |
181 | 182 | """ |
182 | 183 | return await _batching_helper(self._encode_single, chunks_and_specs) |
183 | 184 |
|
| 185 | + @overload |
| 186 | + def to_json(self, zarr_format: Literal[2]) -> CodecJSON_V2[str]: ... |
| 187 | + @overload |
| 188 | + def to_json(self, zarr_format: Literal[3]) -> NamedConfig[str, Mapping[str, object]]: ... |
| 189 | + |
| 190 | + def to_json( |
| 191 | + self, zarr_format: ZarrFormat |
| 192 | + ) -> CodecJSON_V2[str] | NamedConfig[str, Mapping[str, object]]: |
| 193 | + raise NotImplementedError |
| 194 | + |
| 195 | + @classmethod |
| 196 | + def _from_json_v2(cls, data: CodecJSON) -> Self: |
| 197 | + raise NotImplementedError |
| 198 | + |
| 199 | + @classmethod |
| 200 | + def _from_json_v3(cls, data: CodecJSON) -> Self: |
| 201 | + raise NotImplementedError |
| 202 | + |
| 203 | + @classmethod |
| 204 | + def from_json(cls, data: CodecJSON, zarr_format: ZarrFormat) -> Self: |
| 205 | + if zarr_format == 2: |
| 206 | + return cls._from_json_v2(data) |
| 207 | + elif zarr_format == 3: |
| 208 | + return cls._from_json_v3(data) |
| 209 | + raise ValueError( |
| 210 | + f"Unsupported Zarr format {zarr_format}. Expected 2 or 3." |
| 211 | + ) # pragma: no cover |
| 212 | + |
184 | 213 |
|
185 | 214 | class ArrayArrayCodec(BaseCodec[NDBuffer, NDBuffer]): |
186 | 215 | """Base class for array-to-array codecs.""" |
@@ -471,3 +500,7 @@ async def wrap(chunk: CodecInput | None, chunk_spec: ArraySpec) -> CodecOutput | |
471 | 500 | return await func(chunk, chunk_spec) |
472 | 501 |
|
473 | 502 | return wrap |
| 503 | + |
| 504 | + |
| 505 | +# Raised when a codec JSON data is invalid |
| 506 | +class CodecValidationError(ValueError): ... |
0 commit comments