11import math
22import sys
3+ from collections .abc import Callable , Mapping
34from typing import Any , Literal
45
56import hypothesis .extra .numpy as npst
67import hypothesis .strategies as st
78import numpy as np
9+ import numpy .typing as npt
810from hypothesis import event
911from hypothesis .strategies import SearchStrategy
1012
1416from zarr .core .array import Array
1517from zarr .core .chunk_grids import RegularChunkGrid
1618from zarr .core .chunk_key_encodings import DefaultChunkKeyEncoding
17- from zarr .core .common import ZarrFormat
19+ from zarr .core .common import JSON , ZarrFormat
1820from zarr .core .metadata import ArrayV2Metadata , ArrayV3Metadata
1921from zarr .core .sync import sync
2022from zarr .storage import MemoryStore , StoreLike
3032)
3133
3234
33- @st .composite # type: ignore[misc]
34- def keys (draw : st .DrawFn , * , max_num_nodes : int | None = None ) -> Any :
35+ @st .composite
36+ def keys (draw : st .DrawFn , * , max_num_nodes : int | None = None ) -> str :
3537 return draw (st .lists (node_names , min_size = 1 , max_size = max_num_nodes ).map ("/" .join ))
3638
3739
38- @st .composite # type: ignore[misc]
39- def paths (draw : st .DrawFn , * , max_num_nodes : int | None = None ) -> Any :
40+ @st .composite
41+ def paths (draw : st .DrawFn , * , max_num_nodes : int | None = None ) -> str :
4042 return draw (st .just ("/" ) | keys (max_num_nodes = max_num_nodes ))
4143
4244
43- def v3_dtypes () -> st .SearchStrategy [np .dtype ]:
45+ def v3_dtypes () -> st .SearchStrategy [np .dtype [ Any ] ]:
4446 return (
4547 npst .boolean_dtypes ()
4648 | npst .integer_dtypes (endianness = "=" )
@@ -54,7 +56,7 @@ def v3_dtypes() -> st.SearchStrategy[np.dtype]:
5456 )
5557
5658
57- def v2_dtypes () -> st .SearchStrategy [np .dtype ]:
59+ def v2_dtypes () -> st .SearchStrategy [np .dtype [ Any ] ]:
5860 return (
5961 npst .boolean_dtypes ()
6062 | npst .integer_dtypes (endianness = "=" )
@@ -107,7 +109,9 @@ def clear_store(x: Store) -> Store:
107109 .filter (lambda name : name .lower () != "zarr.json" )
108110)
109111array_names = node_names
110- attrs = st .none () | st .dictionaries (_attr_keys , _attr_values )
112+ attrs : st .SearchStrategy [Mapping [str , JSON ] | None ] = st .none () | st .dictionaries (
113+ _attr_keys , _attr_values
114+ )
111115# st.builds will only call a new store constructor for different keyword arguments
112116# i.e. stores.examples() will always return the same object per Store class.
113117# So we map a clear to reset the store.
@@ -118,19 +122,19 @@ def clear_store(x: Store) -> Store:
118122array_shapes = npst .array_shapes (max_dims = 4 , min_side = 3 ) | npst .array_shapes (max_dims = 4 , min_side = 0 )
119123
120124
121- @st .composite # type: ignore[misc]
125+ @st .composite
122126def dimension_names (draw : st .DrawFn , * , ndim : int | None = None ) -> list [None | str ] | None :
123127 simple_text = st .text (zarr_key_chars , min_size = 0 )
124- return draw (st .none () | st .lists (st .none () | simple_text , min_size = ndim , max_size = ndim )) # type: ignore[no-any-return ]
128+ return draw (st .none () | st .lists (st .none () | simple_text , min_size = ndim , max_size = ndim )) # type: ignore[arg-type ]
125129
126130
127- @st .composite # type: ignore[misc]
131+ @st .composite
128132def array_metadata (
129133 draw : st .DrawFn ,
130134 * ,
131- array_shapes : st .SearchStrategy [tuple [int , ...]] = npst .array_shapes ,
135+ array_shapes : Callable [..., st .SearchStrategy [tuple [int , ...] ]] = npst .array_shapes ,
132136 zarr_formats : st .SearchStrategy [Literal [2 , 3 ]] = zarr_formats ,
133- attributes : st . SearchStrategy [dict [str , Any ] ] = attrs ,
137+ attributes : SearchStrategy [Mapping [str , JSON ] | None ] = attrs ,
134138) -> ArrayV2Metadata | ArrayV3Metadata :
135139 zarr_format = draw (zarr_formats )
136140 # separator = draw(st.sampled_from(['/', '\\']))
@@ -146,7 +150,7 @@ def array_metadata(
146150 dtype = dtype ,
147151 fill_value = fill_value ,
148152 order = draw (st .sampled_from (["C" , "F" ])),
149- attributes = draw (attributes ),
153+ attributes = draw (attributes ), # type: ignore[arg-type]
150154 dimension_separator = draw (st .sampled_from (["." , "/" ])),
151155 filters = None ,
152156 compressor = None ,
@@ -157,22 +161,22 @@ def array_metadata(
157161 data_type = dtype ,
158162 chunk_grid = RegularChunkGrid (chunk_shape = chunk_shape ),
159163 fill_value = fill_value ,
160- attributes = draw (attributes ),
164+ attributes = draw (attributes ), # type: ignore[arg-type]
161165 dimension_names = draw (dimension_names (ndim = ndim )),
162166 chunk_key_encoding = DefaultChunkKeyEncoding (separator = "/" ), # FIXME
163167 codecs = [BytesCodec ()],
164168 storage_transformers = (),
165169 )
166170
167171
168- @st .composite # type: ignore[misc]
172+ @st .composite
169173def numpy_arrays (
170174 draw : st .DrawFn ,
171175 * ,
172176 shapes : st .SearchStrategy [tuple [int , ...]] = array_shapes ,
173177 dtype : np .dtype [Any ] | None = None ,
174- zarr_formats : st .SearchStrategy [ZarrFormat ] | None = zarr_formats ,
175- ) -> Any :
178+ zarr_formats : st .SearchStrategy [ZarrFormat ] = zarr_formats ,
179+ ) -> npt . NDArray [ Any ] :
176180 """
177181 Generate numpy arrays that can be saved in the provided Zarr format.
178182 """
@@ -186,7 +190,7 @@ def numpy_arrays(
186190 return draw (npst .arrays (dtype = dtype , shape = shapes ))
187191
188192
189- @st .composite # type: ignore[misc]
193+ @st .composite
190194def chunk_shapes (draw : st .DrawFn , * , shape : tuple [int , ...]) -> tuple [int , ...]:
191195 # We want this strategy to shrink towards arrays with smaller number of chunks
192196 # 1. st.integers() shrinks towards smaller values. So we use that to generate number of chunks
@@ -208,7 +212,7 @@ def chunk_shapes(draw: st.DrawFn, *, shape: tuple[int, ...]) -> tuple[int, ...]:
208212 return chunks
209213
210214
211- @st .composite # type: ignore[misc]
215+ @st .composite
212216def shard_shapes (
213217 draw : st .DrawFn , * , shape : tuple [int , ...], chunk_shape : tuple [int , ...]
214218) -> tuple [int , ...]:
@@ -220,9 +224,11 @@ def shard_shapes(
220224 return tuple (m * c for m , c in zip (multiples , chunk_shape , strict = True ))
221225
222226
223- @st .composite # type: ignore[misc]
227+ @st .composite
224228def np_array_and_chunks (
225- draw : st .DrawFn , * , arrays : st .SearchStrategy [np .ndarray ] = numpy_arrays
229+ draw : st .DrawFn ,
230+ * ,
231+ arrays : st .SearchStrategy [npt .NDArray [Any ]] = numpy_arrays (), # noqa: B008
226232) -> tuple [np .ndarray , tuple [int , ...]]: # type: ignore[type-arg]
227233 """A hypothesis strategy to generate small sized random arrays.
228234
@@ -232,14 +238,14 @@ def np_array_and_chunks(
232238 return (array , draw (chunk_shapes (shape = array .shape )))
233239
234240
235- @st .composite # type: ignore[misc]
241+ @st .composite
236242def arrays (
237243 draw : st .DrawFn ,
238244 * ,
239245 shapes : st .SearchStrategy [tuple [int , ...]] = array_shapes ,
240246 compressors : st .SearchStrategy = compressors ,
241247 stores : st .SearchStrategy [StoreLike ] = stores ,
242- paths : st .SearchStrategy [str | None ] = paths (), # noqa: B008
248+ paths : st .SearchStrategy [str ] = paths (), # noqa: B008
243249 array_names : st .SearchStrategy = array_names ,
244250 arrays : st .SearchStrategy | None = None ,
245251 attrs : st .SearchStrategy = attrs ,
@@ -296,7 +302,7 @@ def arrays(
296302 return a
297303
298304
299- @st .composite # type: ignore[misc]
305+ @st .composite
300306def simple_arrays (
301307 draw : st .DrawFn ,
302308 * ,
@@ -317,7 +323,7 @@ def is_negative_slice(idx: Any) -> bool:
317323 return isinstance (idx , slice ) and idx .step is not None and idx .step < 0
318324
319325
320- @st .composite # type: ignore[misc]
326+ @st .composite
321327def end_slices (draw : st .DrawFn , * , shape : tuple [int ]) -> Any :
322328 """
323329 A strategy that slices ranges that include the last chunk.
@@ -332,23 +338,32 @@ def end_slices(draw: st.DrawFn, *, shape: tuple[int]) -> Any:
332338 return tuple (slicers )
333339
334340
335- @st .composite # type: ignore[misc]
336- def basic_indices (draw : st .DrawFn , * , shape : tuple [int ], ** kwargs : Any ) -> Any :
341+ @st .composite
342+ def basic_indices (
343+ draw : st .DrawFn ,
344+ * ,
345+ shape : tuple [int ],
346+ min_dims : int = 0 ,
347+ max_dims : int | None = None ,
348+ allow_newaxis : bool = False ,
349+ allow_ellipsis : bool = True ,
350+ ) -> Any :
337351 """Basic indices without unsupported negative slices."""
338- strategy = npst .basic_indices (shape = shape , ** kwargs ).filter (
339- lambda idxr : (
340- not (
341- is_negative_slice (idxr )
342- or (isinstance (idxr , tuple ) and any (is_negative_slice (idx ) for idx in idxr ))
343- )
344- )
352+ strategy = npst .basic_indices (
353+ shape = shape ,
354+ min_dims = min_dims ,
355+ max_dims = max_dims ,
356+ allow_newaxis = allow_newaxis ,
357+ allow_ellipsis = allow_ellipsis ,
358+ ).filter (
359+ lambda idxr : (not (is_negative_slice (idxr ) or any (is_negative_slice (idx ) for idx in idxr )))
345360 )
346361 if math .prod (shape ) >= 3 :
347362 strategy = end_slices (shape = shape ) | strategy
348363 return draw (strategy )
349364
350365
351- @st .composite # type: ignore[misc]
366+ @st .composite
352367def orthogonal_indices (
353368 draw : st .DrawFn , * , shape : tuple [int ]
354369) -> tuple [tuple [np .ndarray [Any , Any ], ...], tuple [np .ndarray [Any , Any ], ...]]:
@@ -386,8 +401,8 @@ def orthogonal_indices(
386401
387402
388403def key_ranges (
389- keys : SearchStrategy = node_names , max_size : int = sys .maxsize
390- ) -> SearchStrategy [list [int ]]:
404+ keys : SearchStrategy [ str ] = node_names , max_size : int = sys .maxsize
405+ ) -> SearchStrategy [list [tuple [ str , RangeByteRequest ] ]]:
391406 """
392407 Function to generate key_ranges strategy for get_partial_values()
393408 returns list strategy w/ form::
0 commit comments