Skip to content

Commit b74b78d

Browse files
committed
chore: add informative error for invalid chunk grid parameter
1 parent 4668fe5 commit b74b78d

2 files changed

Lines changed: 62 additions & 6 deletions

File tree

src/zarr/core/chunk_grids.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,7 @@ def _guess_regular_chunks(
683683

684684

685685
def normalize_chunks_1d(
686-
chunks: int | Iterable[int], span: int
686+
chunks: int | Iterable[object], span: int
687687
) -> np.ndarray[tuple[int], np.dtype[np.int64]]:
688688
"""
689689
Normalize a one-dimensional chunk specification into a 1D int64 array of
@@ -707,11 +707,22 @@ def normalize_chunks_1d(
707707
chunk_list = list(chunks)
708708
if not chunk_list:
709709
raise ValueError("Chunk specification must not be empty")
710-
if any(c <= 0 for c in chunk_list):
711-
raise ValueError(f"All chunk sizes must be positive, got {chunk_list}")
712-
if sum(chunk_list) != span:
713-
raise ValueError(f"Chunk sizes {chunk_list} do not sum to span {span}")
714-
return np.asarray(chunk_list, dtype=np.int64)
710+
non_int = [
711+
(idx, c) for idx, c in enumerate(chunk_list) if not isinstance(c, numbers.Integral)
712+
]
713+
if non_int:
714+
non_int_idxs, non_int_vals = [*zip(*non_int, strict=False)]
715+
raise TypeError(
716+
f"Each chunk size must be an integer; got non-integer element(s) {non_int_vals!r} "
717+
f"at indices {non_int_idxs!r}. Chunk sizes must be declareds as a flat sequence of"
718+
f"positive integers (e.g. [3, 3, 1])."
719+
)
720+
ints: list[int] = [int(c) for c in chunk_list] # type: ignore[call-overload]
721+
if any(c <= 0 for c in ints):
722+
raise ValueError(f"All chunk sizes must be positive, got {ints}")
723+
if sum(ints) != span:
724+
raise ValueError(f"Chunk sizes {ints} do not sum to span {span}")
725+
return np.asarray(ints, dtype=np.int64)
715726

716727

717728
def normalize_chunks_nd(

tests/test_chunk_grids.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
import re
12
from typing import Any
23

34
import numpy as np
45
import pytest
56

7+
from tests.test_codecs.conftest import ExpectErr
68
from zarr.core.chunk_grids import (
79
_guess_regular_chunks,
810
normalize_chunks_nd,
@@ -141,6 +143,49 @@ def test_normalize_chunks_1d_errors() -> None:
141143
normalize_chunks_1d([10, 20], 100)
142144

143145

146+
@pytest.mark.parametrize(
147+
"case",
148+
[
149+
# The motivating case: nested/RLE form for a single dim.
150+
ExpectErr(
151+
input=([[3, 3], 1], 7),
152+
msg="non-integer element(s) ([3, 3],) at indices (0,)",
153+
exception_cls=TypeError,
154+
),
155+
# Multiple non-int elements report all offending indices.
156+
ExpectErr(
157+
input=([1, [2, 2], 1, [3]], 9),
158+
msg="non-integer element(s) ([2, 2], [3]) at indices (1, 3)",
159+
exception_cls=TypeError,
160+
),
161+
# Strings are also non-integers and should be reported the same way.
162+
ExpectErr(
163+
input=([2, "3", 5], 10),
164+
msg="non-integer element(s) ('3',) at indices (1,)",
165+
exception_cls=TypeError,
166+
),
167+
],
168+
ids=["rle-single-dim", "multiple-non-ints", "string-element"],
169+
)
170+
def test_normalize_chunks_1d_rejects_non_int_elements(
171+
case: ExpectErr[tuple[list[Any], int]],
172+
) -> None:
173+
"""Reject nested/RLE-style chunk specs with a precise error pointing at offending indices."""
174+
from zarr.core.chunk_grids import normalize_chunks_1d
175+
176+
chunks, span = case.input
177+
with pytest.raises(case.exception_cls, match=re.escape(case.msg)):
178+
normalize_chunks_1d(chunks, span=span)
179+
180+
181+
def test_normalize_chunks_nd_rejects_rle_inner_dim() -> None:
182+
"""End-to-end: a per-dim RLE form like [[3, 3], 1] surfaces the precise error."""
183+
with pytest.raises(
184+
TypeError, match=re.escape("non-integer element(s) ([3, 3],) at indices (0,)")
185+
):
186+
normalize_chunks_nd([[6, 4], [[3, 3], 1]], (10, 10))
187+
188+
144189
def test_normalize_chunks_errors() -> None:
145190
with pytest.raises(ValueError, match="does not accept None"):
146191
normalize_chunks_nd(None, (100,))

0 commit comments

Comments
 (0)