Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions packages/zarr-metadata/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,55 @@

<!-- towncrier release notes start -->

## 0.7.0 (2026-11-11)

### Features

- Added `zarr_metadata.testing.strategies`, Hypothesis strategies that draw valid Zarr v3 metadata declarations, behind a new `testing` extra (`pip install zarr-metadata[testing]`). There is one strategy for every codec, data type, chunk grid and chunk key encoding the package defines that holds no other declaration. `declarations` draws every envelope spelling the spec allows, or only the canonical one with `spellings="canonical"`. Codecs can be drawn for the `Chunk` they are handed, chunk grids for an array shape, and fill values for a data type. The strategies are a mapping keyed by definition, so an extension author can add strategies for their own definitions. ([#4575](https://github.com/zarr-developers/zarr-python/pull/4575))

- Add the `ZARR_PYTHON_CONTEXT` scope, which reads what zarr-python writes: `CORE_AND_EXTENSIONS_CONTEXT` plus zarr-python's own data types `null_terminated_bytes` (NumPy's `S`), `raw_bytes` (NumPy's `V`) and `variable_length_bytes`, which no specification registers. `CORE_AND_EXTENSIONS_CONTEXT` now also reads the `fixed_length_utf32` data type (NumPy's `U`) and the `vlen-utf8` and `vlen-bytes` codecs that zarr-extensions registers, so the strings zarr-python writes are checked instead of read as unclaimed. ([#4583](https://github.com/zarr-developers/zarr-python/pull/4583))

- `zarr_metadata.v3.data_type`, `zarr_metadata.v3.codec`, `zarr_metadata.v3.chunk_grid` and `zarr_metadata.v3.chunk_key_encoding` re-export every name their submodules export, so `from zarr_metadata.v3.data_type import BoolDataTypeName, Uint8DataTypeName` works again, as it did before 0.6.0. Each name is the same object as in its submodule, which stays its documented home. ([#4588](https://github.com/zarr-developers/zarr-python/pull/4588))

- Added strategies to `zarr_metadata.testing.strategies` for the definitions that hold other declarations: `struct`, `cast_value` and `sharding_indexed`. Their nested declarations are drawn from the same `Strategies` mapping, so a struct's field types, a cast's target data type and a shard's codecs come from every definition the mapping holds. A new `pipelines` strategy draws a whole codec pipeline for a `Chunk`, drawing each codec for the chunk the codec before it hands on, as that codec's `transition` gives it. Shards are drawn at most one inside another, and structs likewise. Every function a strategy record holds now also takes the `Strategies` mapping as its last argument, and `declarations` reads what it draws in the scope of every definition the mapping holds. ([#4597](https://github.com/zarr-developers/zarr-python/pull/4597))

- Added `array_documents`, `group_documents` and `consolidated_group_documents` to `zarr_metadata.testing.strategies`, which draw whole Zarr v3 documents. An array's members are drawn to fit each other: the chunk grid for the shape, the fill value for the data type, and the codecs for the grid's chunks of that data type. `pipelines` now takes `spellings`, as `declarations` does. ([#4602](https://github.com/zarr-developers/zarr-python/pull/4602))

- `zarr_metadata.model.read_openable_node_metadata_v3` reads a v3 `zarr.json` as `read_node_metadata_v3` does, and also reports each declaration a reader must understand to open the node that nothing in scope claims, such as an unknown codec or an unknown top-level member without `"must_understand": false`, as a problem of the new kind `unclaimed_declaration`. Its reading has no problems exactly when a reader that understands the scope can open the node, so a validator does not have to check `unclaimed_declarations` itself. The other readers still accept unclaimed declarations, and the `from_json` and reader docstrings now point to `unclaimed_declarations` and the new reader. ([#4604](https://github.com/zarr-developers/zarr-python/pull/4604))

- Export `base64_fill_value_rules` from `zarr_metadata.v3.data_type.bytes`, the rule that rejects a fill value string that is not standard-alphabet base64, so a data type defined outside the package can pass it as `fill_value_rules` for a `Base64Bytes` fill value, or yield from it in a rule of its own. The guide to parsing and validation now shows how to define a data type with `fill_value_rules`. ([#4609](https://github.com/zarr-developers/zarr-python/pull/4609))

### Bugfixes

- **Breaking:** Every problem is now located where the document writes the value. The v2 readers and the v2 models' `from_key_value` locate a problem in the file that holds it, such as `(".zarray", "order")` or `(".zattrs", "x")`, instead of in the merged document, and a v2 array node reading's `at` is now `(".zarray",)`. A problem in a v2 struct record is at `("dtype", 0, 1)` instead of under a `fields` key the document does not have, a codec's missing configuration member, such as the `endian` of a `bytes` codec, is reported inside the configuration it writes, or at `codecs.N.configuration` when it writes none, and a codec handed values it cannot encode is reported at `codecs.N` however it is spelled. ([#4574](https://github.com/zarr-developers/zarr-python/pull/4574))

- Various mistakes in v2 and consolidated metadata are now reported once, at their own location, with the right kind and message. A float where an integer from a fixed set is required, such as `"zarr_format": 2.0`, is an `invalid_type`, and a v2 typestr with a part its family does not take, such as `<f4[ns]`, or a time typestr without a unit, is a single `invalid_value` that names the part. A struct record of the wrong length or with a non-string name, the string `"struct"` given as a v2 dtype, a node that v3 consolidated metadata lists and whose own document has a problem, and a malformed inline `consolidated_metadata` member are each reported for their own problem alone, with the value found there as the problem's `input`. ([#4574](https://github.com/zarr-developers/zarr-python/pull/4574))

- **Breaking:** The v2 readers now agree with the v3 readers. A `.zarray` member the spec does not define may hold `NaN` and the infinities, a `.zmetadata` key that does not name its node's path, such as `/a/.zarray`, is refused instead of being read as the node at `a`, and a `.zgroup` that holds `attributes` is an `invalid_value` rather than an `unknown_key`, so a caller who tolerates unknown keys no longer drops those attributes. ([#4574](https://github.com/zarr-developers/zarr-python/pull/4574))

- `cast_value` and `scale_offset` reject `fixed_length_utf32`, `null_terminated_bytes`, `raw_bytes` and `variable_length_bytes`, whose values are not numbers. The strategies no longer draw them for either codec. The `scale_offset` strategy now draws `offset` and `scale` in every spelling a fill value of the data type takes, including integers, `NaN`, the infinities and the hex strings of their bits; a scale is still never zero. ([#4597](https://github.com/zarr-developers/zarr-python/pull/4597))

- The Zarr format 2 time dtypes accept the generic time unit in brackets — `<M8[generic]`, or `<m8[2generic]` with a scale — the spellings zarr-python writes for a NumPy generic-unit time dtype. A unit is still required: the unitless `<M8` stays refused, as the v2 spec demands. ([#4614](https://github.com/zarr-developers/zarr-python/pull/4614))

### Improved Documentation

- Adds a docstring and an API reference entry for every public object. ([#4590](https://github.com/zarr-developers/zarr-python/pull/4590))

- The documentation now has a short landing page that points each kind of reader to a guide page, instead of one long page. New guide pages cover models and readers, the rules the readers check, consolidated metadata, repairing known writer bugs, writing an extension, JSON Schema and Pydantic. Each claim the pages make about a Zarr specification links to the section of the spec that makes it, and the consolidated metadata page says what the specs do and do not settle, with links to the zarr-specs pull requests and issues and to the original zarr-python implementation. The pages say "context" for a `Context` where some said "scope". ([#4605](https://github.com/zarr-developers/zarr-python/pull/4605))

- The `to_json` docstrings and the guide now say what `to_json` returns: a copy in which each JSON array is a tuple, as the package's JSON types spell an array, so it does not compare equal to what `json.loads` returns. They point to comparing models instead. The guide had said `to_json` returns plain containers. ([#4608](https://github.com/zarr-developers/zarr-python/pull/4608))

### Deprecations and Removals

- Rename the scopes `CORE`, `CORE_AND_EXTENSIONS` and `CORE_V2` to `CORE_CONTEXT`, `CORE_AND_EXTENSIONS_CONTEXT` and `CORE_V2_CONTEXT`, so that a scope's name says it is a context. The old names, imported from `zarr_metadata.v3`, `zarr_metadata.v3.definition`, `zarr_metadata.v2` or `zarr_metadata.v2.definition`, still refer to the same scopes with a `DeprecationWarning`, and will be removed in a later release. ([#4583](https://github.com/zarr-developers/zarr-python/pull/4583))

- **Breaking:** The value found at an extension point, a data type, chunk grid, chunk key encoding, codec or storage transformer, is now called a *declaration*. The word *field* also meant a key of a metadata object, as in `extra_fields`, so one word meant two things. The public names change with no aliases: `AcceptedField`, `UnclaimedField`, `RefusedField` and `ResolvedField` end in `Declaration`, as do `ZarrV3CodecField` and the other kind-specific `...Field` types; a reading's `fields()` is `declarations()`; a model's `unclaimed_fields` is `unclaimed_declarations`; `ZarrV3MetadataFieldJSON` is `ZarrV3DeclarationJSON`; `field_json_schema_v3` is `declaration_json_schema_v3`; a kind's `field_aliases` is `declaration_aliases`; the first parameter of `with_problems` is `declarations`; and the JSON Schema `$defs` use the new names. `extra_fields`, `ExtraFieldDefinition`, `ZarrV3ExtensionField` and `StructField` keep their names. ([#4592](https://github.com/zarr-developers/zarr-python/pull/4592))

- Replace `ZarrV3Context.update(**slots)` and `ZarrV2Context.update(**slots)` with `copy(*, update=None)`, after pydantic's `model_copy(update=...)`: `context.update(codecs=[...])` becomes `context.copy(update={"codecs": [...]})`, and still replaces each slot it is given whole. To add definitions to a scope and keep the ones it has, use `union`: `CORE_AND_EXTENSIONS_CONTEXT.union(ZarrV3Context(data_types=[MY_DATA_TYPE]))`, which the docs now show in place of splicing a slot's definitions back in. ([#4598](https://github.com/zarr-developers/zarr-python/pull/4598))

- `to_key_value` takes a writer instead of an `indent` keyword. The writer is a `JSONWriter`, a frozen dataclass exported from `zarr_metadata` and `zarr_metadata.model` that owns how a document becomes JSON bytes: its settings are `indent`, `sort_keys`, `ensure_ascii` and `trailing_newline`, and its `encode` method does the writing. `to_key_value` also accepts a mapping of the settings (`JSONWriterSchema`), so `to_key_value(indent=2)` becomes `to_key_value({"indent": 2})`, with no import. The defaults are those of `json.dumps`, which the models already used, so a bare `to_key_value()` writes the same bytes as before. A setting that `json.dumps` would accept but misread, such as `indent=True`, a negative indent or a non-whitespace string indent, raises, and so does a mapping key that is not a setting. ([#4610](https://github.com/zarr-developers/zarr-python/pull/4610))


## 0.6.0 (2026-10-26)

### Features
Expand Down
1 change: 0 additions & 1 deletion packages/zarr-metadata/changes/4574.bugfix.1.md

This file was deleted.

1 change: 0 additions & 1 deletion packages/zarr-metadata/changes/4574.bugfix.2.md

This file was deleted.

1 change: 0 additions & 1 deletion packages/zarr-metadata/changes/4574.bugfix.3.md

This file was deleted.

1 change: 0 additions & 1 deletion packages/zarr-metadata/changes/4575.feature.md

This file was deleted.

1 change: 0 additions & 1 deletion packages/zarr-metadata/changes/4583.feature.md

This file was deleted.

1 change: 0 additions & 1 deletion packages/zarr-metadata/changes/4583.removal.md

This file was deleted.

1 change: 0 additions & 1 deletion packages/zarr-metadata/changes/4588.feature.md

This file was deleted.

1 change: 0 additions & 1 deletion packages/zarr-metadata/changes/4590.doc.md

This file was deleted.

1 change: 0 additions & 1 deletion packages/zarr-metadata/changes/4592.removal.md

This file was deleted.

1 change: 0 additions & 1 deletion packages/zarr-metadata/changes/4597.bugfix.md

This file was deleted.

1 change: 0 additions & 1 deletion packages/zarr-metadata/changes/4597.feature.md

This file was deleted.

1 change: 0 additions & 1 deletion packages/zarr-metadata/changes/4598.removal.md

This file was deleted.

1 change: 0 additions & 1 deletion packages/zarr-metadata/changes/4602.feature.md

This file was deleted.

1 change: 0 additions & 1 deletion packages/zarr-metadata/changes/4604.feature.md

This file was deleted.

1 change: 0 additions & 1 deletion packages/zarr-metadata/changes/4605.doc.md

This file was deleted.

Loading
Loading