Skip to content

Commit cdce432

Browse files
Merge branch 'v3' into dependabot/pip/actions-bee7772ec3
2 parents a727d39 + 73b884b commit cdce432

36 files changed

+625
-169
lines changed

.github/ISSUE_TEMPLATE/bug_report.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
name: 🐛 File a bug report
2-
description: X's behavior is deviating from its documented behavior.
1+
name: Bug Report
2+
description: Report incorrect behaviour in the library.
33
labels: ["bug"]
44
body:
55
- type: markdown

.github/ISSUE_TEMPLATE/config.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
blank_issues_enabled: true
22
contact_links:
3-
- name: Propose a new major feature
3+
- name: Propose a new major feature
44
url: https://github.com/zarr-developers/zarr-specs
55
about: A new major feature should be discussed in the Zarr specifications repository.
6-
- name: Discuss something on ZulipChat
6+
- name: Discuss something on ZulipChat
77
url: https://ossci.zulipchat.com/
88
about: For questions like "How do I do X with Zarr?", you can move to our ZulipChat.
9-
- name: Discuss something on GitHub Discussions
9+
- name: Discuss something on GitHub Discussions
1010
url: https://github.com/zarr-developers/zarr-python/discussions
1111
about: For questions like "How do I do X with Zarr?", you can move to GitHub Discussions.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
name: Documentation Improvement
2+
description: Report missing or wrong documentation. Alternatively, you can just open a pull request with the suggested change.
3+
title: "DOC: "
4+
labels: [documentation, help wanted]
5+
6+
body:
7+
- type: textarea
8+
attributes:
9+
label: Describe the issue linked to the documentation
10+
description: >
11+
Please provide a description of what documentation you believe needs to be fixed/improved.
12+
validations:
13+
required: true
14+
- type: textarea
15+
attributes:
16+
label: Suggested fix for documentation
17+
description: >
18+
Please explain the suggested fix and why it's better than the existing documentation.

pyproject.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ extend-exclude = [
206206

207207
[tool.ruff.lint]
208208
extend-select = [
209+
"ANN", # flake8-annotations
209210
"B", # flake8-bugbear
210211
"C4", # flake8-comprehensions
211212
"FLY", # flynt
@@ -222,6 +223,10 @@ extend-select = [
222223
"UP", # pyupgrade
223224
]
224225
ignore = [
226+
"ANN003",
227+
"ANN101",
228+
"ANN102",
229+
"ANN401",
225230
"PT004", # deprecated
226231
"PT011", # TODO: apply this rule
227232
"PT012", # TODO: apply this rule
@@ -247,6 +252,9 @@ ignore = [
247252
"ISC002",
248253
]
249254

255+
[tool.ruff.lint.extend-per-file-ignores]
256+
"tests/**" = ["ANN001", "ANN201"]
257+
250258
[tool.mypy]
251259
python_version = "3.11"
252260
ignore_missing_imports = true

src/zarr/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,13 @@
3434
assert not __version__.startswith("0.0.0")
3535

3636
__all__ = [
37-
"__version__",
38-
"config",
3937
"Array",
4038
"AsyncArray",
41-
"Group",
4239
"AsyncGroup",
43-
"tree",
40+
"Group",
41+
"__version__",
4442
"array",
43+
"config",
4544
"consolidate_metadata",
4645
"copy",
4746
"copy_all",
@@ -63,6 +62,7 @@
6362
"save",
6463
"save_array",
6564
"save_group",
65+
"tree",
6666
"zeros",
6767
"zeros_like",
6868
]

src/zarr/abc/codec.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,21 @@
2020
from zarr.core.indexing import SelectorTuple
2121

2222
__all__ = [
23-
"CodecInput",
24-
"CodecOutput",
2523
"ArrayArrayCodec",
2624
"ArrayBytesCodec",
27-
"BytesBytesCodec",
2825
"ArrayBytesCodecPartialDecodeMixin",
2926
"ArrayBytesCodecPartialEncodeMixin",
27+
"BytesBytesCodec",
28+
"CodecInput",
29+
"CodecOutput",
3030
"CodecPipeline",
3131
]
3232

3333
CodecInput = TypeVar("CodecInput", bound=NDBuffer | Buffer)
3434
CodecOutput = TypeVar("CodecOutput", bound=NDBuffer | Buffer)
3535

3636

37-
class _Codec(Generic[CodecInput, CodecOutput], Metadata):
37+
class _Codec(Metadata, Generic[CodecInput, CodecOutput]):
3838
"""Generic base class for codecs.
3939
Please use ArrayArrayCodec, ArrayBytesCodec or BytesBytesCodec for subclassing.
4040

src/zarr/abc/store.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from zarr.core.buffer import Buffer, BufferPrototype
1515
from zarr.core.common import AccessModeLiteral, BytesLike
1616

17-
__all__ = ["Store", "AccessMode", "ByteGetter", "ByteSetter", "set_or_delete"]
17+
__all__ = ["AccessMode", "ByteGetter", "ByteSetter", "Store", "set_or_delete"]
1818

1919
ByteRangeRequest: TypeAlias = tuple[int | None, int | None]
2020

@@ -88,6 +88,31 @@ async def empty(self) -> bool: ...
8888
@abstractmethod
8989
async def clear(self) -> None: ...
9090

91+
@abstractmethod
92+
def with_mode(self, mode: AccessModeLiteral) -> Self:
93+
"""
94+
Return a new store of the same type pointing to the same location with a new mode.
95+
96+
The returned Store is not automatically opened. Call :meth:`Store.open` before
97+
using.
98+
99+
Parameters
100+
----------
101+
mode: AccessModeLiteral
102+
The new mode to use.
103+
104+
Returns
105+
-------
106+
store:
107+
A new store of the same type with the new mode.
108+
109+
Examples
110+
--------
111+
>>> writer = zarr.store.MemoryStore(mode="w")
112+
>>> reader = writer.with_mode("r")
113+
"""
114+
...
115+
91116
@property
92117
def mode(self) -> AccessMode:
93118
"""Access mode of the store."""
@@ -172,6 +197,22 @@ async def set(self, key: str, value: Buffer) -> None:
172197
"""
173198
...
174199

200+
async def set_if_not_exists(self, key: str, value: Buffer) -> None:
201+
"""
202+
Store a key to ``value`` if the key is not already present.
203+
204+
Parameters
205+
-----------
206+
key : str
207+
value : Buffer
208+
"""
209+
# Note for implementers: the default implementation provided here
210+
# is not safe for concurrent writers. There's a race condition between
211+
# the `exists` check and the `set` where another writer could set some
212+
# value at `key` or delete `key`.
213+
if not await self.exists(key):
214+
await self.set(key, value)
215+
175216
async def _set_many(self, values: Iterable[tuple[str, Buffer]]) -> None:
176217
"""
177218
Insert multiple (key, value) pairs into storage.
@@ -297,6 +338,8 @@ async def set(self, value: Buffer, byte_range: ByteRangeRequest | None = None) -
297338

298339
async def delete(self) -> None: ...
299340

341+
async def set_if_not_exists(self, default: Buffer) -> None: ...
342+
300343

301344
async def set_or_delete(byte_setter: ByteSetter, value: Buffer | None) -> None:
302345
if value is None:

src/zarr/api/asynchronous.py

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import numpy as np
88
import numpy.typing as npt
99

10-
from zarr.core.array import Array, AsyncArray
10+
from zarr.core.array import Array, AsyncArray, get_array_metadata
1111
from zarr.core.common import JSON, AccessModeLiteral, ChunkCoords, MemoryOrder, ZarrFormat
1212
from zarr.core.config import config
1313
from zarr.core.group import AsyncGroup
@@ -30,29 +30,29 @@
3030
PathLike = str
3131

3232
__all__ = [
33+
"array",
3334
"consolidate_metadata",
3435
"copy",
3536
"copy_all",
3637
"copy_store",
37-
"load",
38-
"open",
39-
"open_consolidated",
40-
"save",
41-
"save_array",
42-
"save_group",
43-
"tree",
44-
"array",
45-
"group",
46-
"open_group",
4738
"create",
4839
"empty",
4940
"empty_like",
5041
"full",
5142
"full_like",
43+
"group",
44+
"load",
5245
"ones",
5346
"ones_like",
47+
"open",
5448
"open_array",
49+
"open_consolidated",
50+
"open_group",
5551
"open_like",
52+
"save",
53+
"save_array",
54+
"save_group",
55+
"tree",
5656
"zeros",
5757
"zeros_like",
5858
]
@@ -230,6 +230,18 @@ async def open(
230230
if path is not None:
231231
store_path = store_path / path
232232

233+
if "shape" not in kwargs and mode in {"a", "w", "w-"}:
234+
try:
235+
metadata_dict = await get_array_metadata(store_path, zarr_format=zarr_format)
236+
# for v2, the above would already have raised an exception if not an array
237+
zarr_format = metadata_dict["zarr_format"]
238+
is_v3_array = zarr_format == 3 and metadata_dict.get("node_type") == "array"
239+
if is_v3_array or zarr_format == 2:
240+
return AsyncArray(store_path=store_path, metadata=metadata_dict)
241+
except (AssertionError, FileNotFoundError):
242+
pass
243+
return await open_group(store=store_path, zarr_format=zarr_format, mode=mode, **kwargs)
244+
233245
try:
234246
return await open_array(store=store_path, zarr_format=zarr_format, mode=mode, **kwargs)
235247
except KeyError:

src/zarr/api/synchronous.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,29 +14,29 @@
1414
from zarr.store import StoreLike
1515

1616
__all__ = [
17+
"array",
1718
"consolidate_metadata",
1819
"copy",
1920
"copy_all",
2021
"copy_store",
21-
"load",
22-
"open",
23-
"open_consolidated",
24-
"save",
25-
"save_array",
26-
"save_group",
27-
"tree",
28-
"array",
29-
"group",
30-
"open_group",
3122
"create",
3223
"empty",
3324
"empty_like",
3425
"full",
3526
"full_like",
27+
"group",
28+
"load",
3629
"ones",
3730
"ones_like",
31+
"open",
3832
"open_array",
33+
"open_consolidated",
34+
"open_group",
3935
"open_like",
36+
"save",
37+
"save_array",
38+
"save_group",
39+
"tree",
4040
"zeros",
4141
"zeros_like",
4242
]

src/zarr/codecs/sharding.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ async def set(self, value: Buffer, byte_range: ByteRangeRequest | None = None) -
9797
async def delete(self) -> None:
9898
del self.shard_dict[self.chunk_coords]
9999

100+
async def set_if_not_exists(self, default: Buffer) -> None:
101+
self.shard_dict.setdefault(self.chunk_coords, default)
102+
100103

101104
class _ShardIndex(NamedTuple):
102105
# dtype uint64, shape (chunks_per_shard_0, chunks_per_shard_1, ..., 2)

src/zarr/convenience.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,17 @@
1515
)
1616

1717
__all__ = [
18+
"consolidate_metadata",
19+
"copy",
20+
"copy_all",
21+
"copy_store",
22+
"load",
1823
"open",
24+
"open_consolidated",
1925
"save",
20-
"load",
2126
"save_array",
2227
"save_group",
23-
"copy",
24-
"copy_all",
25-
"copy_store",
2628
"tree",
27-
"consolidate_metadata",
28-
"open_consolidated",
2929
]
3030

3131
warnings.warn(

0 commit comments

Comments
 (0)