Skip to content

fix: deep-copy source attributes in from_array - #4325

Merged
d-v-b merged 3 commits into
zarr-developers:mainfrom
d-v-b:fix/from-array-deepcopy-attributes
Sep 9, 2026
Merged

fix: deep-copy source attributes in from_array#4325
d-v-b merged 3 commits into
zarr-developers:mainfrom
d-v-b:fix/from-array-deepcopy-attributes

Conversation

@d-v-b

@d-v-b d-v-b commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

This AI-authored PR ensures that from_array copies 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 with dict(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 example dst.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 existing from_array attribute test now mutates a nested dict and a nested list on the copy and asserts the source is unchanged; it fails on main and passes here.

Found during the pre-release review for #4256.

For reviewers

The source change is a one-liner plus an import copy. fill_value was 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 structured np.void fill values are distinct objects between source and copy.

Author attestation

  • I am a human, these are my changes, and I have reviewed and understood every change and can explain why each is correct.

TODO

  • Add unit tests and/or doctests in docstrings
  • Add docstrings and API docs for any new/modified user-facing classes and functions (n/a)
  • New/modified features documented in docs/user-guide/*.md (n/a)
  • Changes documented as a new file in changes/
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

`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

codecov Bot commented Sep 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.31%. Comparing base (db93545) to head (c906c8e).

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           
Files with missing lines Coverage Δ
src/zarr/core/array.py 98.08% <100.00%> (+<0.01%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@d-v-b
d-v-b marked this pull request as ready for review September 9, 2026 17:23
@d-v-b
d-v-b merged commit a1b4416 into zarr-developers:main Sep 9, 2026
39 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant