Skip to content

Group attributes not shared across different group instances with identical store_path, path and name #3178

Open
@FabricioArendTorres

Description

@FabricioArendTorres

Zarr version

v3.0.8

Numcodecs version

v0.15.1

Python Version

3.11.11

Operating System

Linux

Installation

uv within devcontainer based on 'mcr.microsoft.com/devcontainers/python:3.12'

Description

Issue: When opening multiple group instances that point to the same store path, their attributes are not properly shared, leading to inconsistent behavior. I tried this specifically for multiple paths that should correspond to the root path ("", "/", ..., see in code).

Expected behavior: All group instances (root1, root2, root3, root4) should share the same attributes since they reference the same store path.

Actual behavior:

  • root1.attrs.asdict() returns {'root1_attrs': '1'}
  • root2.attrs.asdict() returns {'root2_attrs': '2'}
  • root3.attrs.asdict() returns {} (empty)
  • root4.attrs.asdict() returns {'root2_attrs': '2'}

The issue appears to be that group instances maintain separate attribute objects even when they reference the same underlying store path.

Steps to reproduce

# /// script
# requires-python = "==3.11.11"
# dependencies = [
#   "zarr==3.0.8",
#   "numcodecs==0.15.1",
# ]
# ///

import asyncio

import zarr
import zarr.storage


# utility for dealing with async
async def get_all_keys(async_group):
    keys = []
    async for key in async_group.list():
        keys.append(key)
    return keys


def get_items(store):
    return asyncio.run(get_all_keys(store))
############################################


store = zarr.storage.MemoryStore()
root1 = zarr.create_group(store, path="")
root2 = zarr.open_group(store, path="/")
root3 = zarr.open_group(store, path="\\")

root1_subarray = root1.create_array("subarray1", shape=(1, 1), dtype=float)
root2_subarray = root2.create_array("subarray2", shape=(1, 1), dtype=float)

root1.attrs["root1_attrs"] = "1"
root2.attrs["root2_attrs"] = "2"
root4 = zarr.open_group(store, path="")

# this passes
assert root1._async_group.store_path == root2._async_group.store_path == root3._async_group.store_path
assert root1.name == root2.name == root3.name
assert root1.path == root2.path == root3.path
# this passes, but should not
assert root1.attrs.asdict() != root2.attrs.asdict()
assert root1.attrs.asdict() != root3.attrs.asdict()


# overview:
print(get_items(store))
print(f"{root1=}")
print(f"{root2=}")
print(f"{root3=}")
print(f"{root4=}")
print("")
print(f"{list(root1.arrays())=}")
print(f"{list(root2.arrays())=}")
print(f"{list(root3.arrays())=}")
print(f"{list(root4.arrays())=}")
print("")
print(f"{root1.attrs=}")
print(f"{root2.attrs=}")
print(f"{root3.attrs=}")
print(f"{root4.attrs=}")
print("")
print("")
print(f"{root1.attrs.asdict()=}")
print(f"{root2.attrs.asdict()=}")
print(f"{root3.attrs.asdict()=}")
print(f"{root4.attrs.asdict()=}")
print("")

Additional output

Output

['zarr.json', 'subarray1/zarr.json', 'subarray2/zarr.json']
root1=<Group memory://140310329361152>
root2=<Group memory://140310329361152>
root3=<Group memory://140310329361152>
root4=<Group memory://140310329361152>

list(root1.arrays())=[('subarray2', <Array memory://140310329361152/subarray2 shape=(1, 1) dtype=float64>), ('subarray1', <Array memory://140310329361152/subarray1 shape=(1, 1) dtype=float64>)]
list(root2.arrays())=[('subarray2', <Array memory://140310329361152/subarray2 shape=(1, 1) dtype=float64>), ('subarray1', <Array memory://140310329361152/subarray1 shape=(1, 1) dtype=float64>)]
list(root3.arrays())=[('subarray2', <Array memory://140310329361152/subarray2 shape=(1, 1) dtype=float64>), ('subarray1', <Array memory://140310329361152/subarray1 shape=(1, 1) dtype=float64>)]
list(root4.arrays())=[('subarray2', <Array memory://140310329361152/subarray2 shape=(1, 1) dtype=float64>), ('subarray1', <Array memory://140310329361152/subarray1 shape=(1, 1) dtype=float64>)]

root1.attrs=<zarr.core.attributes.Attributes object at 0x7f9c8b414f10>
root2.attrs=<zarr.core.attributes.Attributes object at 0x7f9c8b414f10>
root3.attrs=<zarr.core.attributes.Attributes object at 0x7f9c8b414f10>
root4.attrs=<zarr.core.attributes.Attributes object at 0x7f9c8b414f10>


root1.attrs.asdict()={'root1_attrs': '1'}
root2.attrs.asdict()={'root2_attrs': '2'}
root3.attrs.asdict()={}
root4.attrs.asdict()={'root2_attrs': '2'}

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugPotential issues with the zarr-python library

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions