zarr-developers / zarr-python

An implementation of chunked, compressed, N-dimensional arrays for Python.
https://zarr.readthedocs.io
MIT License
1.5k stars 278 forks source link

Inconsistency between return type of Group.attrs and AsyncGroup.attrs #2214

Open TomAugspurger opened 1 month ago

TomAugspurger commented 1 month ago

Zarr version

v3

Numcodecs version

na

Python Version

na

Operating System

na

Installation

na

Description

There's an inconsistency between Group.attrs and AsyncGroup.attrs. Group.attrs returns an Attributes object while AsyncGroup.attrs returns an Attributes object. Just wanted to confirm that this is deliberate.

I'm planning to add an asdict() method to Attributes for v2 compatibility.

Steps to reproduce

In [13]: g = zarr.open_group(store={}, mode="w")

In [14]: g.attrs
Out[14]: <zarr.core.attributes.Attributes at 0x10bd902e0>

In [15]: g._async_group.attrs
Out[15]: {}

Additional output

No response

jhamman commented 3 weeks ago

Good catch @TomAugspurger. I had forgotten to come back to this.

The dict-like attrs property on the sync Array is not really possible for the AsyncArray. My conclusion is that we probably need something like an AsyncAttributes class:


class AsyncAttributes:
    def __init__(self, obj: AsyncArray | AsyncGroup):
        self._obj = obj

    async def getitem(self, key: str) -> JSON:
        return self._obj.metadata.attributes[key]

    async def setitem(self, key: str, value: JSON) -> None:
        new_attrs = dict(self._obj.metadata.attributes)
        new_attrs[key] = value
        self._obj = await self._obj.update_attributes(new_attrs)

    def delitem(self, key: str) -> None:
        new_attrs = dict(self._obj.metadata.attributes)
        del new_attrs[key]
        self._obj = await self._obj.update_attributes(new_attrs)

    def __iter__(self) -> Iterator[str]:
        return iter(self._obj.metadata.attributes)

    def __len__(self) -> int:
        return len(self._obj.metadata.attributes)

    async def put(self, d: dict[str, JSON]) -> None:
        self._obj = await self._obj.update_attributes(d)