Skip to content

Commit 047a92e

Browse files
committed
docs: state what 2.x actually did with a zero chunk edge
Measured against zarr 2.18.7: `zeros((0,), chunks=False)`, `chunks=-1` and `chunks=(0,)` all write `chunks: [0]`, after which nchunks, read, write, append, resize and reopen-then-read every raise ZeroDivisionError. There was never a working behaviour to preserve; normalizing the edge to 1 makes such arrays usable for the first time. Say so in the comment and fragment instead of claiming the stores were previously readable. Assisted-by: ClaudeCode:claude-fable-5-1
1 parent 921be0d commit 047a92e

2 files changed

Lines changed: 7 additions & 4 deletions

File tree

‎changes/4334.bugfix.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Zero-length dimensions are now handled by a single rule instead of a per-spelling patch: a chunk edge length is always at least 1, while a dimension's extent may be 0 (such a dimension simply has zero chunks). Every way of asking for "one chunk covering the axis" — `chunks=-1`, `chunks=False`, `chunks="auto"`, and `shards="auto"` — now derives the chunk size from the same helper, so they agree on chunk size 1 for a zero-length axis in both Zarr formats. Zarr format 2 metadata now applies the same rule: a stored chunk edge length of 0 on a zero-length axis — which zarr-python 2.x wrote for `chunks=False` and `chunks=(0,)` — is read as 1 (with a `ZarrUserWarning`) so those stores stay readable and no longer read uninitialised data after a resize, while a chunk edge of 0 on an axis that has data is rejected with a clear error. Rectilinear chunk grids (`chunks=[[...], ...]`) can now be created on a zero-length dimension: since no list of positive edge lengths can sum to 0, the given edge lengths are stored as-is and describe the chunks the dimension will grow into on `append` or `resize`, exactly the state a rectilinear dimension is in after being resized down to 0. The private `FixedDimension(size=0, ...)` model, which previously carried its own zero-size special cases, now raises `ValueError`.
1+
Zero-length dimensions are now handled by a single rule instead of a per-spelling patch: a chunk edge length is always at least 1, while a dimension's extent may be 0 (such a dimension simply has zero chunks). Every way of asking for "one chunk covering the axis" — `chunks=-1`, `chunks=False`, `chunks="auto"`, and `shards="auto"` — now derives the chunk size from the same helper, so they agree on chunk size 1 for a zero-length axis in both Zarr formats. Zarr format 2 metadata now applies the same rule: a stored chunk edge length of 0 on a zero-length axis — which zarr-python 2.x wrote for `chunks=False`, `chunks=-1` and `chunks=(0,)` and then could never read, write, append to or resize (every operation raised `ZeroDivisionError`), and which 3.0–3.3 opened but lost data on append — is read as 1 with a `ZarrUserWarning`, making such arrays usable, while a chunk edge of 0 on an axis that has data is rejected with a clear error. Rectilinear chunk grids (`chunks=[[...], ...]`) can now be created on a zero-length dimension: since no list of positive edge lengths can sum to 0, the given edge lengths are stored as-is and describe the chunks the dimension will grow into on `append` or `resize`, exactly the state a rectilinear dimension is in after being resized down to 0. The private `FixedDimension(size=0, ...)` model, which previously carried its own zero-size special cases, now raises `ValueError`.

‎src/zarr/core/metadata/v2.py‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,12 @@ def __init__(
9191
chunks_parsed = parse_shapelike(chunks)
9292
# Same invariant as the Zarr format 3 chunk grid metadata: every chunk edge
9393
# length is at least 1. zarr-python 2.x wrote `chunks: [0]` for a zero-length
94-
# axis created with `chunks=False` or `chunks=(0,)`. Such an axis holds no
95-
# chunks, so those documents are readable; the edge is normalized to 1 so a
96-
# later resize does not divide by zero. On an axis that has data, 0 is invalid.
94+
# axis created with `chunks=False`, `-1` or `(0,)`, and then could not read,
95+
# write, append to or resize the array (every operation divided by zero);
96+
# 3.0-3.3 opened such documents but lost data on append. The axis holds no
97+
# chunks, so the edge is normalized to 1 — the grid every other "one chunk
98+
# spans the axis" spelling produces — which makes the array usable at last.
99+
# On an axis that has data, 0 is invalid and any data was never stored.
97100
normalized_chunks: list[int] = []
98101
for dim_idx, (extent, chunk) in enumerate(zip(shape_parsed, chunks_parsed, strict=False)):
99102
if chunk < 1:

0 commit comments

Comments
 (0)