From 9421b30945b73a561a0a11720f69e85b1772c6ea Mon Sep 17 00:00:00 2001 From: Davis Vann Bennett Date: Wed, 9 Sep 2026 12:53:30 +0200 Subject: [PATCH 1/5] fix: accept numpy arrays as chunks/shards through the public API The #4257 changelog entry claims numpy arrays are accepted as chunk specifications, but that only held for `normalize_chunks_nd` when called directly. Every public creation entry point compares the specification to a string sentinel before normalizing it: `init_array` tests `chunks == "auto"`, `resolve_outer_and_inner_chunks` tests `shard_shape == "auto"`, and `_parse_keep_array_attr` tests `chunks == "keep"` / `shards == "keep"` on both of its branches. For a numpy array those comparisons are elementwise, and using the result in a boolean context raises numpy's "truth value of an array with more than one element is ambiguous" `ValueError`. `zarr.create_array`, `Group.create_array`, and `zarr.from_array` were all affected, for `chunks` and for `shards`. (`zarr.open_array` goes through the legacy `AsyncArray._create` path rather than `init_array` and was not affected.) Add `_is_auto` / `_is_keep` helpers to `chunk_grids.py` that guard the string comparison with `isinstance(spec, str)`, and route the six chunk/shard sentinel checks through them. The helpers return `TypeIs` so mypy keeps narrowing in both branches, exactly as the bare `==` did. Strings, tuples, lists, and numpy integer scalars behave as before; the comparisons for filters/compressors/serializer are untouched because those parameters never receive array-likes. Rebased over #4218 (542ceba2), which rewrote `chunk_grids.py` and the `init_array` / `_parse_keep_array_attr` bodies in `array.py`. The six sentinel-comparison sites survive the rewrite unchanged in kind; no new ones were introduced. `ChunkGridMetadata` values, which #4218 newly allows as `chunks=`, already worked because a dataclass `==` against a string is simply `False`, and they still pass through the guarded helpers. Assisted-by: ClaudeCode:claude-fable-5-1 --- changes/0000.bugfix.md | 1 + src/zarr/core/array.py | 14 ++++++++---- src/zarr/core/chunk_grids.py | 22 +++++++++++++++++- tests/test_array.py | 44 ++++++++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 changes/0000.bugfix.md diff --git a/changes/0000.bugfix.md b/changes/0000.bugfix.md new file mode 100644 index 0000000000..fe66235059 --- /dev/null +++ b/changes/0000.bugfix.md @@ -0,0 +1 @@ +Numpy arrays are now accepted as `chunks` and `shards` through the public array-creation API: `zarr.create_array`, `Group.create_array`, `zarr.from_array`, and the other entry points that build on them. The 3.3.x changelog entry for #4257 said numpy arrays were accepted as chunk specifications, but that only held for the internal normalizer `normalize_chunks_nd`: every public entry point first compared the specification to the `"auto"` or `"keep"` sentinel string, and for a numpy array that comparison raised numpy's ambiguous-truth-value `ValueError` before the normalizer was reached. Those sentinel checks are now guarded so array-like specifications pass through to the normalizer. diff --git a/src/zarr/core/array.py b/src/zarr/core/array.py index 3f67eb7c75..1061415216 100644 --- a/src/zarr/core/array.py +++ b/src/zarr/core/array.py @@ -43,6 +43,8 @@ from zarr.core.chunk_grids import ( SHARDED_INNER_CHUNK_MAX_BYTES, ChunkGrid, + _is_auto, + _is_keep, _is_rectilinear_chunks, guess_chunks, normalize_chunks_nd, @@ -4537,7 +4539,7 @@ async def init_array( # Normalize the user's chunks into a canonical ChunkGrid - if chunks == "auto": + if _is_auto(chunks): max_bytes = None if shards is None else SHARDED_INNER_CHUNK_MAX_BYTES chunks_normalized = guess_chunks(shape_parsed, item_size, max_bytes=max_bytes) else: @@ -4893,10 +4895,12 @@ def _parse_keep_array_attr( DimensionNamesLike, dict[str, JSON] | None, ]: + # chunks / shards may be numpy arrays, so their sentinel checks go through the + # isinstance-guarded helpers rather than a bare ``==`` against the string. if isinstance(data, Array): rectilinear_grid = _stored_rectilinear_grid_or_none(data.metadata) sharded = _sharding_codec(data.metadata) is not None - if chunks == "keep": + if _is_keep(chunks): if rectilinear_grid is None or sharded: # `.chunks` is the inner chunk shape when sharding is used, and # inner chunks are regular whatever the shape of the shard grid. @@ -4908,7 +4912,7 @@ def _parse_keep_array_attr( # and trailing edges beyond the extent left behind by a # shrinking resize. chunks = rectilinear_grid - if shards == "keep": + if _is_keep(shards): if rectilinear_grid is None: shards = data.shards elif sharded: @@ -4960,9 +4964,9 @@ def _parse_keep_array_attr( # array's in-memory metadata and the new array's. attributes = copy.deepcopy(dict(data.attrs)) else: - if chunks == "keep": + if _is_keep(chunks): chunks = "auto" - if shards == "keep": + if _is_keep(shards): shards = None if zarr_format is None: zarr_format = 3 diff --git a/src/zarr/core/chunk_grids.py b/src/zarr/core/chunk_grids.py index 6242994fdf..cc27366027 100644 --- a/src/zarr/core/chunk_grids.py +++ b/src/zarr/core/chunk_grids.py @@ -11,6 +11,7 @@ from typing import ( TYPE_CHECKING, Any, + Literal, NamedTuple, Protocol, cast, @@ -19,6 +20,7 @@ import numpy as np import numpy.typing as npt +from typing_extensions import TypeIs import zarr from zarr.core.common import ( @@ -314,6 +316,24 @@ def is_boundary(self) -> bool: # list of ints (explicit edges), or mixed RLE (e.g. [[10, 3], 5]). +def _is_auto(spec: object) -> TypeIs[Literal["auto"]]: + """Check whether a chunk or shard specification is the ``"auto"`` sentinel. + + Specifications may be numpy arrays, whose ``==`` against a string is + elementwise and cannot be used in a boolean context, so the string check + must be guarded by ``isinstance``. + """ + return isinstance(spec, str) and spec == "auto" + + +def _is_keep(spec: object) -> TypeIs[Literal["keep"]]: + """Check whether a chunk or shard specification is the ``"keep"`` sentinel. + + See `_is_auto` for why this is not a bare ``==`` comparison. + """ + return isinstance(spec, str) and spec == "keep" + + def _is_rectilinear_chunks(chunks: Any) -> bool: """Check if chunks specifies a rectilinear grid along any dimension. @@ -940,7 +960,7 @@ def resolve_outer_and_inner_chunks( # Extract the flat chunk shape (uniform size per dimension) for arithmetic. chunk_shape_flat = chunks.chunk_shape - if shard_shape == "auto": + if _is_auto(shard_shape): warnings.warn( "Automatic shard shape inference is experimental and may change without notice.", ZarrUserWarning, diff --git a/tests/test_array.py b/tests/test_array.py index a1cd687ab9..af2a54248b 100644 --- a/tests/test_array.py +++ b/tests/test_array.py @@ -1155,6 +1155,50 @@ def test_chunks_and_shards() -> None: assert arr_v2.shards is None +def _as_chunk_spec(kind: str, spec: tuple[int, ...]) -> Any: + """Express ``spec`` as one of the accepted chunk-specification forms.""" + if kind == "int-tuple": + return spec + if kind == "numpy-array": + return np.array(spec) + assert kind == "numpy-int-tuple" + return tuple(np.int64(c) for c in spec) + + +@pytest.mark.parametrize( + "entry_point", ["create_array", "group_create_array", "from_array_ndarray", "from_array_zarr"] +) +@pytest.mark.parametrize("spec_kind", ["int-tuple", "numpy-array", "numpy-int-tuple"]) +@pytest.mark.parametrize("with_shards", [False, True], ids=["no-shards", "shards"]) +def test_chunk_spec_forms_via_public_api( + entry_point: str, spec_kind: str, with_shards: bool +) -> None: + """Numpy arrays and numpy integers are accepted as ``chunks`` / ``shards`` through every + public creation entry point, not only through the internal chunk normalizer. The entry + points compare the specification against the ``"auto"`` / ``"keep"`` sentinels first, and + a numpy array must not reach a bare ``==``-with-string test. + """ + shape, chunks, shards = (8, 8), (2, 2), (4, 4) + kwargs: dict[str, Any] = { + "chunks": _as_chunk_spec(spec_kind, chunks), + "shards": _as_chunk_spec(spec_kind, shards) if with_shards else None, + } + if entry_point == "create_array": + arr = zarr.create_array({}, shape=shape, dtype="i4", **kwargs) + elif entry_point == "group_create_array": + arr = zarr.create_group({}).create_array("a", shape=shape, dtype="i4", **kwargs) + elif entry_point == "from_array_ndarray": + arr = zarr.from_array({}, data=np.zeros(shape, dtype="i4"), **kwargs) + else: + # A zarr Array source takes the branch of ``_parse_keep_array_attr`` that would + # otherwise inherit the source's chunks / shards. + assert entry_point == "from_array_zarr" + source = zarr.create_array({}, shape=shape, dtype="i4", chunks=(4, 4)) + arr = zarr.from_array({}, data=source, **kwargs) + assert arr.chunks == chunks + assert arr.shards == (shards if with_shards else None) + + @pytest.mark.parametrize("store", ["memory"], indirect=True) @pytest.mark.filterwarnings("ignore::zarr.core.dtype.common.UnstableSpecificationWarning") @pytest.mark.parametrize( From 104c82b775160e32690609b726f5b6cab50428f9 Mon Sep 17 00:00:00 2001 From: Davis Vann Bennett Date: Wed, 9 Sep 2026 12:54:28 +0200 Subject: [PATCH 2/5] chore: rename changelog fragment to the PR number Assisted-by: ClaudeCode:claude-fable-5-1 --- changes/{0000.bugfix.md => 4329.bugfix.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename changes/{0000.bugfix.md => 4329.bugfix.md} (100%) diff --git a/changes/0000.bugfix.md b/changes/4329.bugfix.md similarity index 100% rename from changes/0000.bugfix.md rename to changes/4329.bugfix.md From 7640ad01c703b5ee5a32182b1d12d02b5b0ff44d Mon Sep 17 00:00:00 2001 From: Davis Vann Bennett Date: Wed, 9 Sep 2026 21:05:20 +0200 Subject: [PATCH 3/5] docs: relabel as a feature and correct the #4257 changelog entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Measured across 3.0.10, 3.1.6, 3.2.1, 3.3.0 and main: create_array, Group.create_array and from_array have never accepted a numpy array as chunks or shards, so this is a new capability for that API, not a fix. The legacy zarr.create / zarr.array / zarr.open_array functions accepted numpy arrays in 2.x and 3.2.x, lost them in 3.3.0 with the numpy-integer regression, and got them back in #4257 — which is what that entry's "numpy arrays are now also accepted" meant. Say so there, and describe this change as the feature it is. Assisted-by: ClaudeCode:claude-fable-5-1 --- changes/4257.bugfix.md | 2 +- changes/4329.bugfix.md | 1 - changes/4329.feature.md | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 changes/4329.bugfix.md create mode 100644 changes/4329.feature.md diff --git a/changes/4257.bugfix.md b/changes/4257.bugfix.md index 6f2740ccb4..f643cf31f0 100644 --- a/changes/4257.bugfix.md +++ b/changes/4257.bugfix.md @@ -1 +1 @@ -Numpy integers are accepted as chunk sizes again. Since 3.3.0 a per-dimension chunk size that was a numpy integer (e.g. `chunks=(np.int64(2), np.int64(2))`, as produced by any computed chunk shape) raised `TypeError: 'numpy.int64' object is not iterable`, because the scalar chunk path narrowed on `int` while its caller dispatched on `numbers.Integral`. Numpy arrays are now also accepted as chunk specifications, and a chunk specification that is neither an integer nor iterable now reports the offending value instead of failing with an opaque iteration error. +Numpy integers are accepted as chunk sizes again. Since 3.3.0 a per-dimension chunk size that was a numpy integer (e.g. `chunks=(np.int64(2), np.int64(2))`, as produced by any computed chunk shape) raised `TypeError: 'numpy.int64' object is not iterable`, because the scalar chunk path narrowed on `int` while its caller dispatched on `numbers.Integral`. The same regression had broken numpy arrays as chunk specifications through the legacy `zarr.create` / `zarr.array` / `zarr.open_array` functions, which accepted them in 2.x and 3.2.x; those work again. (`zarr.create_array` and the functions built on it gain numpy-array support separately, in #4329.) A chunk specification that is neither an integer nor iterable now reports the offending value instead of failing with an opaque iteration error. diff --git a/changes/4329.bugfix.md b/changes/4329.bugfix.md deleted file mode 100644 index fe66235059..0000000000 --- a/changes/4329.bugfix.md +++ /dev/null @@ -1 +0,0 @@ -Numpy arrays are now accepted as `chunks` and `shards` through the public array-creation API: `zarr.create_array`, `Group.create_array`, `zarr.from_array`, and the other entry points that build on them. The 3.3.x changelog entry for #4257 said numpy arrays were accepted as chunk specifications, but that only held for the internal normalizer `normalize_chunks_nd`: every public entry point first compared the specification to the `"auto"` or `"keep"` sentinel string, and for a numpy array that comparison raised numpy's ambiguous-truth-value `ValueError` before the normalizer was reached. Those sentinel checks are now guarded so array-like specifications pass through to the normalizer. diff --git a/changes/4329.feature.md b/changes/4329.feature.md new file mode 100644 index 0000000000..65b0bc598f --- /dev/null +++ b/changes/4329.feature.md @@ -0,0 +1 @@ +`zarr.create_array`, `Group.create_array`, `zarr.from_array`, and the entry points built on them now accept a numpy array as the `chunks` or `shards` specification, alongside ints, tuples, and numpy integer scalars. This is new for that API: it has never accepted numpy arrays in any 3.x release, because each entry point compared the specification to the `"auto"` or `"keep"` sentinel string before normalizing it, and for a numpy array that comparison raised numpy's ambiguous-truth-value `ValueError`. Those sentinel checks are now guarded so array-like specifications reach the normalizer, bringing this API in line with the legacy `zarr.create` / `zarr.array` / `zarr.open_array` functions, which have accepted numpy arrays since 2.x. From 2f4e43188be0873bde9bd5dfc424e93938133e3d Mon Sep 17 00:00:00 2001 From: Davis Vann Bennett Date: Wed, 9 Sep 2026 20:19:34 +0200 Subject: [PATCH 4/5] test: cover chunk specifications in existing API tests Assisted-by: Codex:gpt-6 --- tests/test_array.py | 93 ++++++++++++++++++--------------------------- tests/test_group.py | 23 +++++++++-- 2 files changed, 57 insertions(+), 59 deletions(-) diff --git a/tests/test_array.py b/tests/test_array.py index af2a54248b..29a5fdfa4c 100644 --- a/tests/test_array.py +++ b/tests/test_array.py @@ -32,6 +32,7 @@ AsyncArray, CompressorsLike, FiltersLike, + ShardsLike, _iter_chunk_coords, _iter_chunk_regions, _iter_shard_coords, @@ -53,7 +54,7 @@ resolve_outer_and_inner_chunks, ) from zarr.core.chunk_key_encodings import ChunkKeyEncodingParams -from zarr.core.common import JSON, ZarrFormat, ceildiv +from zarr.core.common import JSON, ChunksLike, ZarrFormat, ceildiv from zarr.core.dtype import ( DateTime64, Float32, @@ -1128,14 +1129,22 @@ def test_auto_partition_auto_shards_with_auto_chunks_should_be_close_to_1MiB() - assert all(s % c == 0 for s, c in zip(shard_shape, chunk_shape, strict=True)) -def test_chunks_and_shards() -> None: +@pytest.mark.parametrize( + "chunks", + [(5, 5), [5, 5], np.array([5, 5]), (np.int64(5), np.int64(5))], + ids=["tuple", "list", "array", "numpy-scalars"], +) +@pytest.mark.parametrize( + "shards", + [(10, 10), [10, 10], np.array([10, 10]), (np.int64(10), np.int64(10))], + ids=["tuple", "list", "array", "numpy-scalars"], +) +def test_chunks_and_shards(chunks: ChunksLike, shards: ShardsLike) -> None: store = StorePath(MemoryStore()) shape = (100, 100) - chunks = (5, 5) - shards = (10, 10) arr_v3 = zarr.create_array(store=store / "v3", shape=shape, chunks=chunks, dtype="i4") - assert arr_v3.chunks == chunks + assert arr_v3.chunks == (5, 5) assert arr_v3.shards is None arr_v3_sharding = zarr.create_array( @@ -1145,60 +1154,16 @@ def test_chunks_and_shards() -> None: shards=shards, dtype="i4", ) - assert arr_v3_sharding.chunks == chunks - assert arr_v3_sharding.shards == shards + assert arr_v3_sharding.chunks == (5, 5) + assert arr_v3_sharding.shards == (10, 10) arr_v2 = zarr.create_array( store=store / "v2", shape=shape, chunks=chunks, zarr_format=2, dtype="i4" ) - assert arr_v2.chunks == chunks + assert arr_v2.chunks == (5, 5) assert arr_v2.shards is None -def _as_chunk_spec(kind: str, spec: tuple[int, ...]) -> Any: - """Express ``spec`` as one of the accepted chunk-specification forms.""" - if kind == "int-tuple": - return spec - if kind == "numpy-array": - return np.array(spec) - assert kind == "numpy-int-tuple" - return tuple(np.int64(c) for c in spec) - - -@pytest.mark.parametrize( - "entry_point", ["create_array", "group_create_array", "from_array_ndarray", "from_array_zarr"] -) -@pytest.mark.parametrize("spec_kind", ["int-tuple", "numpy-array", "numpy-int-tuple"]) -@pytest.mark.parametrize("with_shards", [False, True], ids=["no-shards", "shards"]) -def test_chunk_spec_forms_via_public_api( - entry_point: str, spec_kind: str, with_shards: bool -) -> None: - """Numpy arrays and numpy integers are accepted as ``chunks`` / ``shards`` through every - public creation entry point, not only through the internal chunk normalizer. The entry - points compare the specification against the ``"auto"`` / ``"keep"`` sentinels first, and - a numpy array must not reach a bare ``==``-with-string test. - """ - shape, chunks, shards = (8, 8), (2, 2), (4, 4) - kwargs: dict[str, Any] = { - "chunks": _as_chunk_spec(spec_kind, chunks), - "shards": _as_chunk_spec(spec_kind, shards) if with_shards else None, - } - if entry_point == "create_array": - arr = zarr.create_array({}, shape=shape, dtype="i4", **kwargs) - elif entry_point == "group_create_array": - arr = zarr.create_group({}).create_array("a", shape=shape, dtype="i4", **kwargs) - elif entry_point == "from_array_ndarray": - arr = zarr.from_array({}, data=np.zeros(shape, dtype="i4"), **kwargs) - else: - # A zarr Array source takes the branch of ``_parse_keep_array_attr`` that would - # otherwise inherit the source's chunks / shards. - assert entry_point == "from_array_zarr" - source = zarr.create_array({}, shape=shape, dtype="i4", chunks=(4, 4)) - arr = zarr.from_array({}, data=source, **kwargs) - assert arr.chunks == chunks - assert arr.shards == (shards if with_shards else None) - - @pytest.mark.parametrize("store", ["memory"], indirect=True) @pytest.mark.filterwarnings("ignore::zarr.core.dtype.common.UnstableSpecificationWarning") @pytest.mark.parametrize( @@ -1801,14 +1766,26 @@ async def test_creation_from_other_zarr_format( @pytest.mark.parametrize("store", ["local", "memory", "zip"], indirect=True) @pytest.mark.parametrize("store2", ["local", "memory", "zip"], indirect=["store2"]) @pytest.mark.parametrize("src_chunks", [(40, 10), (11, 50)]) -@pytest.mark.parametrize("new_chunks", [(40, 10), (11, 50)]) +@pytest.mark.parametrize( + "new_chunks", [(40, 10), (11, 50), [40, 10], np.array([11, 50]), (np.int64(40), np.int64(10))] +) +@pytest.mark.parametrize( + "new_shards", + [None, (440, 100), [440, 100], np.array([440, 100]), (np.int64(440), np.int64(100))], + ids=["none", "tuple", "list", "array", "numpy-scalars"], +) +@pytest.mark.parametrize("source_as_numpy", [False, True], ids=["zarr", "numpy"]) async def test_from_array( store: Store, store2: Store, src_chunks: tuple[int, int], - new_chunks: tuple[int, int], + new_chunks: ChunksLike, + new_shards: ShardsLike | None, + source_as_numpy: bool, zarr_format: ZarrFormat, ) -> None: + if zarr_format == 2 and new_shards is not None: + pytest.skip("Zarr format 2 does not support sharding") src_fill_value = 2 src_dtype = np.dtype("uint8") src_attributes = None @@ -1820,6 +1797,7 @@ async def test_from_array( store=store, fill_value=src_fill_value, attributes=src_attributes, + zarr_format=zarr_format, ) src[:] = np.arange(1000).reshape((100, 10)) @@ -1827,18 +1805,21 @@ async def test_from_array( new_attributes: dict[str, JSON] = {"foo": "bar"} result = zarr.from_array( - data=src, + data=np.asarray(src) if source_as_numpy else src, store=store2, chunks=new_chunks, + shards=new_shards, fill_value=new_fill_value, attributes=new_attributes, + zarr_format=zarr_format, ) np.testing.assert_array_equal(result[:], src[:]) assert result.fill_value == new_fill_value assert result.dtype == src_dtype assert result.attrs == new_attributes - assert result.chunks == new_chunks + np.testing.assert_array_equal(result.chunks, new_chunks) + np.testing.assert_array_equal(result.shards, new_shards) @pytest.mark.parametrize("store", ["local"], indirect=True) diff --git a/tests/test_group.py b/tests/test_group.py index f7f2333ef5..4ce326621f 100644 --- a/tests/test_group.py +++ b/tests/test_group.py @@ -60,8 +60,9 @@ import pathlib from collections.abc import Callable + from zarr.core.array import ShardsLike from zarr.core.buffer.core import Buffer - from zarr.core.common import JSON, ZarrFormat + from zarr.core.common import JSON, ChunksLike, ZarrFormat from zarr.core.dtype import ZDType, ZDTypeLike @@ -783,21 +784,35 @@ async def test_group_update_attributes_async(store: Store, zarr_format: ZarrForm @pytest.mark.parametrize("name", ["a", "/a"]) +@pytest.mark.parametrize( + "chunks", + [(2, 2), [2, 2], np.array([2, 2]), (np.int64(2), np.int64(2))], + ids=["tuple", "list", "array", "numpy-scalars"], +) +@pytest.mark.parametrize( + "shards", + [None, (4, 4), [4, 4], np.array([4, 4]), (np.int64(4), np.int64(4))], + ids=["none", "tuple", "list", "array", "numpy-scalars"], +) def test_group_create_array( store: Store, zarr_format: ZarrFormat, overwrite: bool, name: str, + chunks: ChunksLike, + shards: ShardsLike | None, ) -> None: """ - Test `Group.from_store` + Test `Group.create_array` """ + if zarr_format == 2 and shards is not None: + pytest.skip("Zarr format 2 does not support sharding") group = Group.from_store(store, zarr_format=zarr_format) shape = (10, 10) dtype = "uint8" data = np.arange(np.prod(shape)).reshape(shape).astype(dtype) - array = group.create_array(name=name, shape=shape, dtype=dtype) + array = group.create_array(name=name, shape=shape, dtype=dtype, chunks=chunks, shards=shards) array[:] = data if not overwrite: @@ -807,6 +822,8 @@ def test_group_create_array( assert array.path == normalize_path(name) assert array.name == f"/{array.path}" + assert array.chunks == (2, 2) + np.testing.assert_array_equal(array.shards, shards) assert array.shape == shape assert array.dtype == np.dtype(dtype) assert np.array_equal(array[:], data) From 509c9d53cf1b2646f28d1c5cc761ff2ce629f946 Mon Sep 17 00:00:00 2001 From: Davis Vann Bennett Date: Wed, 9 Sep 2026 20:27:10 +0200 Subject: [PATCH 5/5] test: derive expected chunk shapes from normalization Assisted-by: Codex:gpt-6 --- tests/test_array.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/test_array.py b/tests/test_array.py index 29a5fdfa4c..4fcba12207 100644 --- a/tests/test_array.py +++ b/tests/test_array.py @@ -1142,9 +1142,11 @@ def test_auto_partition_auto_shards_with_auto_chunks_should_be_close_to_1MiB() - def test_chunks_and_shards(chunks: ChunksLike, shards: ShardsLike) -> None: store = StorePath(MemoryStore()) shape = (100, 100) + expected_chunks = normalize_chunks_nd(chunks, shape).chunk_shape + expected_shards = normalize_chunks_nd(shards, shape).chunk_shape arr_v3 = zarr.create_array(store=store / "v3", shape=shape, chunks=chunks, dtype="i4") - assert arr_v3.chunks == (5, 5) + assert arr_v3.chunks == expected_chunks assert arr_v3.shards is None arr_v3_sharding = zarr.create_array( @@ -1154,13 +1156,13 @@ def test_chunks_and_shards(chunks: ChunksLike, shards: ShardsLike) -> None: shards=shards, dtype="i4", ) - assert arr_v3_sharding.chunks == (5, 5) - assert arr_v3_sharding.shards == (10, 10) + assert arr_v3_sharding.chunks == expected_chunks + assert arr_v3_sharding.shards == expected_shards arr_v2 = zarr.create_array( store=store / "v2", shape=shape, chunks=chunks, zarr_format=2, dtype="i4" ) - assert arr_v2.chunks == (5, 5) + assert arr_v2.chunks == expected_chunks assert arr_v2.shards is None