Skip to content

Commit fcb3cd3

Browse files
NIK-TIGER-BILLNIK-TIGER-BILL
andauthored
fix: allow writing to 0-dimensional arrays with sharding (zarr-developers#3966)
* fix: allow writing to 0-dimensional arrays with sharding Signed-off-by: NIK-TIGER-BILL <nik.tiger.bill@github.com> * test: directly cover get_chunk_slices_vectorized 0D path Signed-off-by: NIK-TIGER-BILL <nik.tiger.bill@github.com> * fix: ruff unused variable in zero-dim sharding test Signed-off-by: NIK-TIGER-BILL <nik.tiger.bill@github.com> --------- Signed-off-by: NIK-TIGER-BILL <nik.tiger.bill@github.com> Co-authored-by: NIK-TIGER-BILL <nik.tiger.bill@github.com>
1 parent eac9c86 commit fcb3cd3

2 files changed

Lines changed: 38 additions & 0 deletions

File tree

src/zarr/codecs/sharding.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,16 @@ def get_chunk_slices_vectorized(
171171
valid : ndarray of shape (n_chunks,)
172172
Boolean mask indicating which chunks are non-empty.
173173
"""
174+
# Handle 0-dimensional arrays (n_dims == 0)
175+
if chunk_coords_array.shape[1] == 0:
176+
# offsets_and_lengths has shape (2,) for 0D, reshape to (1, 2)
177+
offsets_and_lengths = self.offsets_and_lengths.reshape(1, 2)
178+
starts = offsets_and_lengths[:, 0]
179+
lengths = offsets_and_lengths[:, 1]
180+
valid = starts != MAX_UINT_64
181+
ends = starts + lengths
182+
return starts, ends, valid
183+
174184
# Localize coordinates via modulo (vectorized)
175185
shard_shape = np.array(self.offsets_and_lengths.shape[:-1], dtype=np.uint64)
176186
localized = chunk_coords_array.astype(np.uint64) % shard_shape

tests/test_codecs/test_sharding.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
ShardingCodecIndexLocation,
1717
TransposeCodec,
1818
)
19+
from zarr.codecs.sharding import MAX_UINT_64, _ShardIndex
1920
from zarr.core.buffer import NDArrayLike, default_buffer_prototype
2021
from zarr.storage import StorePath, ZipStore
2122

@@ -554,3 +555,30 @@ def test_sharding_mixed_integer_list_indexing(store: Store) -> None:
554555
s3 = sharded[0:5, 1, 0:3]
555556
assert c3.shape == s3.shape == (5, 3) # type: ignore[union-attr]
556557
np.testing.assert_array_equal(c3, s3)
558+
559+
560+
def test_sharding_zero_dimensional() -> None:
561+
"""Regression test for https://github.com/zarr-developers/zarr-python/issues/3751"""
562+
arr = zarr.create_array({}, shape=(), dtype="f4", chunks=(), shards=())
563+
arr[()] = 42.0
564+
assert arr[()] == pytest.approx(42.0)
565+
# Overwriting should also work
566+
arr[()] = 43.0
567+
assert arr[()] == pytest.approx(43.0)
568+
569+
570+
def test_shard_index_get_chunk_slices_vectorized_zero_dimensional() -> None:
571+
"""Directly cover the 0-D path in _ShardIndex.get_chunk_slices_vectorized."""
572+
# For a 0D array offsets_and_lengths has shape (2,) — reshape to (1, 2) inside.
573+
index = _ShardIndex(np.array([10, 4], dtype=np.uint64))
574+
chunk_coords = np.empty((1, 0), dtype=np.uint64)
575+
starts, ends, valid = index.get_chunk_slices_vectorized(chunk_coords)
576+
np.testing.assert_array_equal(starts, np.array([10], dtype=np.uint64))
577+
np.testing.assert_array_equal(ends, np.array([14], dtype=np.uint64))
578+
np.testing.assert_array_equal(valid, np.array([True]))
579+
580+
# Empty/unwritten chunk case
581+
index_empty = _ShardIndex(np.array([MAX_UINT_64, MAX_UINT_64], dtype=np.uint64))
582+
starts_e, _ends_e, valid_e = index_empty.get_chunk_slices_vectorized(chunk_coords)
583+
np.testing.assert_array_equal(starts_e, np.array([MAX_UINT_64], dtype=np.uint64))
584+
np.testing.assert_array_equal(valid_e, np.array([False]))

0 commit comments

Comments
 (0)