@@ -84,8 +84,15 @@ def test_codec_pipeline() -> None:
8484 np .testing .assert_array_equal (result , expected )
8585
8686
87- @pytest .mark .parametrize ("dtype" , ["|S" , "|V" ])
88- async def test_v2_encode_decode (dtype ):
87+ @pytest .mark .parametrize (
88+ ("dtype" , "expected_dtype" , "fill_value" , "fill_value_encoding" ),
89+ [
90+ ("|S" , "|S0" , b"X" , "WA==" ),
91+ ("|V" , "|V0" , b"X" , "WA==" ),
92+ ("|V10" , "|V10" , b"X" , "WAAAAAAAAAAAAA==" ),
93+ ],
94+ )
95+ async def test_v2_encode_decode (dtype , expected_dtype , fill_value , fill_value_encoding ) -> None :
8996 with config .set (
9097 {
9198 "array.v2_default_filters.bytes" : [{"id" : "vlen-bytes" }],
@@ -95,7 +102,7 @@ async def test_v2_encode_decode(dtype):
95102 store = zarr .storage .MemoryStore ()
96103 g = zarr .group (store = store , zarr_format = 2 )
97104 g .create_array (
98- name = "foo" , shape = (3 ,), chunks = (3 ,), dtype = dtype , fill_value = b"X" , compressor = None
105+ name = "foo" , shape = (3 ,), chunks = (3 ,), dtype = dtype , fill_value = fill_value , compressor = None
99106 )
100107
101108 result = await store .get ("foo/.zarray" , zarr .core .buffer .default_buffer_prototype ())
@@ -105,9 +112,9 @@ async def test_v2_encode_decode(dtype):
105112 expected = {
106113 "chunks" : [3 ],
107114 "compressor" : None ,
108- "dtype" : f" { dtype } 0" ,
109- "fill_value" : "WA==" ,
110- "filters" : [{"id" : "vlen-bytes" }],
115+ "dtype" : expected_dtype ,
116+ "fill_value" : fill_value_encoding ,
117+ "filters" : [{"id" : "vlen-bytes" }] if dtype == "|S" else None ,
111118 "order" : "C" ,
112119 "shape" : [3 ],
113120 "zarr_format" : 2 ,
@@ -284,3 +291,25 @@ def test_default_filters_and_compressor(dtype_expected: Any) -> None:
284291 assert arr .metadata .compressor .codec_id == expected_compressor
285292 if expected_filter is not None :
286293 assert arr .metadata .filters [0 ].codec_id == expected_filter
294+
295+
296+ @pytest .mark .parametrize ("fill_value" , [None , (b"" , 0 , 0.0 )], ids = ["no_fill" , "fill" ])
297+ def test_structured_dtype_roundtrip (fill_value , tmp_path ) -> None :
298+ a = np .array (
299+ [(b"aaa" , 1 , 4.2 ), (b"bbb" , 2 , 8.4 ), (b"ccc" , 3 , 12.6 )],
300+ dtype = [("foo" , "S3" ), ("bar" , "i4" ), ("baz" , "f8" )],
301+ )
302+ array_path = tmp_path / "data.zarr"
303+ za = zarr .create (
304+ shape = (3 ,),
305+ store = array_path ,
306+ chunks = (2 ,),
307+ fill_value = fill_value ,
308+ zarr_format = 2 ,
309+ dtype = a .dtype ,
310+ )
311+ if fill_value is not None :
312+ assert (np .array ([fill_value ] * a .shape [0 ], dtype = a .dtype ) == za [:]).all ()
313+ za [...] = a
314+ za = zarr .open_array (store = array_path )
315+ assert (a == za [:]).all ()
0 commit comments