22
22
23
23
from typing_extensions import Self
24
24
25
+ import numcodecs .abc
25
26
26
27
from zarr .common import (
27
28
JSON ,
@@ -168,15 +169,15 @@ class ArrayV3Metadata(ArrayMetadata):
168
169
def __init__ (
169
170
self ,
170
171
* ,
171
- shape ,
172
- data_type ,
173
- chunk_grid ,
174
- chunk_key_encoding ,
175
- fill_value ,
176
- codecs ,
177
- attributes ,
178
- dimension_names ,
179
- ):
172
+ shape : Iterable [ int ] ,
173
+ data_type : npt . DTypeLike ,
174
+ chunk_grid : dict [ str , JSON ] | ChunkGrid ,
175
+ chunk_key_encoding : dict [ str , JSON ] | ChunkKeyEncoding ,
176
+ fill_value : Any ,
177
+ codecs : Iterable [ Codec | JSON ] ,
178
+ attributes : None | dict [ str , JSON ] ,
179
+ dimension_names : None | Iterable [ str ] ,
180
+ ) -> None :
180
181
"""
181
182
Because the class is a frozen dataclass, we set attributes using object.__setattr__
182
183
"""
@@ -249,14 +250,14 @@ def encode_chunk_key(self, chunk_coords: ChunkCoords) -> str:
249
250
return self .chunk_key_encoding .encode_chunk_key (chunk_coords )
250
251
251
252
def to_buffer_dict (self ) -> dict [str , Buffer ]:
252
- def _json_convert (o ) :
253
+ def _json_convert (o : np . dtype [ Any ] | Enum | Codec ) -> str | dict [ str , Any ] :
253
254
if isinstance (o , np .dtype ):
254
255
return str (o )
255
256
if isinstance (o , Enum ):
256
257
return o .name
257
258
# this serializes numcodecs compressors
258
259
# todo: implement to_dict for codecs
259
- elif hasattr (o , "get_config" ):
260
+ elif isinstance (o , numcodecs . abc . Codec ):
260
261
return o .get_config ()
261
262
raise TypeError
262
263
@@ -271,9 +272,10 @@ def from_dict(cls, data: dict[str, JSON]) -> ArrayV3Metadata:
271
272
# check that the node_type attribute is correct
272
273
_ = parse_node_type_array (data .pop ("node_type" ))
273
274
274
- dimension_names = data .pop ("dimension_names" , None )
275
+ data [ " dimension_names" ] = data .pop ("dimension_names" , None )
275
276
276
- return cls (** data , dimension_names = dimension_names )
277
+ # TODO: Remove the ignores and use a TypedDict to type `data`
278
+ return cls (** data ) # type: ignore[arg-type]
277
279
278
280
def to_dict (self ) -> dict [str , Any ]:
279
281
out_dict = super ().to_dict ()
@@ -367,7 +369,9 @@ def codec_pipeline(self) -> CodecPipeline:
367
369
)
368
370
369
371
def to_buffer_dict (self ) -> dict [str , Buffer ]:
370
- def _json_convert (o ):
372
+ def _json_convert (
373
+ o : np .dtype [Any ],
374
+ ) -> str | list [tuple [str , str ] | tuple [str , str , tuple [int , ...]]]:
371
375
if isinstance (o , np .dtype ):
372
376
if o .fields is None :
373
377
return o .str
@@ -399,7 +403,7 @@ def to_dict(self) -> JSON:
399
403
zarray_dict ["chunks" ] = self .chunk_grid .chunk_shape
400
404
401
405
_ = zarray_dict .pop ("data_type" )
402
- zarray_dict ["dtype" ] = self .data_type
406
+ zarray_dict ["dtype" ] = self .data_type . str
403
407
404
408
return zarray_dict
405
409
@@ -422,7 +426,7 @@ def update_attributes(self, attributes: dict[str, JSON]) -> Self:
422
426
return replace (self , attributes = attributes )
423
427
424
428
425
- def parse_dimension_names (data : Any ) -> tuple [str , ...] | None :
429
+ def parse_dimension_names (data : None | Iterable [ str ] ) -> tuple [str , ...] | None :
426
430
if data is None :
427
431
return data
428
432
if isinstance (data , Iterable ) and all ([isinstance (x , str ) for x in data ]):
@@ -432,12 +436,11 @@ def parse_dimension_names(data: Any) -> tuple[str, ...] | None:
432
436
433
437
434
438
# todo: real validation
435
- def parse_attributes (data : Any ) -> dict [str , JSON ]:
439
+ def parse_attributes (data : None | dict [ str , JSON ] ) -> dict [str , JSON ]:
436
440
if data is None :
437
441
return {}
438
442
439
- data_json = cast (dict [str , JSON ], data )
440
- return data_json
443
+ return data
441
444
442
445
443
446
# todo: move to its own module and drop _v3 suffix
0 commit comments