Skip to content

Commit 1cb6179

Browse files
jhammand-v-b
authored andcommitted
Feature: group and array name properties (#1940)
* feature: group and array path/name/basename properties * tests
1 parent 1ea8373 commit 1cb6179

File tree

4 files changed

+131
-0
lines changed

4 files changed

+131
-0
lines changed

src/zarr/array.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,29 @@ def dtype(self) -> np.dtype[Any]:
378378
def attrs(self) -> dict[str, JSON]:
379379
return self.metadata.attributes
380380

381+
@property
382+
def path(self) -> str:
383+
"""Storage path."""
384+
return self.store_path.path
385+
386+
@property
387+
def name(self) -> str | None:
388+
"""Array name following h5py convention."""
389+
if self.path:
390+
# follow h5py convention: add leading slash
391+
name = self.path
392+
if name[0] != "/":
393+
name = "/" + name
394+
return name
395+
return None
396+
397+
@property
398+
def basename(self) -> str | None:
399+
"""Final component of name."""
400+
if self.name is not None:
401+
return self.name.split("/")[-1]
402+
return None
403+
381404
async def _get_selection(
382405
self,
383406
indexer: Indexer,
@@ -628,6 +651,21 @@ def dtype(self) -> np.dtype[Any]:
628651
def attrs(self) -> Attributes:
629652
return Attributes(self)
630653

654+
@property
655+
def path(self) -> str:
656+
"""Storage path."""
657+
return self._async_array.path
658+
659+
@property
660+
def name(self) -> str | None:
661+
"""Array name following h5py convention."""
662+
return self._async_array.name
663+
664+
@property
665+
def basename(self) -> str | None:
666+
"""Final component of name."""
667+
return self._async_array.basename
668+
631669
@property
632670
def metadata(self) -> ArrayMetadata:
633671
return self._async_array.metadata

src/zarr/group.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,27 @@ async def _save_metadata(self) -> None:
272272
awaitables = [set_or_delete(self.store_path / key, value) for key, value in to_save.items()]
273273
await asyncio.gather(*awaitables)
274274

275+
@property
276+
def path(self) -> str:
277+
"""Storage path."""
278+
return self.store_path.path
279+
280+
@property
281+
def name(self) -> str:
282+
"""Group name following h5py convention."""
283+
if self.path:
284+
# follow h5py convention: add leading slash
285+
name = self.path
286+
if name[0] != "/":
287+
name = "/" + name
288+
return name
289+
return "/"
290+
291+
@property
292+
def basename(self) -> str:
293+
"""Final component of name."""
294+
return self.name.split("/")[-1]
295+
275296
@property
276297
def attrs(self) -> dict[str, Any]:
277298
return self.metadata.attributes
@@ -464,13 +485,15 @@ def create(
464485
store: StoreLike,
465486
*,
466487
attributes: dict[str, Any] = {}, # noqa: B006, FIXME
488+
zarr_format: ZarrFormat = 3,
467489
exists_ok: bool = False,
468490
) -> Group:
469491
obj = sync(
470492
AsyncGroup.create(
471493
store,
472494
attributes=attributes,
473495
exists_ok=exists_ok,
496+
zarr_format=zarr_format,
474497
),
475498
)
476499

@@ -523,6 +546,21 @@ def store_path(self) -> StorePath:
523546
def metadata(self) -> GroupMetadata:
524547
return self._async_group.metadata
525548

549+
@property
550+
def path(self) -> str:
551+
"""Storage path."""
552+
return self._async_group.path
553+
554+
@property
555+
def name(self) -> str:
556+
"""Group name following h5py convention."""
557+
return self._async_group.name
558+
559+
@property
560+
def basename(self) -> str:
561+
"""Final component of name."""
562+
return self._async_group.basename
563+
526564
@property
527565
def attrs(self) -> Attributes:
528566
return Attributes(self)

tests/v3/test_array.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import pytest
2+
3+
from zarr.array import Array
4+
from zarr.common import ZarrFormat
5+
from zarr.group import Group
6+
from zarr.store import LocalStore, MemoryStore
7+
8+
9+
@pytest.mark.parametrize("store", ("local", "memory"), indirect=["store"])
10+
@pytest.mark.parametrize("zarr_format", (2, 3))
11+
def test_array_name_properties_no_group(
12+
store: LocalStore | MemoryStore, zarr_format: ZarrFormat
13+
) -> None:
14+
arr = Array.create(store=store, shape=(100,), chunks=(10,), zarr_format=zarr_format, dtype="i4")
15+
assert arr.path == ""
16+
assert arr.name is None
17+
assert arr.basename is None
18+
19+
20+
@pytest.mark.parametrize("store", ("local", "memory"), indirect=["store"])
21+
@pytest.mark.parametrize("zarr_format", (2, 3))
22+
def test_array_name_properties_with_group(
23+
store: LocalStore | MemoryStore, zarr_format: ZarrFormat
24+
) -> None:
25+
root = Group.create(store=store, zarr_format=zarr_format)
26+
foo = root.create_array("foo", shape=(100,), chunks=(10,), dtype="i4")
27+
assert foo.path == "foo"
28+
assert foo.name == "/foo"
29+
assert foo.basename == "foo"
30+
31+
bar = root.create_group("bar")
32+
spam = bar.create_array("spam", shape=(100,), chunks=(10,), dtype="i4")
33+
34+
assert spam.path == "bar/spam"
35+
assert spam.name == "/bar/spam"
36+
assert spam.basename == "spam"

tests/v3/test_group.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,3 +372,22 @@ def test_group_init(store: LocalStore | MemoryStore, zarr_format: ZarrFormat) ->
372372
agroup = sync(AsyncGroup.create(store=store, zarr_format=zarr_format))
373373
group = Group(agroup)
374374
assert group._async_group == agroup
375+
376+
377+
@pytest.mark.parametrize("store", ("local", "memory"), indirect=["store"])
378+
@pytest.mark.parametrize("zarr_format", (2, 3))
379+
def test_group_name_properties(store: LocalStore | MemoryStore, zarr_format: ZarrFormat) -> None:
380+
root = Group.create(store=store, zarr_format=zarr_format)
381+
assert root.path == ""
382+
assert root.name == "/"
383+
assert root.basename == ""
384+
385+
foo = root.create_group("foo")
386+
assert foo.path == "foo"
387+
assert foo.name == "/foo"
388+
assert foo.basename == "foo"
389+
390+
bar = root.create_group("foo/bar")
391+
assert bar.path == "foo/bar"
392+
assert bar.name == "/foo/bar"
393+
assert bar.basename == "bar"

0 commit comments

Comments
 (0)