1
1
import sys
2
- from typing import Any
2
+ from typing import Any , Literal
3
3
4
4
import hypothesis .extra .numpy as npst
5
5
import hypothesis .strategies as st
8
8
from hypothesis .strategies import SearchStrategy
9
9
10
10
import zarr
11
- from zarr .abc .store import RangeByteRequest
11
+ from zarr .abc .store import RangeByteRequest , Store
12
+ from zarr .codecs .bytes import BytesCodec
12
13
from zarr .core .array import Array
14
+ from zarr .core .chunk_grids import RegularChunkGrid
15
+ from zarr .core .chunk_key_encodings import DefaultChunkKeyEncoding
13
16
from zarr .core .common import ZarrFormat
17
+ from zarr .core .metadata import ArrayV2Metadata , ArrayV3Metadata
14
18
from zarr .core .sync import sync
15
19
from zarr .storage import MemoryStore , StoreLike
16
20
from zarr .storage ._common import _dereference_path
@@ -67,6 +71,11 @@ def safe_unicode_for_dtype(dtype: np.dtype[np.str_]) -> st.SearchStrategy[str]:
67
71
)
68
72
69
73
74
+ def clear_store (x : Store ) -> Store :
75
+ sync (x .clear ())
76
+ return x
77
+
78
+
70
79
# From https://zarr-specs.readthedocs.io/en/latest/v3/core/v3.0.html#node-names
71
80
# 1. must not be the empty string ("")
72
81
# 2. must not include the character "/"
@@ -85,12 +94,59 @@ def safe_unicode_for_dtype(dtype: np.dtype[np.str_]) -> st.SearchStrategy[str]:
85
94
# st.builds will only call a new store constructor for different keyword arguments
86
95
# i.e. stores.examples() will always return the same object per Store class.
87
96
# So we map a clear to reset the store.
88
- stores = st .builds (MemoryStore , st .just ({})).map (lambda x : sync ( x . clear ()) )
97
+ stores = st .builds (MemoryStore , st .just ({})).map (clear_store )
89
98
compressors = st .sampled_from ([None , "default" ])
90
99
zarr_formats : st .SearchStrategy [ZarrFormat ] = st .sampled_from ([2 , 3 ])
91
100
array_shapes = npst .array_shapes (max_dims = 4 , min_side = 0 )
92
101
93
102
103
+ @st .composite # type: ignore[misc]
104
+ def dimension_names (draw : st .DrawFn , * , ndim : int | None = None ) -> list [None | str ] | None :
105
+ simple_text = st .text (zarr_key_chars , min_size = 0 )
106
+ return draw (st .none () | st .lists (st .none () | simple_text , min_size = ndim , max_size = ndim )) # type: ignore[no-any-return]
107
+
108
+
109
+ @st .composite # type: ignore[misc]
110
+ def array_metadata (
111
+ draw : st .DrawFn ,
112
+ * ,
113
+ array_shapes : st .SearchStrategy [tuple [int , ...]] = npst .array_shapes ,
114
+ zarr_formats : st .SearchStrategy [Literal [2 , 3 ]] = zarr_formats ,
115
+ attributes : st .SearchStrategy [dict [str , Any ]] = attrs ,
116
+ ) -> ArrayV2Metadata | ArrayV3Metadata :
117
+ zarr_format = draw (zarr_formats )
118
+ # separator = draw(st.sampled_from(['/', '\\']))
119
+ shape = draw (array_shapes ())
120
+ ndim = len (shape )
121
+ chunk_shape = draw (array_shapes (min_dims = ndim , max_dims = ndim ))
122
+ dtype = draw (v3_dtypes ())
123
+ fill_value = draw (npst .from_dtype (dtype ))
124
+ if zarr_format == 2 :
125
+ return ArrayV2Metadata (
126
+ shape = shape ,
127
+ chunks = chunk_shape ,
128
+ dtype = dtype ,
129
+ fill_value = fill_value ,
130
+ order = draw (st .sampled_from (["C" , "F" ])),
131
+ attributes = draw (attributes ),
132
+ dimension_separator = draw (st .sampled_from (["." , "/" ])),
133
+ filters = None ,
134
+ compressor = None ,
135
+ )
136
+ else :
137
+ return ArrayV3Metadata (
138
+ shape = shape ,
139
+ data_type = dtype ,
140
+ chunk_grid = RegularChunkGrid (chunk_shape = chunk_shape ),
141
+ fill_value = fill_value ,
142
+ attributes = draw (attributes ),
143
+ dimension_names = draw (dimension_names (ndim = ndim )),
144
+ chunk_key_encoding = DefaultChunkKeyEncoding (separator = "/" ), # FIXME
145
+ codecs = [BytesCodec ()],
146
+ storage_transformers = (),
147
+ )
148
+
149
+
94
150
@st .composite # type: ignore[misc]
95
151
def numpy_arrays (
96
152
draw : st .DrawFn ,
0 commit comments