Skip to content

Commit 6be197f

Browse files
authored
Merge branch 'main' into honor-read-only
2 parents d6d747c + e738e2f commit 6be197f

File tree

7 files changed

+57
-32
lines changed

7 files changed

+57
-32
lines changed

changes/3428.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Ensure syntax like ``root['/subgroup']`` works equivalently to ``root['subgroup']`` when using consolidated metadata.

changes/3431.bugfix.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Creating a new group with `zarr.group` no longer errors.
2+
This fixes a regression introduced in version 3.1.2.

src/zarr/api/asynchronous.py

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -670,38 +670,24 @@ async def group(
670670
g : group
671671
The new group.
672672
"""
673-
674-
zarr_format = _handle_zarr_version_or_format(zarr_version=zarr_version, zarr_format=zarr_format)
675-
676673
mode: AccessModeLiteral
677674
if overwrite:
678675
mode = "w"
679676
else:
680-
mode = "r+"
681-
store_path = await make_store_path(store, path=path, mode=mode, storage_options=storage_options)
682-
683-
if chunk_store is not None:
684-
warnings.warn("chunk_store is not yet implemented", ZarrRuntimeWarning, stacklevel=2)
685-
if cache_attrs is not None:
686-
warnings.warn("cache_attrs is not yet implemented", ZarrRuntimeWarning, stacklevel=2)
687-
if synchronizer is not None:
688-
warnings.warn("synchronizer is not yet implemented", ZarrRuntimeWarning, stacklevel=2)
689-
if meta_array is not None:
690-
warnings.warn("meta_array is not yet implemented", ZarrRuntimeWarning, stacklevel=2)
691-
692-
if attributes is None:
693-
attributes = {}
694-
695-
try:
696-
return await AsyncGroup.open(store=store_path, zarr_format=zarr_format)
697-
except (KeyError, FileNotFoundError):
698-
_zarr_format = zarr_format or _default_zarr_format()
699-
return await AsyncGroup.from_store(
700-
store=store_path,
701-
zarr_format=_zarr_format,
702-
overwrite=overwrite,
703-
attributes=attributes,
704-
)
677+
mode = "a"
678+
return await open_group(
679+
store=store,
680+
mode=mode,
681+
chunk_store=chunk_store,
682+
cache_attrs=cache_attrs,
683+
synchronizer=synchronizer,
684+
path=path,
685+
zarr_version=zarr_version,
686+
zarr_format=zarr_format,
687+
meta_array=meta_array,
688+
attributes=attributes,
689+
storage_options=storage_options,
690+
)
705691

706692

707693
async def create_group(

src/zarr/core/group.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,7 @@ def _getitem_consolidated(
735735
assert self.metadata.consolidated_metadata is not None
736736

737737
# we support nested getitems like group/subgroup/array
738-
indexers = key.split("/")
738+
indexers = normalize_path(key).split("/")
739739
indexers.reverse()
740740
metadata: ArrayV2Metadata | ArrayV3Metadata | GroupMetadata = self.metadata
741741

src/zarr/storage/_common.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,12 @@
3131

3232

3333
def _dereference_path(root: str, path: str) -> str:
34-
assert isinstance(root, str)
35-
assert isinstance(path, str)
34+
if not isinstance(root, str):
35+
msg = f"{root=} is not a string ({type(root)=})" # type: ignore[unreachable]
36+
raise TypeError(msg)
37+
if not isinstance(path, str):
38+
msg = f"{path=} is not a string ({type(path)=})" # type: ignore[unreachable]
39+
raise TypeError(msg)
3640
root = root.rstrip("/")
3741
path = f"{root}/{path}" if root else path
3842
return path.rstrip("/")

tests/test_api/test_asynchronous.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@
88
import pytest
99

1010
from zarr import create_array
11-
from zarr.api.asynchronous import _get_shape_chunks, _like_args, open
11+
from zarr.api.asynchronous import _get_shape_chunks, _like_args, group, open
1212
from zarr.core.buffer.core import default_buffer_prototype
13+
from zarr.core.group import AsyncGroup
1314

1415
if TYPE_CHECKING:
16+
from pathlib import Path
1517
from typing import Any
1618

1719
import numpy.typing as npt
@@ -103,3 +105,18 @@ async def test_open_no_array() -> None:
103105
TypeError, match=r"open_group\(\) got an unexpected keyword argument 'shape'"
104106
):
105107
await open(store=store, shape=(1,))
108+
109+
110+
async def test_open_group_new_path(tmp_path: Path) -> None:
111+
"""
112+
Test that zarr.api.asynchronous.group properly handles a string representation of a local file
113+
path that does not yet exist.
114+
See https://github.com/zarr-developers/zarr-python/issues/3406
115+
"""
116+
# tmp_path exists, but tmp_path / "test.zarr" will not, which is important for this test
117+
path = tmp_path / "test.zarr"
118+
grp = await group(store=path, attributes={"a": 1})
119+
assert isinstance(grp, AsyncGroup)
120+
# Calling group on an existing store should just open that store
121+
grp = await group(store=path)
122+
assert grp.attrs == {"a": 1}

tests/test_metadata/test_consolidated.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,21 @@ async def test_use_consolidated_for_children_members(
692692
expected = ["b", "b/c"]
693693
assert result == expected
694694

695+
async def test_absolute_path_for_subgroup(self, memory_store: zarr.storage.MemoryStore) -> None:
696+
root = await zarr.api.asynchronous.create_group(store=memory_store)
697+
await root.create_group("a/b")
698+
with pytest.warns(
699+
ZarrUserWarning,
700+
match="Consolidated metadata is currently not part in the Zarr format 3 specification.",
701+
):
702+
await zarr.api.asynchronous.consolidate_metadata(memory_store)
703+
704+
group = await zarr.api.asynchronous.open_group(store=memory_store)
705+
subgroup = await group.getitem("/a")
706+
assert isinstance(subgroup, AsyncGroup)
707+
members = [x async for x in subgroup.keys()] # noqa: SIM118
708+
assert members == ["b"]
709+
695710

696711
@pytest.mark.parametrize("fill_value", [np.nan, np.inf, -np.inf])
697712
async def test_consolidated_metadata_encodes_special_chars(

0 commit comments

Comments
 (0)