Test across Python 3.9-3.14 in CI - #7
Merged
Merged
Conversation
CI ran a single Python 3.11 job while pyproject declares `requires-python = ">=3.9"`, so five of the six supported versions were never exercised. Add a matrix over the full declared range, with fail-fast disabled so one version failing does not hide the others. The matrix immediately caught a real failure. Nothing is pinned -- no lockfile is committed -- so each Python resolves its own dependency set, and 3.12+ picks up numpy 2.5, whose stubs give np.isnan a concrete ndarray return type. Assigning None to that variable afterwards is an error mypy only sees on those versions; 3.9 through 3.11 resolve to numpy <= 2.4 and pass. Annotate nan_mask as Optional[np.ndarray]. This is a typing-only change with no runtime effect, and the suite passes on all six versions either way. Also add, matching OmniWatermask: - `fetch-depth: 0`, so setuptools-scm can read tags. Without it CI was installing version 0.1.dev1+g<hash> rather than the real version -- the same silent-version hazard the conda-forge recipe guards against. - A weekly schedule. With nothing pinned, upstream releases reach users through a fresh resolve; this surfaces them on our schedule instead of theirs. OpenCV 5.0.0 already satisfies our `>=4.10` floor and is what every version above resolves to today. - `workflow_dispatch`, and a per-version uv cache suffix. Verified locally across all six: lint, mypy and 573 tests pass on each. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Short answer to "should we test more Python versions": yes, and doing it found a bug.
CI ran a single Python 3.11 job while
pyproject.tomldeclaresrequires-python = ">=3.9"— five of the six supported versions were never exercised.What the matrix caught immediately
Nothing is pinned (no lockfile is committed), so each Python resolves its own dependency set. That is the point of the matrix here, and it is where the failure was hiding:
numpy 2.5's stubs give
np.isnana concretendarrayreturn type, so assigningNoneto that variable afterwards is an error. Python 3.9–3.11 resolve to numpy ≤ 2.4 and never see it — which is exactly why a single-version job missed it.Fixed by annotating
nan_mask: Optional[np.ndarray]. Typing-only, no runtime effect — the test suite passes on all six versions with or without it. No changelog entry for that reason.Also included, matching OmniWatermask
fetch-depth: 0sosetuptools-scmcan read tags. Without it CI was installing0.1.dev1+g<hash>instead of the real version — I verified this against a shallow clone. It is the same silent-version hazard the conda-forge recipe explicitly guards against with its version assertion.>=4.10floor and is what every version above resolves to today. The suite passes on it, but that happened without anyone deciding it.workflow_dispatchand a per-version uv cache suffix.fail-fast: falseso one version failing does not mask the rest.Verification
Ran the complete CI sequence locally against all six interpreters —
uv sync --all-extras --dev, ruff, mypy, pytest. All green:Two things left as your call
>=3.10, that is arequires-pythonbump plus removing one matrix entry.pyproject.tomlhas noclassifiers. OmniWatermask listsProgramming Language :: Python :: 3.10–3.14and topic/audience classifiers; MultiClean lists none, so PyPI shows no version support at all. Adjacent to this change but not part of it — happy to add them separately.🤖 Generated with Claude Code