Skip to content

Require Python 3.10 and use the annotations it provides - #94

Merged
birkholz-cubert merged 1 commit into
developfrom
feature/require-python-3.10
Aug 19, 2026
Merged

Require Python 3.10 and use the annotations it provides#94
birkholz-cubert merged 1 commit into
developfrom
feature/require-python-3.10

Conversation

@birkholz-cubert

Copy link
Copy Markdown
Collaborator

What

  • Raises requires-python from >=3.9 to >=3.10, drops the typing_extensions dependency and the 3.9 classifier, and moves ruff to target-version = "py310".
  • Removes the try/except ImportError fallback in cuvis/doc.py; ParamSpec and TypeAlias are in typing from 3.10.
  • Rewrites 71 annotations: Union[A, B] and Optional[A] to A | B and A | None, and Tuple, FrozenSet, Sequence, Callable, Awaitable to builtins and collections.abc.
  • Fixes register_ready_callback, whose callback parameter was annotated Callable[None, Awaitable[None]].

Why

  • Python 3.9 reached end of life in October 2025, and it was the only reason for the typing_extensions dependency and the import fallback. CI already runs 3.11 alone, so no workflow changes.
  • The annotation rewrite is ALL-1431, which was blocked on the floor.
  • Callable[None, ...] was never a valid Callable form. typing.Callable did not validate it; collections.abc.Callable does and raises TypeError at import, so the migration surfaced it. The implementation calls callback() with no arguments, so Callable[[], Awaitable[None]] is what it always meant.

Pitfalls

  • Breaking for anyone still on 3.9. That is the point, but it is a floor bump in a wrapper-only revision, so it wants a deliberate version decision before release.
  • The annotation sweep touches 15 modules and is nearly all diff noise. Reviewing it commit-by-file is easier than reading the whole diff; it was applied with ruff check --select UP006,UP007,UP035,UP045 --fix, not by hand.
  • ImageData.__getitem__ deliberately keeps Union. Its member list contains a forward reference, and | cannot join a type to a string at runtime. Ruff declines to rewrite it for the same reason.

Verification

  • 123 passed against the installed SDK on 3.11.
  • Annotations evaluate cleanly on 3.10, 3.12 and 3.14; 3.9 now fails at import as intended.
  • ruff check, ruff format --check and scripts/check_changelog.py clean.

Python 3.9 reached end of life in October 2025, and it was the only
reason the package carried a typing_extensions dependency and a
try/except import fallback in cuvis/doc.py. CI has been running 3.11
alone for a while, so nothing in the workflow changes.

With the floor raised, the annotations are restated in the forms 3.10
provides: Union and Optional become A | B and A | None, and Tuple,
FrozenSet, Sequence, Callable and Awaitable come from builtins and
collections.abc. Applied with ruff's pyupgrade rules rather than by
hand. ImageData.__getitem__ keeps Union on purpose, because its member
list holds a forward reference and | cannot join a type to a string at
runtime.

The migration also surfaced a latent bug. register_ready_callback was
annotated Callable[None, Awaitable[None]], which is not a valid Callable
form; typing.Callable never checked, collections.abc.Callable does. It
is now Callable[[], Awaitable[None]], matching the no-argument call the
implementation makes.
@birkholz-cubert
birkholz-cubert merged commit 132fe14 into develop Aug 19, 2026
4 checks passed
@birkholz-cubert
birkholz-cubert deleted the feature/require-python-3.10 branch August 19, 2026 17:42
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