@@ -562,3 +562,78 @@ def chunk_paths(draw: st.DrawFn, ndim: int, numblocks: tuple[int, ...], subset:
562562 )
563563 subset_slicer = slice (draw (st .integers (min_value = 0 , max_value = ndim ))) if subset else slice (None )
564564 return "/" .join (map (str , blockidx [subset_slicer ]))
565+
566+
567+ @st .composite
568+ def complex_chunk_grids (draw : st .DrawFn ) -> RectilinearChunkGrid :
569+ ndim = draw (st .integers (min_value = 1 , max_value = 3 ))
570+ nchunks = draw (st .integers (min_value = 10 , max_value = 100 ))
571+ dim_chunks = st .lists (
572+ st .integers (min_value = 1 , max_value = 10 ), unique = True , min_size = nchunks , max_size = nchunks
573+ )
574+ if draw (st .booleans ()):
575+ event ("using RectilinearChunkGrid" )
576+ chunk_shapes = draw (st .lists (dim_chunks , min_size = ndim , max_size = ndim ))
577+ return RectilinearChunkGrid (chunk_shapes = chunk_shapes )
578+
579+ else :
580+ event ("using RectilinearChunkGrid (run length encoded)" )
581+ repeats = st .lists (
582+ st .integers (min_value = 1 , max_value = 20 ), min_size = nchunks , max_size = nchunks
583+ )
584+ chunk_shapes_rle = [
585+ [[c , r ] for c , r in zip (draw (dim_chunks ), draw (repeats ), strict = True )]
586+ for _ in range (ndim )
587+ ]
588+ return RectilinearChunkGrid (chunk_shapes = chunk_shapes_rle )
589+
590+
591+ @st .composite
592+ def complex_chunked_arrays (
593+ draw : st .DrawFn ,
594+ * ,
595+ stores : st .SearchStrategy [StoreLike ] = stores ,
596+ ) -> Array :
597+ store = draw (stores , label = "store" )
598+ chunks = draw (complex_chunk_grids (), label = "chunk grid" )
599+ assert isinstance (chunks , RectilinearChunkGrid )
600+ shape = tuple (x [- 1 ] for x in chunks ._cumulative_sizes )
601+ nparray = draw (numpy_arrays (shapes = st .just (shape )), label = "array data" )
602+ root = zarr .open_group (store , mode = "w" )
603+
604+ a = root .create_array (
605+ "/foo" ,
606+ shape = nparray .shape ,
607+ chunks = chunks ,
608+ shards = None ,
609+ dtype = nparray .dtype ,
610+ attributes = {},
611+ fill_value = None ,
612+ dimension_names = None ,
613+ )
614+
615+ assert isinstance (a , Array )
616+ if a .metadata .zarr_format == 3 :
617+ assert a .fill_value is not None
618+ assert nparray .shape == a .shape
619+
620+ # Verify chunks - for RegularChunkGrid check exact match
621+ # For RectilinearChunkGrid, skip chunks check since it raises NotImplementedError
622+ if isinstance (a .metadata .chunk_grid , RectilinearChunkGrid ):
623+ # Just verify the chunk_grid is set correctly
624+ assert isinstance (a .metadata .chunk_grid , RectilinearChunkGrid )
625+ # shards also raises NotImplementedError for RectilinearChunkGrid
626+ else :
627+ # For RegularChunkGrid, the chunks property returns the normalized chunk_shape
628+ # which may differ from the input (e.g., (0,) becomes (1,) after normalization)
629+ # We should compare against the actual chunk_grid's chunk_shape
630+ from zarr .core .chunk_grids import RegularChunkGrid
631+
632+ assert isinstance (a .metadata .chunk_grid , RegularChunkGrid )
633+ expected_chunks = a .metadata .chunk_grid .chunk_shape
634+ assert expected_chunks == a .chunks
635+
636+ assert a .shards is None # We don't use sharding with RectilinearChunkGrid
637+
638+ a [:] = nparray
639+ return a
0 commit comments