fix: deep-copy source attributes in from_array - #4325
Merged
d-v-b merged 3 commits intoSep 9, 2026
Conversation
`from_array` copied the source array's attributes with `dict(data.attrs)`, a shallow copy, so any nested dict or list inside the attributes was shared between the source array's in-memory metadata and the new array's. Mutating a nested attribute on the copy (e.g. appending to a list) silently changed the source array's attributes as well. The alias never reached the source's store, but it was created by zarr without the user's involvement. Copy the attributes with `copy.deepcopy` instead. Attributes are JSON values (dicts, lists, scalars), so a deep copy is safe and cheap. The existing `from_array` attribute test now mutates a nested dict and a nested list on the copy and asserts the source is unchanged. Assisted-by: ClaudeCode:claude-fable-5-1
Assisted-by: ClaudeCode:claude-fable-5-1
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4325 +/- ##
=======================================
Coverage 94.31% 94.31%
=======================================
Files 92 92
Lines 12919 12920 +1
=======================================
+ Hits 12184 12185 +1
Misses 735 735
🚀 New features to boost your workflow:
|
d-v-b
marked this pull request as ready for review
September 9, 2026 17:23
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This AI-authored PR ensures that
from_arraycopies source array attributes by value instead of by reference, which prevents mutating the input attributes as a side effect of mutating the derived array's attributes.🤖 AI text below 🤖
Summary
zarr.from_array(since #4288) copies the source array's attributes onto the new array withdict(data.attrs), which is a shallow copy. Any nested dict or list inside the attributes was therefore shared between the source array's in-memory metadata and the new array's, so mutating a nested attribute on the copy — for exampledst.attrs["meta"]["tags"].append(...)— silently changed the source array's attributes too. The alias never reached the source's store, but it was created by zarr without the user's involvement, which is a surprise.This PR switches to
copy.deepcopy; attributes are JSON values (dicts, lists, scalars), so the deep copy is safe and cheap. The existingfrom_arrayattribute test now mutates a nested dict and a nested list on the copy and asserts the source is unchanged; it fails onmainand passes here.Found during the pre-release review for #4256.
For reviewers
The source change is a one-liner plus an
import copy.fill_valuewas checked for the same issue and does not have it: the value is re-parsed when the new array's metadata is built, so even structurednp.voidfill values are distinct objects between source and copy.Author attestation
TODO
docs/user-guide/*.md(n/a)changes/