Skip to content

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

Open

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'}

Activity

  1. changed the title [-]Group attributes not shared across different group instances pointing to same path[/-] [+]Group attributes not shared across different group instances with same store_path and name[/+] on Jun 29, 2025
  2. changed the title [-]Group attributes not shared across different group instances with same store_path and name[/-] [+]Group attributes not shared across different group instances with identical store_path, path and name[/+] on Jun 29, 2025
  3. added 2 commits that reference this issue on Jul 8, 2025
    82c8324
    16675fa
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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