Skip to content

Commit 0f0576e

Browse files
committed
Make dimensions private
1 parent 6667fda commit 0f0576e

File tree

3 files changed

+61
-49
lines changed

3 files changed

+61
-49
lines changed

src/zarr/core/chunk_grids.py

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -303,15 +303,25 @@ class ChunkGrid:
303303
or VaryingDimension (per-chunk edge lengths with prefix sums).
304304
"""
305305

306-
dimensions: tuple[DimensionGrid, ...]
306+
_dimensions: tuple[DimensionGrid, ...]
307307
_is_regular: bool
308308

309309
def __init__(self, *, dimensions: tuple[DimensionGrid, ...]) -> None:
310-
object.__setattr__(self, "dimensions", dimensions)
310+
object.__setattr__(self, "_dimensions", dimensions)
311311
object.__setattr__(
312312
self, "_is_regular", all(isinstance(d, FixedDimension) for d in dimensions)
313313
)
314314

315+
def __repr__(self) -> str:
316+
sizes: list[str] = []
317+
for d in self._dimensions:
318+
if isinstance(d, FixedDimension):
319+
sizes.append(str(d.size))
320+
elif isinstance(d, VaryingDimension):
321+
sizes.append(repr(tuple(d.edges)))
322+
shape = tuple(d.extent for d in self._dimensions)
323+
return f"ChunkGrid(chunk_sizes=({', '.join(sizes)}), array_shape={shape})"
324+
315325
@classmethod
316326
def from_metadata(cls, metadata: ArrayMetadata) -> ChunkGrid:
317327
"""Construct a behavioral ChunkGrid from array metadata.
@@ -381,7 +391,7 @@ def from_sizes(
381391

382392
@property
383393
def ndim(self) -> int:
384-
return len(self.dimensions)
394+
return len(self._dimensions)
385395

386396
@property
387397
def is_regular(self) -> bool:
@@ -390,7 +400,7 @@ def is_regular(self) -> bool:
390400
@property
391401
def grid_shape(self) -> tuple[int, ...]:
392402
"""Number of chunks per dimension."""
393-
return tuple(d.nchunks for d in self.dimensions)
403+
return tuple(d.nchunks for d in self._dimensions)
394404

395405
@property
396406
def chunk_shape(self) -> tuple[int, ...]:
@@ -400,7 +410,7 @@ def chunk_shape(self) -> tuple[int, ...]:
400410
"chunk_shape is only available for regular chunk grids. "
401411
"Use grid[coords] for per-chunk sizes."
402412
)
403-
return tuple(d.size for d in self.dimensions if isinstance(d, FixedDimension))
413+
return tuple(d.size for d in self._dimensions if isinstance(d, FixedDimension))
404414

405415
@property
406416
def chunk_sizes(self) -> tuple[tuple[int, ...], ...]:
@@ -416,7 +426,7 @@ def chunk_sizes(self) -> tuple[tuple[int, ...], ...]:
416426
One inner tuple per dimension, each containing the data size
417427
of every chunk along that dimension.
418428
"""
419-
return tuple(tuple(d.data_size(i) for i in range(d.nchunks)) for d in self.dimensions)
429+
return tuple(tuple(d.data_size(i) for i in range(d.nchunks)) for d in self._dimensions)
420430

421431
# -- Collection interface --
422432

@@ -431,7 +441,7 @@ def __getitem__(self, coords: int | tuple[int, ...]) -> ChunkSpec | None:
431441
)
432442
slices: list[slice] = []
433443
codec_shape: list[int] = []
434-
for dim, ix in zip(self.dimensions, coords, strict=True):
444+
for dim, ix in zip(self._dimensions, coords, strict=True):
435445
if ix < 0 or ix >= dim.nchunks:
436446
return None
437447
offset = dim.chunk_offset(ix)
@@ -441,7 +451,7 @@ def __getitem__(self, coords: int | tuple[int, ...]) -> ChunkSpec | None:
441451

442452
def __iter__(self) -> Iterator[ChunkSpec]:
443453
"""Iterate all chunks, yielding ChunkSpec for each."""
444-
for coords in itertools.product(*(range(d.nchunks) for d in self.dimensions)):
454+
for coords in itertools.product(*(range(d.nchunks) for d in self._dimensions)):
445455
spec = self[coords]
446456
if spec is not None:
447457
yield spec
@@ -499,7 +509,7 @@ def iter_chunk_regions(
499509
yield spec.slices
500510

501511
def get_nchunks(self) -> int:
502-
return reduce(operator.mul, (d.nchunks for d in self.dimensions), 1)
512+
return reduce(operator.mul, (d.nchunks for d in self._dimensions), 1)
503513

504514
# -- Resize --
505515

@@ -526,7 +536,7 @@ def update_shape(self, new_shape: tuple[int, ...]) -> ChunkGrid:
526536
)
527537
dims = tuple(
528538
dim.resize(new_extent)
529-
for dim, new_extent in zip(self.dimensions, new_shape, strict=True)
539+
for dim, new_extent in zip(self._dimensions, new_shape, strict=True)
530540
)
531541
return ChunkGrid(dimensions=dims)
532542

src/zarr/core/indexing.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,7 @@ def __init__(
578578
shape: tuple[int, ...],
579579
chunk_grid: ChunkGrid,
580580
) -> None:
581-
dim_grids = chunk_grid.dimensions
581+
dim_grids = chunk_grid._dimensions
582582
# handle ellipsis
583583
selection_normalized = replace_ellipsis(selection, shape)
584584

@@ -905,7 +905,7 @@ class OrthogonalIndexer(Indexer):
905905
drop_axes: tuple[int, ...]
906906

907907
def __init__(self, selection: Selection, shape: tuple[int, ...], chunk_grid: ChunkGrid) -> None:
908-
dim_grids = chunk_grid.dimensions
908+
dim_grids = chunk_grid._dimensions
909909

910910
# handle ellipsis
911911
selection = replace_ellipsis(selection, shape)
@@ -1050,7 +1050,7 @@ class BlockIndexer(Indexer):
10501050
def __init__(
10511051
self, selection: BasicSelection, shape: tuple[int, ...], chunk_grid: ChunkGrid
10521052
) -> None:
1053-
dim_grids = chunk_grid.dimensions
1053+
dim_grids = chunk_grid._dimensions
10541054

10551055
# handle ellipsis
10561056
selection_normalized = replace_ellipsis(selection, shape)
@@ -1180,7 +1180,7 @@ class CoordinateIndexer(Indexer):
11801180
def __init__(
11811181
self, selection: CoordinateSelection, shape: tuple[int, ...], chunk_grid: ChunkGrid
11821182
) -> None:
1183-
dim_grids = chunk_grid.dimensions
1183+
dim_grids = chunk_grid._dimensions
11841184

11851185
cdata_shape: tuple[int, ...]
11861186
if shape == ():

tests/test_unified_chunk_grid.py

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def _enable_rectilinear_chunks() -> Generator[None, None, None]:
4646

4747
def _edges(grid: ChunkGrid, dim: int) -> tuple[int, ...]:
4848
"""Extract the per-chunk edge lengths for *dim* from a ChunkGrid."""
49-
d = grid.dimensions[dim]
49+
d = grid._dimensions[dim]
5050
if isinstance(d, FixedDimension):
5151
return tuple(d.size for _ in range(d.nchunks))
5252
if isinstance(d, VaryingDimension):
@@ -327,8 +327,8 @@ def test_chunk_grid_construction(
327327
def test_chunk_grid_rectilinear_uniform_dim_is_fixed() -> None:
328328
"""A rectilinear grid with all-same sizes in one dim stores it as Fixed."""
329329
g = ChunkGrid.from_sizes((60, 100), [[10, 20, 30], [25, 25, 25, 25]])
330-
assert isinstance(g.dimensions[0], VaryingDimension)
331-
assert isinstance(g.dimensions[1], FixedDimension)
330+
assert isinstance(g._dimensions[0], VaryingDimension)
331+
assert isinstance(g._dimensions[1], FixedDimension)
332332

333333

334334
# ---------------------------------------------------------------------------
@@ -715,7 +715,7 @@ def test_parse_chunk_grid_varying_extent_mismatch_raises() -> None:
715715
with pytest.raises(ValueError, match="extent"):
716716
ChunkGrid(
717717
dimensions=tuple(
718-
dim.with_extent(ext) for dim, ext in zip(g.dimensions, (100, 100), strict=True)
718+
dim.with_extent(ext) for dim, ext in zip(g._dimensions, (100, 100), strict=True)
719719
)
720720
)
721721

@@ -725,10 +725,10 @@ def test_parse_chunk_grid_varying_extent_match_ok() -> None:
725725
g = ChunkGrid.from_sizes((60, 100), [[10, 20, 30], [50, 50]])
726726
g2 = ChunkGrid(
727727
dimensions=tuple(
728-
dim.with_extent(ext) for dim, ext in zip(g.dimensions, (60, 100), strict=True)
728+
dim.with_extent(ext) for dim, ext in zip(g._dimensions, (60, 100), strict=True)
729729
)
730730
)
731-
assert g2.dimensions[0].extent == 60
731+
assert g2._dimensions[0].extent == 60
732732

733733

734734
@pytest.mark.parametrize(
@@ -793,7 +793,7 @@ def test_parse_chunk_grid_varying_dimension_extent_mismatch_on_chunkgrid_input()
793793
with pytest.raises(ValueError, match="less than"):
794794
ChunkGrid(
795795
dimensions=tuple(
796-
dim.with_extent(ext) for dim, ext in zip(g.dimensions, (100, 50), strict=True)
796+
dim.with_extent(ext) for dim, ext in zip(g._dimensions, (100, 50), strict=True)
797797
)
798798
)
799799

@@ -1126,30 +1126,30 @@ def test_0d_grid_nchunks() -> None:
11261126
def test_parse_chunk_grid_preserves_varying_extent() -> None:
11271127
"""parse_chunk_grid does not overwrite VaryingDimension extent."""
11281128
g = ChunkGrid.from_sizes((60, 100), [[10, 20, 30], [50, 50]])
1129-
assert isinstance(g.dimensions[0], VaryingDimension)
1130-
assert g.dimensions[0].extent == 60
1129+
assert isinstance(g._dimensions[0], VaryingDimension)
1130+
assert g._dimensions[0].extent == 60
11311131

11321132
g2 = ChunkGrid(
11331133
dimensions=tuple(
1134-
dim.with_extent(ext) for dim, ext in zip(g.dimensions, (60, 100), strict=True)
1134+
dim.with_extent(ext) for dim, ext in zip(g._dimensions, (60, 100), strict=True)
11351135
)
11361136
)
1137-
assert isinstance(g2.dimensions[0], VaryingDimension)
1138-
assert g2.dimensions[0].extent == 60
1137+
assert isinstance(g2._dimensions[0], VaryingDimension)
1138+
assert g2._dimensions[0].extent == 60
11391139

11401140

11411141
def test_parse_chunk_grid_rebinds_fixed_extent() -> None:
11421142
"""parse_chunk_grid updates FixedDimension extent from array shape."""
11431143
g = ChunkGrid.from_sizes((100, 200), (10, 20))
1144-
assert g.dimensions[0].extent == 100
1144+
assert g._dimensions[0].extent == 100
11451145

11461146
g2 = ChunkGrid(
11471147
dimensions=tuple(
1148-
dim.with_extent(ext) for dim, ext in zip(g.dimensions, (50, 100), strict=True)
1148+
dim.with_extent(ext) for dim, ext in zip(g._dimensions, (50, 100), strict=True)
11491149
)
11501150
)
1151-
assert isinstance(g2.dimensions[0], FixedDimension)
1152-
assert g2.dimensions[0].extent == 50
1151+
assert isinstance(g2._dimensions[0], FixedDimension)
1152+
assert g2._dimensions[0].extent == 50
11531153
assert g2.grid_shape == (5, 5)
11541154

11551155

@@ -1775,7 +1775,7 @@ def test_varying_dimension_interior_chunk_spec() -> None:
17751775
def test_overflow_multiple_chunks_past_extent() -> None:
17761776
"""Edges past extent are structural; nchunks counts active only."""
17771777
g = ChunkGrid.from_sizes((50,), [[10, 20, 30, 40]])
1778-
d = g.dimensions[0]
1778+
d = g._dimensions[0]
17791779
assert d.ngridcells == 4
17801780
assert d.nchunks == 3
17811781
assert d.data_size(0) == 10
@@ -1821,10 +1821,10 @@ def test_overflow_multidim() -> None:
18211821
def test_overflow_uniform_edges_collapses_to_fixed() -> None:
18221822
"""Uniform edges where len == ceildiv(extent, edge) collapse to FixedDimension."""
18231823
g = ChunkGrid.from_sizes((35,), [[10, 10, 10, 10]])
1824-
assert isinstance(g.dimensions[0], FixedDimension)
1824+
assert isinstance(g._dimensions[0], FixedDimension)
18251825
assert g.is_regular
18261826
assert g.chunk_sizes == ((10, 10, 10, 5),)
1827-
assert g.dimensions[0].nchunks == 4
1827+
assert g._dimensions[0].nchunks == 4
18281828

18291829

18301830
def test_overflow_index_to_chunk_near_extent() -> None:
@@ -2009,7 +2009,7 @@ def test_update_shape_shrink_single_dim() -> None:
20092009
grid = ChunkGrid.from_sizes((100, 50), [[10, 20, 30, 40], [25, 25]])
20102010
new_grid = grid.update_shape((35, 50))
20112011
assert _edges(new_grid, 0) == (10, 20, 30, 40)
2012-
assert new_grid.dimensions[0].nchunks == 3
2012+
assert new_grid._dimensions[0].nchunks == 3
20132013
assert _edges(new_grid, 1) == (25, 25)
20142014

20152015

@@ -2018,7 +2018,7 @@ def test_update_shape_shrink_to_single_chunk() -> None:
20182018
grid = ChunkGrid.from_sizes((60, 50), [[10, 20, 30], [25, 25]])
20192019
new_grid = grid.update_shape((5, 50))
20202020
assert _edges(new_grid, 0) == (10, 20, 30)
2021-
assert new_grid.dimensions[0].nchunks == 1
2021+
assert new_grid._dimensions[0].nchunks == 1
20222022
assert _edges(new_grid, 1) == (25, 25)
20232023

20242024

@@ -2027,9 +2027,9 @@ def test_update_shape_shrink_multiple_dims() -> None:
20272027
grid = ChunkGrid.from_sizes((40, 60), [[10, 10, 15, 5], [20, 25, 15]])
20282028
new_grid = grid.update_shape((25, 35))
20292029
assert _edges(new_grid, 0) == (10, 10, 15, 5)
2030-
assert new_grid.dimensions[0].nchunks == 3
2030+
assert new_grid._dimensions[0].nchunks == 3
20312031
assert _edges(new_grid, 1) == (20, 25, 15)
2032-
assert new_grid.dimensions[1].nchunks == 2
2032+
assert new_grid._dimensions[1].nchunks == 2
20332033

20342034

20352035
def test_update_shape_dimension_mismatch_error() -> None:
@@ -2049,9 +2049,9 @@ def test_update_shape_boundary_cases() -> None:
20492049
grid2 = ChunkGrid.from_sizes((60, 50), [[10, 20, 30], [15, 25, 10]])
20502050
new_grid2 = grid2.update_shape((30, 40))
20512051
assert _edges(new_grid2, 0) == (10, 20, 30)
2052-
assert new_grid2.dimensions[0].nchunks == 2
2052+
assert new_grid2._dimensions[0].nchunks == 2
20532053
assert _edges(new_grid2, 1) == (15, 25, 10)
2054-
assert new_grid2.dimensions[1].nchunks == 2
2054+
assert new_grid2._dimensions[1].nchunks == 2
20552055

20562056

20572057
def test_update_shape_regular_preserves_extents(tmp_path: Path) -> None:
@@ -2065,7 +2065,7 @@ def test_update_shape_regular_preserves_extents(tmp_path: Path) -> None:
20652065
z[:] = np.arange(100, dtype="int32")
20662066
z.resize(50)
20672067
assert z.shape == (50,)
2068-
assert ChunkGrid.from_metadata(z.metadata).dimensions[0].extent == 50
2068+
assert ChunkGrid.from_metadata(z.metadata)._dimensions[0].extent == 50
20692069

20702070

20712071
# ---------------------------------------------------------------------------
@@ -2077,7 +2077,7 @@ def test_update_shape_shrink_creates_boundary() -> None:
20772077
"""Shrinking extent into a chunk creates a boundary with clipped data_size"""
20782078
grid = ChunkGrid.from_sizes((60,), [[10, 20, 30]])
20792079
new_grid = grid.update_shape((45,))
2080-
dim = new_grid.dimensions[0]
2080+
dim = new_grid._dimensions[0]
20812081
assert isinstance(dim, VaryingDimension)
20822082
assert dim.edges == (10, 20, 30)
20832083
assert dim.extent == 45
@@ -2089,7 +2089,7 @@ def test_update_shape_shrink_to_exact_boundary() -> None:
20892089
"""Shrinking to an exact chunk boundary reduces nchunks without partial data"""
20902090
grid = ChunkGrid.from_sizes((60,), [[10, 20, 30]])
20912091
new_grid = grid.update_shape((30,))
2092-
dim = new_grid.dimensions[0]
2092+
dim = new_grid._dimensions[0]
20932093
assert isinstance(dim, VaryingDimension)
20942094
assert dim.edges == (10, 20, 30)
20952095
assert dim.nchunks == 2
@@ -2113,9 +2113,11 @@ def test_update_shape_parse_chunk_grid_rebinds_extent() -> None:
21132113
"""parse_chunk_grid re-binds VaryingDimension extent to array shape."""
21142114
g = ChunkGrid.from_sizes((60,), [[10, 20, 30]])
21152115
g2 = ChunkGrid(
2116-
dimensions=tuple(dim.with_extent(ext) for dim, ext in zip(g.dimensions, (50,), strict=True))
2116+
dimensions=tuple(
2117+
dim.with_extent(ext) for dim, ext in zip(g._dimensions, (50,), strict=True)
2118+
)
21172119
)
2118-
dim = g2.dimensions[0]
2120+
dim = g2._dimensions[0]
21192121
assert isinstance(dim, VaryingDimension)
21202122
assert dim.extent == 50
21212123
assert dim.data_size(2) == 20
@@ -2364,7 +2366,7 @@ def test_v2_chunk_grid_is_regular(tmp_path: Path) -> None:
23642366
assert grid.is_regular
23652367
assert grid.chunk_shape == (10, 15)
23662368
assert grid.grid_shape == (2, 2)
2367-
assert all(isinstance(d, FixedDimension) for d in grid.dimensions)
2369+
assert all(isinstance(d, FixedDimension) for d in grid._dimensions)
23682370

23692371

23702372
def test_v2_boundary_chunks(tmp_path: Path) -> None:
@@ -2377,9 +2379,9 @@ def test_v2_boundary_chunks(tmp_path: Path) -> None:
23772379
zarr_format=2,
23782380
)
23792381
grid = ChunkGrid.from_metadata(a.metadata)
2380-
assert grid.dimensions[0].nchunks == 3
2381-
assert grid.dimensions[0].chunk_size(2) == 10
2382-
assert grid.dimensions[0].data_size(2) == 5
2382+
assert grid._dimensions[0].nchunks == 3
2383+
assert grid._dimensions[0].chunk_size(2) == 10
2384+
assert grid._dimensions[0].data_size(2) == 5
23832385

23842386

23852387
def test_v2_slicing_with_boundary(tmp_path: Path) -> None:
@@ -2714,7 +2716,7 @@ def test_property_block_indexing_rectilinear(data: st.DataObject) -> None:
27142716
grid = ChunkGrid.from_metadata(z.metadata)
27152717

27162718
for dim in range(a.ndim):
2717-
dim_grid = grid.dimensions[dim]
2719+
dim_grid = grid._dimensions[dim]
27182720
block_ix = data.draw(st.integers(min_value=0, max_value=dim_grid.nchunks - 1))
27192721
sel = [slice(None)] * a.ndim
27202722
start = dim_grid.chunk_offset(block_ix)

0 commit comments

Comments
 (0)