Skip to content

Commit 49ab7a2

Browse files
author
Claude Subagent
committed
refactor: Separate registry logic from ChunkGrid base class (fixes #3734)
- Remove ChunkGrid.from_dict class method that handled registry dispatch - Create new parse_chunk_grid function to handle deserialization - Update ArrayV3Metadata to use parse_chunk_grid instead of ChunkGrid.from_dict - Follows the same pattern as parse_chunk_key_encoding for consistency - Improves separation of concerns by removing registry responsibility from base class
1 parent b6d3ae2 commit 49ab7a2

3 files changed

Lines changed: 54 additions & 12 deletions

File tree

changes/3734.refactor.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Refactor: Separate registry logic from ChunkGrid base class (fixes #3734)
2+
3+
## Summary
4+
The `ChunkGrid` base class previously contained registry logic in its `from_dict` class method, which was responsible for dispatching to the appropriate subclass (e.g., `RegularChunkGrid`) based on the configuration. This violated the separation of concerns principle.
5+
6+
## Changes
7+
1. **Removed `from_dict` from `ChunkGrid` base class**: The base class no longer handles the dispatch logic.
8+
2. **Created `parse_chunk_grid` function**: A new module-level function now handles the deserialization and dispatch to appropriate subclasses. This follows the same pattern as other similar functions in the codebase (e.g., `parse_chunk_key_encoding`).
9+
3. **Updated `ArrayV3Metadata`**: The metadata class now uses `parse_chunk_grid` instead of `ChunkGrid.from_dict`.
10+
11+
## Benefits
12+
- **Separation of concerns**: The base class is now a pure data structure without registry responsibilities.
13+
- **Consistency**: The pattern now matches other similar types in the codebase (e.g., chunk key encodings).
14+
- **Extensibility**: New chunk grid types can be registered without modifying the base class.
15+
- **Clearer intent**: The registry logic is now explicit via the `parse_chunk_grid` function.
16+
17+
## API Changes
18+
- **Breaking**: Code that directly called `ChunkGrid.from_dict()` should now call `parse_chunk_grid()` instead.
19+
- **Non-breaking**: Internal uses within the library have been updated. Public API users may need to update if they were directly using `ChunkGrid.from_dict()`.

src/zarr/core/chunk_grids.py

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -155,16 +155,6 @@ def normalize_chunks(chunks: Any, shape: tuple[int, ...], typesize: int) -> tupl
155155

156156
@dataclass(frozen=True)
157157
class ChunkGrid(Metadata):
158-
@classmethod
159-
def from_dict(cls, data: dict[str, JSON] | ChunkGrid | NamedConfig[str, Any]) -> ChunkGrid:
160-
if isinstance(data, ChunkGrid):
161-
return data
162-
163-
name_parsed, _ = parse_named_configuration(data)
164-
if name_parsed == "regular":
165-
return RegularChunkGrid._from_dict(data)
166-
raise ValueError(f"Unknown chunk grid. Got {name_parsed}.")
167-
168158
@abstractmethod
169159
def all_chunk_coords(self, array_shape: tuple[int, ...]) -> Iterator[tuple[int, ...]]:
170160
pass
@@ -205,6 +195,39 @@ def get_nchunks(self, array_shape: tuple[int, ...]) -> int:
205195
)
206196

207197

198+
def parse_chunk_grid(data: dict[str, JSON] | ChunkGrid | NamedConfig[str, Any]) -> ChunkGrid:
199+
"""
200+
Take an implicit specification of a chunk grid and parse it into a ChunkGrid object.
201+
202+
This function handles the deserialization of chunk grid configurations, dispatching
203+
to the appropriate ChunkGrid subclass based on the `name` field.
204+
205+
Parameters
206+
----------
207+
data : dict[str, JSON] | ChunkGrid | NamedConfig[str, Any]
208+
The chunk grid specification. Can be:
209+
- A ChunkGrid instance (returned as-is)
210+
- A dict or NamedConfig with a "name" field specifying the type
211+
212+
Returns
213+
-------
214+
ChunkGrid
215+
The parsed ChunkGrid instance.
216+
217+
Raises
218+
------
219+
ValueError
220+
If the chunk grid type is unknown.
221+
"""
222+
if isinstance(data, ChunkGrid):
223+
return data
224+
225+
name_parsed, _ = parse_named_configuration(data)
226+
if name_parsed == "regular":
227+
return RegularChunkGrid._from_dict(data)
228+
raise ValueError(f"Unknown chunk grid. Got {name_parsed}.")
229+
230+
208231
def _guess_num_chunks_per_axis_shard(
209232
chunk_shape: tuple[int, ...], item_size: int, max_bytes: int, array_shape: tuple[int, ...]
210233
) -> int:

src/zarr/core/metadata/v3.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
from zarr.abc.codec import ArrayArrayCodec, ArrayBytesCodec, BytesBytesCodec, Codec
2626
from zarr.core.array_spec import ArrayConfig, ArraySpec
27-
from zarr.core.chunk_grids import ChunkGrid, RegularChunkGrid
27+
from zarr.core.chunk_grids import ChunkGrid, RegularChunkGrid, parse_chunk_grid
2828
from zarr.core.chunk_key_encodings import (
2929
ChunkKeyEncoding,
3030
ChunkKeyEncodingLike,
@@ -229,7 +229,7 @@ def __init__(
229229
"""
230230

231231
shape_parsed = parse_shapelike(shape)
232-
chunk_grid_parsed = ChunkGrid.from_dict(chunk_grid)
232+
chunk_grid_parsed = parse_chunk_grid(chunk_grid)
233233
chunk_key_encoding_parsed = parse_chunk_key_encoding(chunk_key_encoding)
234234
dimension_names_parsed = parse_dimension_names(dimension_names)
235235
# Note: relying on a type method is numpy-specific

0 commit comments

Comments
 (0)