Skip to content

Commit 2c6e2bc

Browse files
authored
Merge branch 'main' into test-stateful-hierarchy
2 parents cccdd89 + d1075de commit 2c6e2bc

File tree

13 files changed

+61
-16
lines changed

13 files changed

+61
-16
lines changed

src/zarr/abc/store.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,6 @@ async def _set_many(self, values: Iterable[tuple[str, Buffer]]) -> None:
284284
Insert multiple (key, value) pairs into storage.
285285
"""
286286
await gather(*starmap(self.set, values))
287-
return
288287

289288
@property
290289
@abstractmethod

src/zarr/api/asynchronous.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
from zarr.abc.store import Store
1212
from zarr.core.array import Array, AsyncArray, get_array_metadata
13+
from zarr.core.buffer import NDArrayLike
1314
from zarr.core.common import (
1415
JSON,
1516
AccessModeLiteral,
@@ -31,7 +32,6 @@
3132
from collections.abc import Iterable
3233

3334
from zarr.abc.codec import Codec
34-
from zarr.core.buffer import NDArrayLike
3535
from zarr.core.chunk_key_encodings import ChunkKeyEncoding
3636

3737
# TODO: this type could use some more thought
@@ -393,6 +393,8 @@ async def save_array(
393393
_handle_zarr_version_or_format(zarr_version=zarr_version, zarr_format=zarr_format)
394394
or _default_zarr_version()
395395
)
396+
if not isinstance(arr, NDArrayLike):
397+
raise TypeError("arr argument must be numpy or other NDArrayLike array")
396398

397399
mode = kwargs.pop("mode", None)
398400
store_path = await make_store_path(store, path=path, mode=mode, storage_options=storage_options)
@@ -447,16 +449,26 @@ async def save_group(
447449
or _default_zarr_version()
448450
)
449451

452+
for arg in args:
453+
if not isinstance(arg, NDArrayLike):
454+
raise TypeError(
455+
"All arguments must be numpy or other NDArrayLike arrays (except store, path, storage_options, and zarr_format)"
456+
)
457+
for k, v in kwargs.items():
458+
if not isinstance(v, NDArrayLike):
459+
raise TypeError(f"Keyword argument '{k}' must be a numpy or other NDArrayLike array")
460+
450461
if len(args) == 0 and len(kwargs) == 0:
451462
raise ValueError("at least one array must be provided")
452463
aws = []
453464
for i, arr in enumerate(args):
465+
_path = f"{path}/arr_{i}" if path is not None else f"arr_{i}"
454466
aws.append(
455467
save_array(
456468
store,
457469
arr,
458470
zarr_format=zarr_format,
459-
path=f"{path}/arr_{i}",
471+
path=_path,
460472
storage_options=storage_options,
461473
)
462474
)

src/zarr/codecs/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,13 @@
99
from zarr.codecs.bytes import BytesCodec, Endian
1010
from zarr.codecs.crc32c_ import Crc32cCodec
1111
from zarr.codecs.gzip import GzipCodec
12-
from zarr.codecs.pipeline import BatchedCodecPipeline
1312
from zarr.codecs.sharding import ShardingCodec, ShardingCodecIndexLocation
1413
from zarr.codecs.transpose import TransposeCodec
1514
from zarr.codecs.vlen_utf8 import VLenBytesCodec, VLenUTF8Codec
1615
from zarr.codecs.zstd import ZstdCodec
1716
from zarr.core.metadata.v3 import DataType
1817

1918
__all__ = [
20-
"BatchedCodecPipeline",
2119
"BloscCname",
2220
"BloscCodec",
2321
"BloscShuffle",

src/zarr/codecs/registry.py

Whitespace-only changes.

src/zarr/codecs/sharding.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ def create_empty(
252252
def __setitem__(self, chunk_coords: ChunkCoords, value: Buffer) -> None:
253253
chunk_start = len(self.buf)
254254
chunk_length = len(value)
255-
self.buf = self.buf + value
255+
self.buf += value
256256
self.index.set_chunk_slice(chunk_coords, slice(chunk_start, chunk_start + chunk_length))
257257

258258
def __delitem__(self, chunk_coords: ChunkCoords) -> None:

src/zarr/core/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from __future__ import annotations
2+
3+
from zarr.core.buffer import Buffer, NDBuffer # noqa: F401
4+
from zarr.core.codec_pipeline import BatchedCodecPipeline # noqa: F401
File renamed without changes.

src/zarr/core/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def reset(self) -> None:
4747
"threading": {"max_workers": None},
4848
"json_indent": 2,
4949
"codec_pipeline": {
50-
"path": "zarr.codecs.pipeline.BatchedCodecPipeline",
50+
"path": "zarr.core.codec_pipeline.BatchedCodecPipeline",
5151
"batch_size": 1,
5252
},
5353
"codecs": {

src/zarr/core/indexing.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -675,7 +675,7 @@ def check(a: npt.NDArray[Any]) -> Order:
675675
def wraparound_indices(x: npt.NDArray[Any], dim_len: int) -> None:
676676
loc_neg = x < 0
677677
if np.any(loc_neg):
678-
x[loc_neg] = x[loc_neg] + dim_len
678+
x[loc_neg] += dim_len
679679

680680

681681
def boundscheck_indices(x: npt.NDArray[Any], dim_len: int) -> None:
@@ -1000,8 +1000,8 @@ def __init__(
10001000
if stop < 0:
10011001
stop = dim_numchunks + stop
10021002

1003-
start = start * dim_chunk_size
1004-
stop = stop * dim_chunk_size
1003+
start *= dim_chunk_size
1004+
stop *= dim_chunk_size
10051005
slice_ = slice(start, stop)
10061006

10071007
else:

tests/test_api.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,33 @@ async def test_open_group_unspecified_version(
132132
assert g2.metadata.zarr_format == zarr_format
133133

134134

135+
@pytest.mark.parametrize("store", ["local", "memory", "zip"], indirect=["store"])
136+
@pytest.mark.parametrize("n_args", [10, 1, 0])
137+
@pytest.mark.parametrize("n_kwargs", [10, 1, 0])
138+
def test_save(store: Store, n_args: int, n_kwargs: int) -> None:
139+
data = np.arange(10)
140+
args = [np.arange(10) for _ in range(n_args)]
141+
kwargs = {f"arg_{i}": data for i in range(n_kwargs)}
142+
143+
if n_kwargs == 0 and n_args == 0:
144+
with pytest.raises(ValueError):
145+
save(store)
146+
elif n_args == 1 and n_kwargs == 0:
147+
save(store, *args)
148+
array = open(store)
149+
assert isinstance(array, Array)
150+
assert_array_equal(array[:], data)
151+
else:
152+
save(store, *args, **kwargs) # type: ignore[arg-type]
153+
group = open(store)
154+
assert isinstance(group, Group)
155+
for array in group.array_values():
156+
assert_array_equal(array[:], data)
157+
for k in kwargs.keys():
158+
assert k in group
159+
assert group.nmembers() == n_args + n_kwargs
160+
161+
135162
def test_save_errors() -> None:
136163
with pytest.raises(ValueError):
137164
# no arrays provided
@@ -142,6 +169,10 @@ def test_save_errors() -> None:
142169
with pytest.raises(ValueError):
143170
# no arrays provided
144171
save("data/group.zarr")
172+
with pytest.raises(TypeError):
173+
# mode is no valid argument and would get handled as an array
174+
a = np.arange(10)
175+
zarr.save("data/example.zarr", a, mode="w")
145176

146177

147178
def test_open_with_mode_r(tmp_path: pathlib.Path) -> None:

0 commit comments

Comments
 (0)