Repository navigation
Conversation
…y layer Declaring an array today eagerly stores its metadata, so chunks cannot be written first. ArrayIO and AsyncArrayIO bind an array metadata document to a store location without performing any IO on construction; storing metadata (store_metadata) and storing or reading chunks (setitem/getitem) are explicit method calls that run in whatever order the caller chooses, mirroring the array APIs of zarrs and zarrita. The normalization half of init_array is extracted into the pure build_array_metadata, which init_array and AsyncArrayIO.build share; init_array's behavior is unchanged. Refs zarr-developers#4217 Assisted-by: ClaudeCode:claude-fable-5
Assisted-by: ClaudeCode:claude-fable-5
…ing open Every write now has an inverse, copying zarrs: store_metadata ↔ erase_metadata, chunk writes ↔ erase_chunk / erase_chunks, each succeeding when the target is already absent. open's zarr_format now defaults to None (read format 3, fall back to format 2), matching zarrs' open, instead of requiring format 3. Adversarial review against zarrs and TensorStore also found contract gaps now documented: the bound metadata is assumed, never verified (TensorStore's assume_metadata hazard); store_metadata keeps any previous array's chunks; a repaired document is stored before the first chunk write; and the module docstring no longer cites zarrita, whose create is eager. Assisted-by: ClaudeCode:claude-fable-5
… store A writer that declared an array independently (the distributed chunks-first pattern: one coordinator stores metadata, N workers build the same declaration) can assert its assumption before writing chunks. verify() reads the stored document, favoring format 3 when both exist, and raises naming each differing field — the explicit counterpart of TensorStore's spec-constraint validation on open. Assisted-by: ClaudeCode:claude-fable-5
The explicit-IO layer is the lower layer, so it moves into zarr.core.array as a self-contained class holding its own (metadata, store path, config, codec pipeline, chunk grid) state, with zarr.experimental.array_io re-exporting it. AsyncArray now holds one field, the wrapped AsyncArrayIO, exposes metadata/store_path/config/ codec_pipeline/_chunk_grid as properties over it, and delegates its metadata and selection IO to it; resize rebinds the wrapped state, so the two layers cannot drift. AsyncArrayIO defines value equality over the full binding, preserving AsyncArray's previous dataclass equality, and to_array() returns an AsyncArray sharing the same binding. The repair-before-chunk-write hook and the stored-document mark reset become module functions used by the one remaining implementation. Refs zarr-developers#4217 Assisted-by: ClaudeCode:claude-fable-5
Assisted-by: ClaudeCode:claude-fable-5
ArrayIO and AsyncArrayIO move out of zarr.experimental into the zarr namespace, next to Array and AsyncArray, which are built on them: the wrapped layer is reachable as Array.io / AsyncArray.io, the inverse of to_array(). The zarr.experimental.array_io shim is removed and the layer is documented on the array API page. Assisted-by: ClaudeCode:claude-fable-5
zarr-python now depends on zarr-metadata (>=0.6.0): AsyncArrayIO holds one source — the document, a zarr_metadata model, when constructed by open; the resolved metadata when constructed by build or by AsyncArray — and derives the other form, the chunk grid, the chunk key encoding and the codec pipeline as caches. Document operations (store_metadata, erase_metadata, erase_chunk, erase_chunks, verify, equality) never resolve codec or data type names, so an array whose codecs this environment lacks still opens for document work and refuses only when the data path is built; a document zarr can only read as repaired is refused by the strict model read, with AsyncArray.open remaining the repairing reader. Grid derivation goes through the same grid-metadata objects ChunkGrid.from_metadata dispatches on, so both derivations lay out chunks identically, and model JSON is normalized through JSON text because the model returns read-only forms. Resolved-seeded instances keep deriving their grid, chunk keys and equality from the resolved metadata: zarr-python writes some documents the strict model refuses (Zarr format 2 generic time units), and the array API's behavior must not depend on the model accepting them. Refs zarr-developers#4217 Assisted-by: ClaudeCode:claude-fable-5
This branch has not been deployed
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.
🤖 AI text below 🤖
Added
zarr.ArrayIOandzarr.AsyncArrayIO, an explicit-IO layer over Zarr arrays. Constructing one performs no IO against storage: storing metadata (store_metadata), storing or reading chunks (setitem/getitem), and their erasing inverses (erase_metadata,erase_chunk,erase_chunks) are explicit method calls that run in whatever order the caller chooses — so chunks can be written before metadata, as in the array API ofzarrs.openauto-detects the Zarr format by default, aszarrsdoes, andverifyreads the stored metadata and raises, naming each differing field, when it does not match the bound metadata.The binding holds the metadata document as a
zarr-metadatamodel — zarr-python now depends onzarr-metadata>=0.6.0, its first sibling-package dependency — reachable asArrayIO.document. Document operations (store_metadata,erase_metadata,erase_chunk,erase_chunks,verify, equality) never resolve codec or data type names: an array whose codecs this environment lacks still opens for document work and refuses only when chunks are read or written. The strict model read refuses a stored document zarr can only read as repaired (AsyncArray.openremains the repairing reader), and instances built from resolved metadata — everyAsyncArray— keep deriving their chunk grid, chunk keys and equality from the resolved form, because zarr-python writes some documents the strict model refuses (Zarr format 2 generic time units).AsyncArrayis now an array-like layer over this one: it holds a single wrappedAsyncArrayIO, exposesmetadata/store_path/config/codec_pipelineas properties over it, and delegates its metadata and selection IO to it, withresizerebinding the wrapped state so the two layers cannot drift.AsyncArrayIO.to_array()returns anAsyncArraysharing the same binding.AsyncArrayIOdefines value equality over the full binding, preservingAsyncArray's previous dataclass equality.The normalization half of
init_arrayis extracted into the purebuild_array_metadata, whichinit_arrayandAsyncArrayIO.buildshare;init_array's behavior is unchanged.Design notes:
store_metadata↔erase_metadata, chunk writes ↔erase_chunk/erase_chunks), each succeeding when the target is already absent, copying zarrs.store_metadata()writes unconditionally, likestore_metadatainzarrs; guarded creation (raising when a node exists) remainscreate_array's job, and chunks of a previous array at the location are kept —erase_chunksis the broom.assume_metadatahazard); this is documented on the class.verifyis the explicit check.zarr.core.arrayand are exported from thezarrnamespace, next to the classes built on them; the wrapped layer is reachable asArray.io/AsyncArray.io, the inverse ofto_array().Issues this layer addresses or advances: zarr-developers#4217 (the 2026-10-29 comment: avoiding implicit IO, writing chunks before metadata — the
Array-over-engine layering that issue describes now exists at the array layer), zarr-developers#1435 (idempotent, non-deleting parallel creation), zarr-developers#4175 (build_array_metadatamoves metadata creation offAsyncArray), zarr-developers#4399 / zarr-developers#1754 (storage-free declaration with caller-scheduled IO), zarr-developers#3017 (metadata IO as explicit free-standing operations), and zarr-developers#4027 / zarr-developers#3782 (theArray/AsyncArrayrelationship: the syncArrayIOstill routes throughsync(), so the event-loop issues — zarr-developers#2878, zarr-developers#3487, zarr-developers#3859 — need a sync engine under zarr-developers#4217 before they close).Stack
Base of the stack. #420 (Context scoping) stacks on this branch.
🤖 Generated with Claude Code