feat: add the zarr-indexing package (TensorStore-style index transforms, ndsel wire format) - #249
Open
d-v-b wants to merge 13 commits into
Open
feat: add the zarr-indexing package (TensorStore-style index transforms, ndsel wire format)#249d-v-b wants to merge 13 commits into
d-v-b wants to merge 13 commits into
Conversation
7 tasks
…zarr-developers#4205) - Codec construction warnings (e.g. sharding's "disables partial reads") fired twice per array open, and on every decode/encode through the fused pipeline's async fallback. Re-constructions of an already-validated codec chain now go through codecs_from_list_unchecked, which validates structure without repeating first-construction advisory warnings; each warning fires exactly once per open under both pipelines. - concurrent_iter returned a lazy generator while its docstring promised eagerly scheduled tasks; it now materializes the task list so awaiting one at a time cannot serialize the batch. - A garbage codec_pipeline.max_workers value (e.g. from the environment) raised ValueError mid-read; it now warns and falls back to the default, consistent with tolerant handling of config input. - The as-completed pipeline helpers abandoned in-flight tasks when one failed, leaving stray background writes and "Task exception was never retrieved" warnings; failures now cancel and drain outstanding tasks. - Benchmarks: seed the data generator for reproducibility; fix a copy-pasted docstring. - Remove dead commented-out test blocks referencing the removed set_range API. Assisted-by: ClaudeCode:claude-sonnet-5
* 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
Standalone workspace package extracted from the lazy-indexing branch (zarr-developers#3906): composable, lazy coordinate transforms (IndexTransform / IndexDomain / output maps), dependency-aware chunk resolution against a DimensionGridLike protocol, and an ndsel-conformant JSON wire format validated against the vendored conformance corpus. zarr itself does not depend on zarr-indexing yet — the runtime wiring lands separately once 0.1.0 is published. The package is numpy-only; its tests exercise chunk resolution against zarr's concrete ChunkGrid, so they run from the workspace root (uv sync --all-packages). Assisted-by: ClaudeCode:claude-fable-5
Assisted-by: ClaudeCode:claude-fable-5
Candidate-chunk enumeration took the cartesian product of each correlated ArrayMap's per-dimension distinct chunk ids and relied on intersect() to filter untouched combinations. For a diagonal selection of P scattered points that is P**2 intersect calls — quadratic in the number of selected points, the same workload shape as zarr-developers#4174 (400 points: ~2.6s; 10k points: ~30min). Group correlated maps jointly instead: broadcast their per-point chunk ids, take the distinct rows (np.unique(axis=0), O(P log P)), and enumerate exactly the touched combinations. Candidate slots now carry chunk-coordinate tuples covering one or more output dimensions; orthogonal/constant/slice dimensions keep their existing per-dimension candidates. 400-point diagonal resolution drops from 2628ms to 14ms and scales linearly. Assisted-by: ClaudeCode:claude-fable-5
Mirror the treatment zarr-metadata received in zarr-developers#4208/zarr-developers#4210 onto zarr-indexing: a self-contained mkdocs site under the package (own mkdocs.yml, landing page, ndsel wire-format guide, mkdocstrings page per module, and .readthedocs.yaml for a dedicated RTD project), so the package presents as a separate project with docs versioned by its own zarr_indexing-v* release tags rather than zarr-python's. The zarr-python site's API Reference nav links out to it, and each RTD project now skips PR builds that do not touch its half of the repo. The package gains a pinned docs dependency group, a docs build job in its CI workflow, and a justfile with package-scoped dev recipes. Two recipes deviate from the zarr-metadata original by design: - `test` runs against the workspace-root environment (`uv run --project ../.. --all-packages --group test`), because the chunk-resolution tests exercise this package against zarr's chunk grids and `zarr` is deliberately not a dependency of this package. - `typecheck` uses plain `pyright`, unpinned and on the default interpreter, mirroring this package's own CI invocation. The zarr-metadata pin exists for a PEP 661 sentinel regression that zarr-indexing's sources do not hit. composition.py gains the module docstring the other modules already have, since mkdocstrings renders it as the page introduction. Assisted-by: ClaudeCode:claude-fable-5
The bytes-codec byte-order fix this fragment describes shipped upstream and its entry is already in docs/release-notes.md; the fragment survived on this branch only as a rebase remnant, and would emit a duplicate entry in the next release. Assisted-by: ClaudeCode:claude-fable-5
d-v-b
force-pushed
the
feat/zarr-indexing-package
branch
from
July 30, 2026 11:41
d1e931f to
733b3c3
Compare
…/ndsel Also aligns the zarr-indexing workflow's setup-uv pin (v8.3.2) with the rest of the repo. The vendored-corpus sha is present upstream; the historical d-v-b/ndsel#1 PR reference stays as provenance. Assisted-by: ClaudeCode:claude-fable-5
…th 11 updates (zarr-developers#4216) * chore(deps): bump the python-dependencies group across 1 directory with 11 updates Bumps the python-dependencies group with 11 updates in the / directory: | Package | From | To | | --- | --- | --- | | [numpy](https://github.com/numpy/numpy) | `2.5.0` | `2.5.1` | | [typer](https://github.com/fastapi/typer) | `0.26.8` | `0.27.0` | | [coverage](https://github.com/coveragepy/coveragepy) | `7.14.3` | `7.15.2` | | [hypothesis](https://github.com/HypothesisWorks/hypothesis) | `6.155.7` | `6.160.0` | | [tomlkit](https://github.com/python-poetry/tomlkit) | `0.15.0` | `0.15.1` | | [uv](https://github.com/astral-sh/uv) | `0.11.26` | `0.11.31` | | [mkdocs-material[imaging]](https://github.com/squidfunk/mkdocs-material) | `9.7.6` | `9.7.7` | | [mkdocstrings](https://github.com/mkdocstrings/mkdocstrings) | `1.0.4` | `1.0.6` | | [markdown-exec[ansi]](https://github.com/pawamoy/markdown-exec) | `1.12.1` | `1.12.3` | | [ruff](https://github.com/astral-sh/ruff) | `0.15.20` | `0.15.22` | | [mypy](https://github.com/python/mypy) | `2.1.0` | `2.3.0` | Updates `numpy` from 2.5.0 to 2.5.1 - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst) - [Commits](numpy/numpy@v2.5.0...v2.5.1) Updates `typer` from 0.26.8 to 0.27.0 - [Release notes](https://github.com/fastapi/typer/releases) - [Changelog](https://github.com/fastapi/typer/blob/master/docs/release-notes.md) - [Commits](fastapi/typer@0.26.8...0.27.0) Updates `coverage` from 7.14.3 to 7.15.2 - [Release notes](https://github.com/coveragepy/coveragepy/releases) - [Changelog](https://github.com/coveragepy/coveragepy/blob/main/CHANGES.rst) - [Commits](coveragepy/coveragepy@7.14.3...7.15.2) Updates `hypothesis` from 6.155.7 to 6.160.0 - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](HypothesisWorks/hypothesis@v6.155.7...v6.160.0) Updates `tomlkit` from 0.15.0 to 0.15.1 - [Release notes](https://github.com/python-poetry/tomlkit/releases) - [Changelog](https://github.com/python-poetry/tomlkit/blob/master/CHANGELOG.md) - [Commits](python-poetry/tomlkit@0.15.0...0.15.1) Updates `uv` from 0.11.26 to 0.11.31 - [Release notes](https://github.com/astral-sh/uv/releases) - [Changelog](https://github.com/astral-sh/uv/blob/0.11.31/CHANGELOG.md) - [Commits](astral-sh/uv@0.11.26...0.11.31) Updates `mkdocs-material[imaging]` from 9.7.6 to 9.7.7 - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG) - [Commits](squidfunk/mkdocs-material@9.7.6...9.7.7) Updates `mkdocstrings` from 1.0.4 to 1.0.6 - [Release notes](https://github.com/mkdocstrings/mkdocstrings/releases) - [Changelog](https://github.com/mkdocstrings/mkdocstrings/blob/main/CHANGELOG.md) - [Commits](mkdocstrings/mkdocstrings@1.0.4...1.0.6) Updates `markdown-exec[ansi]` from 1.12.1 to 1.12.3 - [Release notes](https://github.com/pawamoy/markdown-exec/releases) - [Changelog](https://github.com/pawamoy/markdown-exec/blob/main/CHANGELOG.md) - [Commits](pawamoy/markdown-exec@1.12.1...1.12.3) Updates `ruff` from 0.15.20 to 0.15.22 - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/0.15.22/CHANGELOG.md) - [Commits](astral-sh/ruff@0.15.20...0.15.22) Updates `mypy` from 2.1.0 to 2.3.0 - [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md) - [Commits](python/mypy@v2.1.0...v2.3.0) --- updated-dependencies: - dependency-name: coverage dependency-version: 7.15.2 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: python-dependencies - dependency-name: hypothesis dependency-version: 6.160.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: python-dependencies - dependency-name: markdown-exec[ansi] dependency-version: 1.12.3 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: python-dependencies - dependency-name: mkdocs-material[imaging] dependency-version: 9.7.7 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: python-dependencies - dependency-name: mkdocstrings dependency-version: 1.0.6 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: python-dependencies - dependency-name: mypy dependency-version: 2.3.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: python-dependencies - dependency-name: numpy dependency-version: 2.5.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: python-dependencies - dependency-name: ruff dependency-version: 0.15.22 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: python-dependencies - dependency-name: tomlkit dependency-version: 0.15.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: python-dependencies - dependency-name: typer dependency-version: 0.27.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: python-dependencies - dependency-name: uv dependency-version: 0.11.31 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: python-dependencies ... Signed-off-by: dependabot[bot] <support@github.com> * fix: satisfy numpy 2.5.1 type stubs in indexing selection normalization numpy 2.5.1 stubs infer np.asarray(<list>) as a float64 array, so mypy now rejects the untyped asarray calls in replace_lists and CoordinateIndexer. Pass dtype=np.intp where the integer dtype is guaranteed, and cast to ArrayOfIntOrBool where the list contents are only known at runtime. Assisted-by: ClaudeCode:claude-fable-5 --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
…elopers#4219) * fix: reject malformed chunk keys in DefaultChunkKeyEncoding decode_chunk_key stripped a single leading character and split the rest, so any key at all decoded to something. "0/1" silently became (1,) -- the "0" was eaten as if it were the "c" prefix -- and a key written with one separator decoded wrongly under an encoding configured with the other. Validate the "c<separator>" prefix and raise ValueError when it is absent, so a key that is not a chunk key for this encoding is reported rather than silently misread. Adds the tests this method never had, covering the round trip for both separators and each way a key can fail to carry the prefix. Assisted-by: ClaudeCode:claude-fable-5 * Rename 250.bugfix.md to 4219.bugfix.md
Per review: the root pyproject.toml should not change in this PR. The package now operates fully standalone (like zarr-metadata); the test invocations layer the package into the repo-root environment as an editable overlay instead (python -m pytest, since a base-env console script would not see the overlay). Assisted-by: ClaudeCode:claude-fable-5
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 🤖
Adds
zarr-indexingas a standalone uv-workspace package (packages/zarr-indexing, import namezarr_indexing), without wiring it into zarr's runtime — per the land-the-package-first sequencing. The runtime integration (lazy.lazyindexing, transform-routed selection I/O) stays onrefactor/simplify-indexing(zarr-developers#3906) and will gain thezarr-indexing>=0.1.0dependency only after 0.1.0 is on PyPI.What the package is
IndexTransform/IndexDomain/ three output-map kinds, full-input-rank index arrays with dependency-axis-derived correlation (oindex outer-product vs vindex broadcast), composition, literal-coordinate slice semantics verified against tensorstore 0.1.84.DimensionGridLikeprotocol (public-name-only contract; zarr's per-dimension grids satisfy it structurally, no zarr import). Includes the touched-chunks-only enumeration and the sorted-1-D fast path from perf(zarr-transforms): partition sorted 1-D array maps by chunk #234.parse_ndsel/normalize_ndselimplement the ndsel draft spec (all five message kinds, canonical normalize, full error taxonomy), validated against the byte-vendored conformance corpus plus a tensorstoreIndexTransform(json=...)round-trip cross-check.Contents
packages/zarr-indexing/— sources, tests (273, all green againstmain's zarr), vendored ndsel corpus with provenance, own towncrier changelog..github/workflows/zarr-indexing.yml— pytest (3.12–3.14) / ruff / pyright, paths-filtered; test job usesuv sync --all-packagessince zarr does not depend on the package here..github/workflows/zarr-indexing-release.yml— tag-triggered (zarr_indexing-v*) TestPyPI/PyPI publish with attestation and an isolated-wheel smoke test; byte-identical to the zarr-metadata release flow modulo the package name. A local dress rehearsal of the tagged build produced exactly0.1.0and the wheel imports with no zarr installed.check_changelogs.yml— covers the package'schanges/dir.pyproject.toml— uv workspace membership only (no runtime dependency).Sequencing
zarr-indexing→ pushzarr_indexing-v0.1.0.History note: files were developed on the zarr-developers#3906 branch (with per-commit review);
git log --followtraces their evolution there.