Skip to content

Make type checking cover tests and match CI - #181

Merged
d-v-b merged 1 commit into
zarr-developers:mainfrom
d-v-b:claude/typecheck-src-and-tests
Aug 5, 2026
Merged

Make type checking cover tests and match CI#181
d-v-b merged 1 commit into
zarr-developers:mainfrom
d-v-b:claude/typecheck-src-and-tests

Conversation

@d-v-b

@d-v-b d-v-b commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

🤖 AI text below 🤖

Splits the type-checking work out of #180 so the justfile PR can build on it.

The problem

hatch run types:check failed immediately with 227 errors, so just typecheck in #180 would have been broken out of the box. Two independent causes:

  • The types environment installed only mypy, pydantic and numpy — no zarr, pytest, xarray or dask. With ignore_missing_imports = true those all became Any, producing ~90 phantom errors (untyped-decorator on every pytest mark, stale unused-ignore comments).
  • The mypy that actually gated CI was the mirrors-mypy pre-commit hook, pinned to v1.15.0 and scoped to files: src. The hatch env resolved a different mypy and checked tests too, so the two could never agree.

Provisioning the environment correctly dropped this to 134 errors and made src/ clean — the 19 apparent source errors were also artifacts of the missing zarr install.

Single entry point

hatch run types:check is now the only type-check command, run locally and by a new typecheck CI job:

  • [tool.hatch.envs.types] gains dependency-groups = ["test"] and pins mypy==2.3.0, so the versions mypy checks against come from the same place the tests get them and cannot drift.
  • The mypy pre-commit hook is removed. sp-repo-review's PC140 hard-requires that hook, so it joins the existing [tool.repo-review] ignore list.

Trade-off worth naming: there is no longer mypy feedback at git commit time; the CI job is what catches it.

Real bugs found

  1. from_zarr overloads declared depth without a default in both v2 and experimental.v2, so the documented one-argument call from_zarr(group) did not type-check — for downstream users too, not just this repo. v3 was already correct.
  2. experimental.v2.GroupSpec.from_flat was narrower than to_flat: to_flat() returns BaseGroupSpec values but from_flat() accepted only GroupSpec, so GroupSpec.from_flat(group.to_flat()) did not type-check. Widened to match the module-level from_flat, which already accepted it.
  3. A test assertion that could only pass as None == None: spec.filters is a tuple while auto_filters() returns the raw list, so any non-empty case would have failed. Now normalised before comparing.

The remainder is mechanical: ~40 stale type: ignore comments removed, missing annotations added, and isinstance narrowing in place of # type: ignore[attr-defined] on .members chains — which makes those assertions stronger rather than merely quieter.

Verification

Check Result
hatch run types:check (src + tests) Success, 21 files
pre-commit run --all-files all hooks pass
tests, zarr 3.0.10 / 3.1.0 / 3.3.0 19568 / 19690 / 19690 passed
tests, no-zarr env 17876 passed
doctests 30 passed

Only src change with runtime effect is none — the two source fixes are annotation-level. tests/conftest.py does change at runtime (Structured(fields=...) now takes a tuple), which is why all three zarr versions were exercised.

🤖 Generated with Claude Code

The `types` hatch environment installed only mypy, pydantic and numpy, so
zarr, pytest, xarray and dask were all missing. Combined with
`ignore_missing_imports = true` this turned them into `Any` and produced a
large number of phantom errors, while the mypy that actually gated CI was
the pre-commit hook, which checked `src` only with a separately pinned
version.

Give the `types` environment the `test` dependency group and pin mypy, so
it type-checks against the same dependencies the tests run against. Remove
the mypy pre-commit hook and add a `typecheck` CI job running
`hatch run types:check`, making that command the single entry point for
local and CI type checking. `sp-repo-review`'s PC140 is ignored since it
hard-requires a mypy pre-commit hook.

Fix the errors this surfaced in `tests/`, and two genuine typing bugs in
`src/`:

- `v2.from_zarr` and `experimental.v2.from_zarr` declared `depth` without a
  default in their overloads, so the documented one-argument call
  `from_zarr(group)` did not type-check for callers.
- `experimental.v2.GroupSpec.from_flat` accepted only
  `Mapping[str, ArraySpec | GroupSpec]` while `to_flat` returns
  `BaseGroupSpec` values, so the round trip did not type-check.

Also fixes a test assertion in `experimental/test_v2.py` that compared
`spec.filters` (a tuple) against `auto_filters()` (a list), which could only
ever have passed when both were `None`.

Assisted-by: ClaudeCode:claude-opus-5
@d-v-b
d-v-b merged commit 97b1f55 into zarr-developers:main Aug 5, 2026
20 checks passed
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