Skip to content

Claude/internal simplifications#4105

Open
d-v-b wants to merge 16 commits into
zarr-developers:mainfrom
d-v-b:claude/internal-simplifications
Open

Claude/internal simplifications#4105
d-v-b wants to merge 16 commits into
zarr-developers:mainfrom
d-v-b:claude/internal-simplifications

Conversation

@d-v-b

@d-v-b d-v-b commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

I had claude do a review of our codebase and look for low-hanging fruit style improvements

Summary

Internal-only simplifications: dedupe repeated creation / containment logic and remove single-caller pass-through wrappers. Zero public-API changes — all touched code is private (underscore-prefixed or module-internal) with no external callers (verified via grep across src/ and tests/). Behavior is identical; verified with targeted tests and ad-hoc snippets where stack/precedence semantics mattered.

Addresses S1–S6, S8, S10 of https://www.github.com/d-v-b/zarr-python/issues/181.

Changes (each is a separate commit)

  1. Dedupe overwrite-check logic (src/zarr/core/array.py) — extracted the repeated "delete existing node if overwriting and the store supports deletes, else enforce no existing node" dance into a private _prepare_overwrite helper, used by _create_v3, _create_v2, and _create_array_metadata. The three sites used two equivalent spellings; both collapse to the helper. (+19 / −18)

  2. Remove single-caller get-selection wrappers (src/zarr/core/array.py) — _get_orthogonal_selection, _get_mask_selection, _get_coordinate_selection each built an indexer and delegated to _get_selection, with exactly one caller apiece (the matching AsyncArray.get_*_selection). Inlined the indexer construction into those methods and deleted the wrappers. (+19 / −182). No analogous module-level _set_*_selection wrappers exist, so nothing to remove there.

  3. Unify dtype dispatch (src/zarr/core/array.py) — ArrayV2Metadata.dtype and ArrayV3Metadata.dtype (the latter an alias for data_type) both already return the zarr dtype object, so the inline metadata.dtype if zarr_format == 2 else metadata.data_type dispatch in AsyncArray._zdtype, _get_selection, and _set_selection collapses to metadata.dtype. No new property needed. (+7 / −14)

  4. cdata_shape duplication (src/zarr/core/array.py) — Array.cdata_shape now delegates to Array._chunk_grid_shape instead of duplicating its body. Signatures/docstrings unchanged. (+1 / −1)

  5. "not yet implemented" warning boilerplate (src/zarr/api/asynchronous.py) — extracted a _warn_unimplemented_kwargs(dict) helper used by open_group and create. Uses stacklevel=3 to compensate for the extra frame; verified the emitted warning has identical message, category, source location, and emission order as before. (+32 / −22)

  6. contains_group V3 dedup (src/zarr/storage/_common.py) — rewrote the V3 branch as (await _contains_node_v3(store_path)) == "group", behaviorally identical across all cases (missing doc, array, group, malformed/non-object JSON, missing node_type, invalid format). (+1 / −12)

    • contains_array intentionally left unchanged: its V3 branch falls through to raise ValueError("Invalid zarr_format...") when a group node is present, which _contains_node_v3 does not reproduce (it would yield False). Swapping it would change observable behavior, so it was skipped to honor the "behavior identical" constraint.
  7. Inline no-op default_filters_v3 (src/zarr/core/array.py) — the function unconditionally returned (). Inlined the empty tuple at both call sites (note: two callers, not one) with a short comment and deleted the function. (+4 / −11)

  8. Fold fill_value into _like_args (src/zarr/api/asynchronous.py) — _like_args now records the source array's fill_value, so empty_like/full_like/open_like drop their isinstance + setdefault blocks. ones_like/zeros_like pop the inherited fill_value (they supply their own), preserving exact prior precedence semantics — including the pre-existing duplicate-keyword TypeError when an explicit fill_value is passed to ones_like/zeros_like. Updated the _like_args unit test to include the new key. (+11 / −8)

🤖 Generated with Claude Code

dependabot Bot and others added 14 commits May 31, 2026 19:28
…#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>
Extract the repeated "delete existing node if overwriting (and the store
supports deletes), otherwise enforce no existing node" dance into a single
private helper `_prepare_overwrite`, used by `_create_v3`, `_create_v2`, and
`_create_array_metadata`.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The module-level `_get_orthogonal_selection`, `_get_mask_selection`, and
`_get_coordinate_selection` helpers each constructed an indexer and delegated
to `_get_selection`, and each had exactly one caller (the corresponding
`AsyncArray.get_*_selection` method). Inline the indexer construction into
those methods and delete the wrappers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`ArrayV2Metadata.dtype` and `ArrayV3Metadata.dtype` (the latter an alias for
`data_type`) both already return the zarr dtype object, so the repeated
`metadata.dtype if zarr_format == 2 else metadata.data_type` dispatch in
`AsyncArray._zdtype`, `_get_selection`, and `_set_selection` collapses to a
single `metadata.dtype` access.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`Array.cdata_shape` and `Array._chunk_grid_shape` had identical bodies; the
public `cdata_shape` now delegates to `_chunk_grid_shape` instead of
duplicating the access.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`default_filters_v3` unconditionally returned an empty tuple. Inline that
empty tuple at its two call sites (with a short comment) and delete the
function.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The V3 branch of `contains_group` re-implemented the node-type detection that
`_contains_node_v3` already performs. Replace it with
`(await _contains_node_v3(store_path)) == "group"`, which is behaviorally
identical for all cases (missing document, array, group, malformed/non-object
JSON, and missing node_type key all map to the same result).

`contains_array` is intentionally left unchanged: its V3 branch falls through
to a `ValueError` when a *group* node is present, which `_contains_node_v3`
does not reproduce, so swapping it would change observable behavior.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`open_group` and `create` each had repeated
`if x is not None: warnings.warn(f"...not yet implemented...")` blocks. Extract
a `_warn_unimplemented_kwargs` helper taking a name->value mapping. The helper
uses stacklevel=3 to compensate for the extra call frame, so the warning still
points at the same call site (verified: identical message, category, source
location, and emission order).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`_like_args` now records the source array's fill_value, so `empty_like`,
`full_like`, and `open_like` no longer need to re-check isinstance and
setdefault it. `ones_like`/`zeros_like` drop the inherited fill_value (they
supply their own), preserving exact prior behavior including the existing
duplicate-keyword TypeError when an explicit fill_value is passed. Update the
`_like_args` unit test to include the new key.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions github-actions Bot added the needs release notes Automatically applied to PRs which haven't added release notes label Jun 26, 2026
@codecov

codecov Bot commented Jun 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.54%. Comparing base (e29ddd2) to head (9ca2870).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4105      +/-   ##
==========================================
+ Coverage   93.50%   93.54%   +0.03%     
==========================================
  Files          90       90              
  Lines       11981    11937      -44     
==========================================
- Hits        11203    11166      -37     
+ Misses        778      771       -7     
Files with missing lines Coverage Δ
src/zarr/api/asynchronous.py 96.29% <100.00%> (+2.24%) ⬆️
src/zarr/core/array.py 97.83% <100.00%> (-0.04%) ⬇️
src/zarr/storage/_common.py 89.10% <100.00%> (-0.42%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@d-v-b d-v-b requested review from chuckwondo and maxrjones June 26, 2026 15:46
@maxrjones

Copy link
Copy Markdown
Member

TBH I find the PR title confusing, as I'm not sure what I should take from it starting with Claude. Is this a new commit style?

@maxrjones

Copy link
Copy Markdown
Member

The Claude-generated summary makes it hard to gauge how much to scrutinize. For an internal refactor this size you could self-merge per our policy. What are you hoping a second reviewer adds? where would you most want me to look?

@d-v-b

d-v-b commented Jun 27, 2026

Copy link
Copy Markdown
Contributor Author

The Claude-generated summary makes it hard to gauge how much to scrutinize. For an internal refactor this size you could self-merge per our policy. What are you hoping a second reviewer adds? where would you most want me to look?

sorry for the confusion, I was just looking for another set of eyes on these changes, since some of them are a bit closer to public API than other internal cleanups. I think a quick eyeball check on them would be fine! And i'm happy self-reviewing if you don't have time.

It's a collection of logically independent changes, so in principle they could each be in a separate PR, but I opted for batching them. If that strategy doesn't work well, I can avoid this in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs release notes Automatically applied to PRs which haven't added release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants