@@ -84,8 +84,15 @@ def test_codec_pipeline() -> None:
84
84
np .testing .assert_array_equal (result , expected )
85
85
86
86
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 :
89
96
with config .set (
90
97
{
91
98
"array.v2_default_filters.bytes" : [{"id" : "vlen-bytes" }],
@@ -95,7 +102,7 @@ async def test_v2_encode_decode(dtype):
95
102
store = zarr .storage .MemoryStore ()
96
103
g = zarr .group (store = store , zarr_format = 2 )
97
104
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
99
106
)
100
107
101
108
result = await store .get ("foo/.zarray" , zarr .core .buffer .default_buffer_prototype ())
@@ -105,9 +112,9 @@ async def test_v2_encode_decode(dtype):
105
112
expected = {
106
113
"chunks" : [3 ],
107
114
"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 ,
111
118
"order" : "C" ,
112
119
"shape" : [3 ],
113
120
"zarr_format" : 2 ,
@@ -284,3 +291,25 @@ def test_default_filters_and_compressor(dtype_expected: Any) -> None:
284
291
assert arr .metadata .compressor .codec_id == expected_compressor
285
292
if expected_filter is not None :
286
293
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