Skip to content

Test on Python 3.15, and fix the typing._eval_type call it breaks - #87

Merged
wbarnha merged 1 commit into
masterfrom
claude/python-3.15-cicd-testing-6jtvbj
Aug 10, 2026
Merged

Test on Python 3.15, and fix the typing._eval_type call it breaks#87
wbarnha merged 1 commit into
masterfrom
claude/python-3.15-cicd-testing-6jtvbj

Conversation

@wbarnha

@wbarnha wbarnha commented Aug 10, 2026

Copy link
Copy Markdown
Member

Description

Adds Python 3.15 to the CI matrix, and fixes the one thing that stopped the suite passing on it.

CI

Two new rows — 3.15 and 3.15t (default and free-threaded builds), matching the coverage the 3.14 rows get.

allow-prereleases: true on setup-python resolves 3.15 to whatever pre-release the runner image publishes — 3.15.0rc1 today — and will pick up 3.15.0 final in October with no further change here. Setting it does not disturb the stable rows: it widens 3.X to ~3.X.0-0, and a pre-release only wins when no stable release satisfies the spec, so 3.10–3.14 still resolve to their newest stable patch. I verified this against the real actions/python-versions manifest — 3.10 → 3.10.20, 3.12 → 3.12.13, 3.14 → 3.14.7, identical with and without the flag; and without it 3.15 resolves to nothing at all, which is the "Version 3.15 was not found in the local cache" failure.

The new rows are advisory (experimental: truecontinue-on-error) while 3.15 is a pre-release, so a CPython-side regression in rc2 or final can't block merges on a version nothing runs in production. The comment in the workflow records how to promote them to required once 3.15.0 ships.

The fix

The suite did not pass as-is. typing._eval_type gained a type_params argument in 3.13, where omitting it only emitted a DeprecationWarning and defaulted to (). In 3.15 it is a required positional, so every call raised:

TypeError: _eval_type() missing 1 required positional argument: 'type_params'

That took out all five annotation tests here. It also stopped faust importing at all on 3.15 — every faust Record model resolves its annotations through mode.utils.objects.annotations, so collection died before the first test ran. See faust-streaming/faust#770, which is blocked on this landing and being released.

Nothing resolved through eval_type carries PEP 695 type parameters of its own, so () is both what 3.13/3.14 already substituted when the argument was omitted and what 3.15 requires — passing it explicitly keeps behaviour identical across versions and silences the 3.13/3.14 deprecation warning on the way.

The signature is inspected once at import rather than caught per call on purpose: _eval_type also raises TypeError for annotations typing._type_check rejects, and eval_type depends on being able to tell those two apart (that's the ClassVar branch right below it).

Verification

Ran against the actual 3.15.0rc1 build the runners use, not a proxy:

result
3.15.0rc1 866 passed, 1 skipped
3.15.0rc1 free-threaded (3.15t) 866 passed — GIL confirmed disabled
3.11 (regression check) 866 passed, unchanged
ruff check + ruff format --check clean
mypy typecheck test clean

Generated by Claude Code

Adds Python 3.15 to the CI matrix, both the default and the free-threaded
build.  `allow-prereleases` on setup-python resolves `3.15` to the newest
pre-release the runner image publishes (3.15.0rc1 today) and will pick up
3.15.0 final when it ships, with no further change here.  Setting it does
not disturb the stable rows: it widens `3.X` to `~3.X.0-0`, and a
pre-release only wins when no stable release satisfies the spec, so
3.10-3.14 still resolve to their newest stable patch.

The rows are advisory (`experimental: true` -> `continue-on-error`) while
3.15 is a pre-release, so a CPython-side regression in rc2 or final cannot
block merges on a version nothing runs in production.  The comment records
how to promote them.

The suite did not pass as-is.  `typing._eval_type` gained a `type_params`
argument in 3.13, where omitting it only warned and defaulted to `()`; in
3.15 it is a required positional, so every call raised

    TypeError: _eval_type() missing 1 required positional argument: 'type_params'

which took out all five annotation tests -- and, because faust resolves
every Record model's annotations through `mode.utils.objects.annotations`,
stopped faust importing at all on 3.15.

Nothing resolved here carries PEP 695 type parameters of its own, so `()`
is both what 3.13/3.14 already substituted and what 3.15 wants; passing it
explicitly keeps behaviour identical across versions and silences the
3.13/3.14 deprecation warning.  The signature is inspected once at import
rather than caught per call, because `_eval_type` also raises TypeError for
annotations `typing._type_check` rejects and `eval_type` relies on telling
those two apart.

Verified against the 3.15.0rc1 build the runners use: 866 passed on 3.15
and on 3.15t, unchanged on 3.11, with ruff and the mypy typecheck test
clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jr6Lsfd3fULmP1Gi4b6nDK
@wbarnha
wbarnha merged commit b63a8c1 into master Aug 10, 2026
15 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.

2 participants