2222 bytes_to_json ,
2323 check_json_str ,
2424)
25+ from zarr .core .dtype .npy .subarray import Subarray
2526from zarr .core .dtype .wrapper import TBaseDType , TBaseScalar , ZDType
2627
2728if TYPE_CHECKING :
@@ -34,9 +35,11 @@ class StructuredJSON_V2(DTypeConfig_V2[StructuredName_V2, None]):
3435 """
3536 A wrapper around the JSON representation of the ``Structured`` data type in Zarr V2.
3637
37- The ``name`` field is a sequence of sequences, where each inner sequence has two values:
38- the field name and the data type name for that field (which could be another sequence).
39- The data type names are strings, and the object codec ID is always None.
38+ The ``name`` field is a sequence of sequences, where each inner sequence has 2 or 3 values:
39+ - First value: field name
40+ - Second value: data type name (which could be another sequence for nested structured dtypes)
41+ - Third value (optional): shape of the field (for subarray dtypes)
42+ The object codec ID is always None.
4043
4144 References
4245 ----------
@@ -49,7 +52,7 @@ class StructuredJSON_V2(DTypeConfig_V2[StructuredName_V2, None]):
4952 {
5053 "name": [
5154 ["f0", "<m8[10s]"],
52- ["f1", "<m8[10s]" ],
55+ ["f1", "int32", [2, 2] ],
5356 ],
5457 "object_codec_id": None
5558 }
@@ -252,17 +255,33 @@ def _from_json_v2(cls, data: DTypeJSON) -> Self:
252255 # structured dtypes are constructed directly from a list of lists
253256 # note that we do not handle the object codec here! this will prevent structured
254257 # dtypes from containing object dtypes.
255- return cls (
256- fields = tuple ( # type: ignore[misc]
257- ( # type: ignore[misc]
258- f_name ,
259- get_data_type_from_json (
260- {"name" : f_dtype , "object_codec_id" : None }, zarr_format = 2
261- ),
262- )
263- for f_name , f_dtype in data ["name" ]
258+ fields = []
259+ name = data ["name" ]
260+ for tpl in name :
261+ f_name = tpl [0 ]
262+ if not isinstance (f_name , str ):
263+ msg = f"Invalid field name. Got { f_name !r} , expected a string."
264+ raise DataTypeValidationError (msg )
265+
266+ f_dtype = tpl [1 ]
267+ subdtype = get_data_type_from_json (
268+ {"name" : f_dtype , "object_codec_id" : None }, zarr_format = 2
264269 )
265- )
270+
271+ if len (tpl ) == 3 :
272+ f_shape = cast ("tuple[int]" , tuple (tpl [2 ]))
273+ if not all (isinstance (dim , int ) for dim in f_shape ):
274+ msg = f"Invalid shape for field { f_name !r} . Got { f_shape !r} , expected a sequence of integers."
275+ raise DataTypeValidationError (msg )
276+ subdtype = Subarray (
277+ subdtype = subdtype ,
278+ shape = f_shape ,
279+ )
280+
281+ fields .append ((f_name , subdtype ))
282+
283+ return cls (fields = tuple (fields ))
284+
266285 msg = f"Invalid JSON representation of { cls .__name__ } . Got { data !r} , expected a JSON array of arrays"
267286 raise DataTypeValidationError (msg )
268287
@@ -309,11 +328,23 @@ def to_json(self, zarr_format: ZarrFormat) -> StructuredJSON_V2 | StructuredJSON
309328 If the zarr_format is not 2 or 3.
310329 """
311330 if zarr_format == 2 :
312- fields = [
313- [f_name , f_dtype .to_json (zarr_format = zarr_format )["name" ]]
314- for f_name , f_dtype in self .fields
315- ]
316- return {"name" : fields , "object_codec_id" : None }
331+ fields = []
332+ for f_name , f_dtype in self .fields :
333+ if isinstance (f_dtype , Subarray ):
334+ fields .append (
335+ [
336+ f_name ,
337+ f_dtype .subdtype .to_json (zarr_format = zarr_format )["name" ],
338+ list (f_dtype .shape ),
339+ ]
340+ )
341+ else :
342+ fields .append ([f_name , f_dtype .to_json (zarr_format = zarr_format )["name" ]])
343+ dct = {
344+ "name" : fields ,
345+ "object_codec_id" : None ,
346+ }
347+ return cast ("StructuredJSON_V2" , dct )
317348 elif zarr_format == 3 :
318349 v3_unstable_dtype_warning (self )
319350 fields = [
@@ -415,7 +446,6 @@ def default_scalar(self) -> np.void:
415446 The default scalar value, which is the scalar representation of 0
416447 cast to this structured data type.
417448 """
418-
419449 return self ._cast_scalar_unchecked (0 )
420450
421451 def from_json_scalar (self , data : JSON , * , zarr_format : ZarrFormat ) -> np .void :
0 commit comments