Skip to content

Cache attributes - #220

Merged
alimanfoo merged 15 commits into
masterfrom
cache-attrs-20171224b
Jan 2, 2018
Merged

Cache attributes#220
alimanfoo merged 15 commits into
masterfrom
cache-attrs-20171224b

Conversation

@alimanfoo

@alimanfoo alimanfoo commented Dec 24, 2017

Copy link
Copy Markdown
Member

This PR adds support for caching user attributes, enabled by default. Resolves #218.

TODO:

@alimanfoo alimanfoo added this to the v2.2 milestone Dec 24, 2017
@alimanfoo

Copy link
Copy Markdown
Member Author

cc @jhamman, @mrocklin

Comment thread zarr/attrs.py Outdated

def _get(self):
if self.key in self.store:
d = json.loads(text_type(self.store[self.key], 'ascii'))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a general note, in the future for remote datasets we might want to minimize multiple touches of self.store. I can imagine wanting to change things like this to code like the following instead:

try:
    data = self.store[self.key[
except KeyError:
    d = {}
else:
    d = json.loads(text_type(data))

This is just a general comment though, not something that should necessarily be done here. I'll bring it up again if we find this a challenge when profiling.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good suggestion, asking for permission is a hard habit to break :-)

@jhamman

jhamman commented Dec 26, 2017

Copy link
Copy Markdown
Member

@alimanfoo - is it possible or could it be possible to load all the attributes of an array/store at once? Caching is great but accessing each attribute individually will still be pretty costly.

@alimanfoo

alimanfoo commented Dec 26, 2017 via email

Copy link
Copy Markdown
Member Author

@jakirkham

Copy link
Copy Markdown
Member

Is there a way to toggle caching on an existing object? Also is there a way to clear the cache?

@alimanfoo

Copy link
Copy Markdown
Member Author

Btw I've also now exposed a put() method on the Attributes class in the public API, which should be even more efficient than update() in the case where you know you want to initially set or completely replace all attributes. put() requires only a single write operation (overwrites whatever .zattrs is there) whereas update() requires a read and a write operation (retrieves .zattrs then applies update before writing).

@alimanfoo

Copy link
Copy Markdown
Member Author

@jakirkham you can turn caching off with o.attrs.cache = False. Also I've added o.attrs.refresh() to force reloading the cached attributes from the store.

@jakirkham

Copy link
Copy Markdown
Member

Thanks @alimanfoo. That sounds great.

@alimanfoo
alimanfoo merged commit 5af7ace into master Jan 2, 2018
@alimanfoo
alimanfoo deleted the cache-attrs-20171224b branch January 2, 2018 23:01
d-v-b added a commit that referenced this pull request Jul 16, 2026
* 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: byte-order handling for structured dtypes in the bytes codec (#220)

* 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 #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

* docs: 3.3.0 release notes

Add missing changelog fragments for #3955 (datetime64/timedelta64 V3
metadata types), #3966 (writes to 0-dimensional sharded arrays), and the
public alias renames that accompanied the #3963/#3968 enum deprecations,
then build the 3.3.0 release notes with towncrier, consuming all
fragments accumulated since v3.2.1.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
d-v-b added a commit that referenced this pull request Jul 17, 2026
* fix: byte-order handling for structured dtypes in the bytes codec (#220)

* 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 #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

* fix(store): copy buffers on write in MemoryStore

Encoding an uncompressed chunk hands the store a zero-copy view of the
caller's array, and MemoryStore keeps whatever it is given alive in a
dict rather than serializing it. Mutating the source array after a write
therefore rewrote chunks already committed to the store, silently.

Stores that serialize on write (LocalStore, ZipStore, remote stores) are
unaffected, so they keep the full benefit of #3885. Only MemoryStore pays
the copy, and only where it was aliasing to begin with: an uncompressed
34 MB write goes from ~23 ms to ~39 ms, while compressed writes are
unchanged.

Copying at the store boundary rather than narrowing the fast path in
_merge_chunk_array also fixes the single-chunk case, which aliased in
v3.2.1 too.

Assisted-by: ClaudeCode:claude-opus-4.8

* docs: add changelog entry for MemoryStore buffer copy

Assisted-by: ClaudeCode:claude-opus-4.8

* docs: correct changelog
d-v-b added a commit that referenced this pull request Jul 20, 2026
…4165)

* fix: byte-order handling for structured dtypes in the bytes codec (#220)

* 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 #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

* fix(store): FsspecStore.close() no longer closes the filesystem

FsspecStore.close() closed the underlying filesystem's session, on the
premise that a store built by from_url "owns" the filesystem it created.
That premise does not hold: fsspec caches and shares filesystem
instances across callers (its instance cache keys on storage options,
not path), and users can hand one filesystem to many stores directly.
Closing one store therefore killed the session that sibling stores were
still using, and left the dead filesystem in fsspec's cache for later
callers.

Determining whether a filesystem is actually shared requires reaching
into fsspec's private instance cache (_cache, _fs_token, cachable) and
walking wrapper chains for caching/proxy filesystems — an implementation
detail that leaks upward and that we would have to keep in sync with
fsspec forever, getting it subtly wrong in between. The wrapper case
alone (simplecache::/dir://) already slipped through a cache-membership
check.

The filesystem's lifecycle is simply not the store's to manage. This
removes the ownership model added in the unreleased gh-4003: no _owns_fs,
no _close_fs, no ownership transfer in with_read_only, and close() just
marks the store not-open. The only thing given up is suppressing an
"Unclosed client session" ResourceWarning, which was true anyway — the
session belongs to a cached filesystem that outlives the store.

Since gh-4003 never shipped (latest release is v3.2.1), its changelog
fragment is removed rather than superseded.

Assisted-by: ClaudeCode:claude-opus-4.8

* test: skip with_read_only fs test when AsyncFileSystemWrapper is absent

test_with_read_only_shares_filesystem replaced an ownership test that
carried a guard for fsspec < 2024.12.0, and the guard was dropped in the
rewrite. The test still opens a file:// URL, which needs
AsyncFileSystemWrapper, so it failed the min_deps job.

Assisted-by: ClaudeCode:claude-opus-4.8

* docs: correct changelog claim about gh-4003 release status

The fragment said gh-4003 was unreleased with no net change for
released versions. Its text is already in the staged 3.3.0 release
notes, so the revert is a real behavior change for anyone relying on
close() releasing the session.

Assisted-by: ClaudeCode:claude-opus-4.8

* docs: remove changelog entry for unreleased versions
d-v-b added a commit that referenced this pull request Jul 29, 2026
* fix: byte-order handling for structured dtypes in the bytes codec (#220)

* 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 #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

* fix(codec_pipeline): keep FusedCodecPipeline compute off the event-loop thread

FusedCodecPipeline.read/write ran their synchronous fast path inline on
the coroutine servicing the request — i.e. on the global zarr_io event
loop thread. Single-chunk batches decoded inline on the loop and
multi-chunk batches blocked the loop in pool.map, so every sync-API call
from every user thread serialized behind each other's codec compute.
The blocked window scales with codec cost, which is why users reported
the fused pipeline as "slower for zstd-compressed data" under
multi-threaded (dask-style, one chunk per call) access: at 8 reader
threads on 4 MiB zstd chunks it was 3.4x slower than
BatchedCodecPipeline, and throughput did not scale with threads at all
(336 -> 439 ms from 1 to 8 threads, versus 669 -> 121 ms for batched).

Offload the synchronous batch to a worker thread with asyncio.to_thread:
one hop per batch, not per chunk, preserving the fused pipeline's win
over per-chunk async scheduling while keeping the loop free. After the
fix the same workload scales 625 -> 109 ms from 1 to 8 threads, beating
batched at every thread count; single-threaded performance is unchanged
(the hop costs ~75 us per batch).

The regression test asserts deterministically (no timing) that codec
compute never runs on a thread with a running event loop, covering
single- and multi-chunk reads and writes through the sync API. A new
benchmark covers the many-threads/one-chunk-per-call access pattern.

Assisted-by: ClaudeCode:claude-fable-5

* docs: rename change note to upstream PR number (4194)

towncrier's issue_format links to zarr-developers/zarr-python issues, so
247 (the fork PR number) would render a link to an unrelated old issue.

Assisted-by: ClaudeCode:claude-fable-5

* test: guard event-loop test against vacuity if the sync fast path stops triggering

The test asserts a negative (compute never ran on the loop thread). If a
refactor made the sync fast path stop triggering, the traced ChunkTransform
methods would never be called (the async fallback uses AsyncChunkTransform)
and the test would pass while guarding nothing. Assert the traced hooks
actually ran.

Assisted-by: ClaudeCode:claude-fable-5
d-v-b added a commit that referenced this pull request Jul 29, 2026
…#4200)

* fix: byte-order handling for structured dtypes in the bytes codec (#220)

* 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 #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

* fix: make benchmark page-cache clearing opt-in, never prompt for sudo

clear_cache() in tests/benchmarks/test_e2e.py ran sudo unconditionally in
every benchmark's setup, so a plain `pytest` run blocked on a password
prompt (#4199). It is now a no-op unless ZARR_BENCHMARK_CLEAR_CACHE is
set, uses `sudo -n` so it can never block interactively, and the broken
Darwin invocation ("&&" passed as an argument to sync) is fixed. The
benchmark CI jobs set the variable to keep clearing caches.

Closes #4199

Assisted-by: ClaudeCode:claude-fable-5
d-v-b added a commit that referenced this pull request Jul 31, 2026
…ms, ndsel wire format) (#4196)

* fix: byte-order handling for structured dtypes in the bytes codec (#220)

* 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 #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

* feat: add the zarr-indexing package (TensorStore-style index transforms)

Standalone workspace package extracted from the lazy-indexing branch
(#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

* style: conventional submodule import in the chunk-resolution tests

Assisted-by: ClaudeCode:claude-fable-5

* perf(zarr-indexing): joint chunk enumeration for correlated vindex maps

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 #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

* docs(zarr-indexing): standalone documentation site; add package justfile

Mirror the treatment zarr-metadata received in #4208/#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

* chore: drop the already-released 4141 changelog fragment

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

* docs(zarr-indexing): canonicalize ndsel references to zarr-developers/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

* chore: drop the root uv-workspace wiring for zarr-indexing

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
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.

Cache attributes DOC: Attributes class

4 participants