@@ -468,12 +468,12 @@ def arrays(
468468 if isinstance (chunk_grid_meta , RectilinearChunkGridMetadata ):
469469 # The per-dimension list form of `chunks=` can only express a grid with
470470 # at least one edge list (bare ints alone declare a regular grid) whose
471- # edge lists sum exactly to the extent. Other grids are passed as the
471+ # edge lists sum exactly to the extent, or belong to a zero-length axis . Other grids are passed as the
472472 # metadata object, which `create_array` also accepts.
473473 expressible_as_lists = any (
474474 isinstance (dim , tuple ) for dim in chunk_grid_meta .chunk_shapes
475475 ) and all (
476- isinstance (dim , int ) or sum (dim ) == extent
476+ isinstance (dim , int ) or extent == 0 or sum (dim ) == extent
477477 for dim , extent in zip (chunk_grid_meta .chunk_shapes , nparray .shape , strict = True )
478478 )
479479 if expressible_as_lists and draw (st .booleans (), label = "chunks as lists" ):
@@ -578,12 +578,19 @@ def chunks_param_from_rectilinear(
578578def rectilinear_dim_edges (draw : st .DrawFn , * , extent : int ) -> list [int ]:
579579 """Explicit chunk edge lengths summing exactly to `extent`.
580580
581+ A zero `extent` has no chunks for edges to cover, and no non-empty list
582+ of positive edges sums to 0; its edges are the chunks the axis grows into
583+ on `append` or `resize`, so any non-empty list of positive edges is drawn.
584+
581585 Two modes: "uneven" cuts the extent at random dividers; "uniform" repeats
582586 one size with an optional remainder, optionally shuffled so equal edges
583587 are not all adjacent. At most 20 chunks per dimension keeps property
584588 tests fast.
585589 """
586- assert extent > 0
590+ assert extent >= 0
591+ if extent == 0 :
592+ event ("rectilinear edges: zero extent" )
593+ return draw (st .lists (st .integers (min_value = 1 , max_value = 10 ), min_size = 1 , max_size = 5 ))
587594 if extent == 1 :
588595 return [1 ]
589596 if draw (st .booleans (), label = "uneven edges" ):
@@ -615,7 +622,7 @@ def _rectilinear_step(draw: st.DrawFn, *, extent: int) -> int:
615622 """A bare-int chunk size for one dimension: a step that repeats to cover
616623 the extent, with the last chunk possibly smaller. A step larger than the
617624 extent (one overhanging chunk) is allowed, as for a regular grid."""
618- step = draw (st .integers (min_value = math .ceil (extent / 20 ), max_value = extent + 3 ))
625+ step = draw (st .integers (min_value = max ( 1 , math .ceil (extent / 20 ) ), max_value = extent + 3 ))
619626 event ("rectilinear dim: bare int" + (", larger than extent" if step > extent else "" ))
620627 return step
621628
@@ -625,7 +632,8 @@ def rectilinear_chunks(draw: st.DrawFn, *, shape: tuple[int, ...]) -> list[int |
625632 """A `chunks=` specification declaring a rectilinear grid over `shape`.
626633
627634 Each dimension is either a bare int (a step size; the last chunk may be
628- smaller) or an explicit edge list summing to the extent. At least one
635+ smaller) or an explicit edge list summing to the extent (any edges, for a
636+ zero extent). At least one
629637 dimension is an edge list, since bare ints alone declare a regular grid.
630638 Run-length encoding is not part of the `chunks=` syntax; it belongs to
631639 stored metadata, see `rectilinear_chunk_shape_declarations`.
@@ -637,7 +645,6 @@ def rectilinear_chunks(draw: st.DrawFn, *, shape: tuple[int, ...]) -> list[int |
637645 forced_list = draw (st .integers (min_value = 0 , max_value = len (shape ) - 1 ))
638646 chunks : list [int | list [int ]] = []
639647 for i , extent in enumerate (shape ):
640- assert extent > 0
641648 if i != forced_list and draw (st .booleans (), label = "bare int" ):
642649 chunks .append (_rectilinear_step (draw , extent = extent ))
643650 else :
@@ -696,7 +703,6 @@ def rectilinear_chunk_shape_declarations(
696703 declaration : list [_RectilinearDimDeclaration ] = []
697704 chunk_shapes : list [int | tuple [int , ...]] = []
698705 for extent in shape :
699- assert extent > 0
700706 if draw (st .booleans (), label = "bare int" ):
701707 step = _rectilinear_step (draw , extent = extent )
702708 declaration .append (step )
@@ -742,12 +748,6 @@ def chunk_grids(
742748
743749 This allows property tests to exercise both chunk grid types.
744750 """
745- # RectilinearChunkGridMetadata doesn't support zero-sized dimensions,
746- # so use RegularChunkGridMetadata if any dimension is 0
747- if any (s == 0 for s in shape ):
748- event ("using RegularChunkGridMetadata (zero-sized dimensions)" )
749- return RegularChunkGridMetadata (chunk_shape = draw (chunk_shapes (shape = shape )))
750-
751751 if zarr .config .get ("array.rectilinear_chunks" ) and draw (st .booleans ()):
752752 event ("using RectilinearChunkGridMetadata" )
753753 return draw (rectilinear_chunk_grids (shape = shape ))
0 commit comments