Skip to content

feat(sharding): manage inner chunks as a semi-regular grid (sharding_indexed v1.1) - #4198

Draft
d-v-b wants to merge 10 commits into
zarr-developers:mainfrom
d-v-b:claude/sharding-codec-semi-regular-grid-fe8054
Draft

feat(sharding): manage inner chunks as a semi-regular grid (sharding_indexed v1.1)#4198
d-v-b wants to merge 10 commits into
zarr-developers:mainfrom
d-v-b:claude/sharding-codec-semi-regular-grid-fe8054

Conversation

@d-v-b

@d-v-b d-v-b commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements a proposed extension to the sharding codec spec which allows semi-regular inner chunk grids. Meaning, with this sharding codec implementation, the outer chunk shape can be (10,), and the inner chunk shape can be declared as (8,), resulting in actual inner chunks sized (8, 2), i.e. 10 partitioned into chunks sized 8, with the remainder. This makes the sharding codec much more useful for arrays with rectilinear chunk grids, or arrays with shapes made of prime numbers.

Implementation-wise, the biggest change is a layer of dynamism for the per-chunk models used by the sharding codec. chunk spec objects have to be generated dynamically per-chunk, because the inner chunk grid depends on the outer chunk shape.

For reviewers

This is a proof of concept intended to demonstrate the impact of implementing the proposed sharding codec change. Widening our model of the sharding codec has ecosystem-wide implications, so we will not merge this without either ecosystem-wide coordination or an explicit "I accept that I am going off-road" mechanism for zarr-python users to opt into. So do not consider this review-ready until I advertise that one or both of those conditions are met.

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
  • New/modified features documented in docs/user-guide/*.md
  • Changes documented as a new file in changes/
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

these changes were written with claude. See the claude-authored PR here: d-v-b#251

d-v-b and others added 9 commits July 14, 2026 13:25
* fix: byte-order handling for structured dtypes in the bytes codec

The bytes codec neither byte-swapped structured-dtype fields to its
configured endian on encode (numpy reports byteorder '|' for void
dtypes, so the top-level byteorder comparison never detected a
mismatch) nor honored its endian when decoding, silently corrupting
any structured data whose field byte order differed from the stored
one (e.g. virtual references to external big-endian data).

Encode now detects byte-order mismatches by comparing full dtypes via
newbyteorder, and decode reinterprets raw bytes in the stored byte
order before converting to the data type's declared byte order, so the
stored layout (codec state) and the in-memory layout (array data type)
are independent.

Closes zarr-developers#4141

Assisted-by: ClaudeCode:claude-fable-5

* test: fold structured byte-order cases into existing bytes codec tests

Extend test_endian's parametrization with structured dtypes and
test_bytes_codec_sync_roundtrip with endian/dtype parametrization plus
stored-layout and decoded-dtype assertions, instead of adding parallel
test functions for the same properties.

Assisted-by: ClaudeCode:claude-fable-5

* refactor: rename stored_dtype to view_dtype in BytesCodec decode

The variable is the dtype used to view the raw chunk bytes (byte order
from the codec's endian configuration), not a property of the stored
data or of the returned buffer, which always carries the array's
declared dtype.

Assisted-by: ClaudeCode:claude-fable-5

* docs: note that the decode-side byte-order conversion copies the chunk

Assisted-by: ClaudeCode:claude-fable-5
…t" data type (#202)

* chore(deps): bump the actions group across 1 directory with 8 updates (#176)

Bumps the actions group with 8 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [prefix-dev/setup-pixi](https://github.com/prefix-dev/setup-pixi) | `0.9.5` | `0.9.6` |
| [codecov/codecov-action](https://github.com/codecov/codecov-action) | `6.0.0` | `6.0.1` |
| [github/issue-metrics](https://github.com/github/issue-metrics) | `4.2.2` | `4.2.7` |
| [j178/prek-action](https://github.com/j178/prek-action) | `2.0.3` | `2.0.4` |
| [actions/upload-artifact](https://github.com/actions/upload-artifact) | `7.0.0` | `7.0.1` |
| [actions/download-artifact](https://github.com/actions/download-artifact) | `7.0.0` | `8.0.1` |
| [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) | `1.13.0` | `1.14.0` |
| [zizmorcore/zizmor-action](https://github.com/zizmorcore/zizmor-action) | `0.5.3` | `0.5.6` |



Updates `prefix-dev/setup-pixi` from 0.9.5 to 0.9.6
- [Release notes](https://github.com/prefix-dev/setup-pixi/releases)
- [Commits](prefix-dev/setup-pixi@1b2de7f...5185adf)

Updates `codecov/codecov-action` from 6.0.0 to 6.0.1
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](codecov/codecov-action@57e3a13...e79a696)

Updates `github/issue-metrics` from 4.2.2 to 4.2.7
- [Release notes](https://github.com/github/issue-metrics/releases)
- [Commits](github-community-projects/issue-metrics@c9e9838...1e38d5e)

Updates `j178/prek-action` from 2.0.3 to 2.0.4
- [Release notes](https://github.com/j178/prek-action/releases)
- [Commits](j178/prek-action@6ad8027...bdca6f1)

Updates `actions/upload-artifact` from 7.0.0 to 7.0.1
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v7...043fb46)

Updates `actions/download-artifact` from 7.0.0 to 8.0.1
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](actions/download-artifact@v7...3e5f45b)

Updates `pypa/gh-action-pypi-publish` from 1.13.0 to 1.14.0
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](pypa/gh-action-pypi-publish@v1.13.0...cef2210)

Updates `zizmorcore/zizmor-action` from 0.5.3 to 0.5.6
- [Release notes](https://github.com/zizmorcore/zizmor-action/releases)
- [Commits](zizmorcore/zizmor-action@b1d7e1f...5f14fd0)

---
updated-dependencies:
- dependency-name: prefix-dev/setup-pixi
  dependency-version: 0.9.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
- dependency-name: codecov/codecov-action
  dependency-version: 6.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
- dependency-name: github/issue-metrics
  dependency-version: 4.2.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
- dependency-name: j178/prek-action
  dependency-version: 2.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
- dependency-name: actions/download-artifact
  dependency-version: 8.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: pypa/gh-action-pypi-publish
  dependency-version: 1.14.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions
- dependency-name: zizmorcore/zizmor-action
  dependency-version: 0.5.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix: don't warn on the spec'd "struct" data type in v3

The `struct` data type now has a stable Zarr V3 specification
(zarr-extensions/data-types/struct), so serializing it no longer
warrants an UnstableSpecificationWarning. The legacy `structured`
alias and the unspecified bytes data types (null_terminated_bytes,
raw_bytes, variable_length_bytes) continue to warn.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019rRWaxXfZ3ZmbiZYWZoDBP

* docs: add changelog fragment for struct warning fix

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019rRWaxXfZ3ZmbiZYWZoDBP

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Implement zarr-specs zarr-developers#370: the sharding codec's chunk_shape no longer
needs to evenly divide the shard shape. Inner chunks are laid out on a
semi-regular grid managed by ChunkGrid: chunks per shard is the ceiling
division of the shard shape by chunk_shape, and chunks straddling the
shard boundary are encoded and stored at their clipped shape.

- validate() drops the divisibility requirement (dimension-count and
  grid-type checks remain)
- all encode/decode paths (sync and async, full and partial) use
  per-chunk ArraySpecs derived from the inner grid
- the uncompressed whole-shard bulk-decode fast path gates on an evenly
  divided grid; the scalar-broadcast write memo only reuses encoded
  bytes across nominal-shape chunks
- Array.read_chunk_sizes and cdata_shape account for the inner grid
  restarting at every shard boundary
- composes with rectilinear outer chunk grids and nested sharding

Arrays written with a non-divisible chunk_shape require a v1.1-aware
implementation to read; v1.0 implementations must reject them.

Assisted-by: ClaudeCode:claude-fable-5
Fixes from a multi-agent adversarial review of the semi-regular grid
change:

- nchunks_initialized used floor division for chunks-per-shard, which
  undercounts on clipped grids and reports 0 when chunk_shape exceeds
  the shard shape; use ceiling division to match the inner grid
- the scalar-broadcast write memo in _encode_partial_sync gated on
  ArraySpec object identity, which never holds because _get_chunk_spec
  is uncached (zarr-developers#3054); gate on shape equality so the memo fires again
  (one encode instead of one per complete chunk)
- the rectilinear clipping test used shard edges [[6, 4]], which
  normalize to a regular grid; use [[4, 6]] with the rectilinear config
  flag so RectilinearChunkGridMetadata is actually exercised

Adds regression tests for the first two.

Assisted-by: ClaudeCode:claude-fable-5
Assisted-by: ClaudeCode:claude-fable-5
@d-v-b

d-v-b commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

see zarr-developers/zarr-specs#370

@codecov

codecov Bot commented Jul 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 93.86%. Comparing base (123268a) to head (518c90a).

Files with missing lines Patch % Lines
src/zarr/codecs/sharding.py 97.50% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4198      +/-   ##
==========================================
- Coverage   93.90%   93.86%   -0.05%     
==========================================
  Files          91       91              
  Lines       12672    12692      +20     
==========================================
+ Hits        11900    11913      +13     
- Misses        772      779       +7     
Files with missing lines Coverage Δ
src/zarr/core/array.py 97.31% <100.00%> (-0.54%) ⬇️
src/zarr/codecs/sharding.py 96.03% <97.50%> (-0.09%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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