Repository navigation
fix(python): a class with PEP 695 type parameters reads its base list - #3105
Closed
JosefAschauer wants to merge 1 commit into
Closed
JosefAschauer wants to merge 1 commit into
JosefAschauer wants to merge 1 commit into
Conversation
pythonBaseList, behind module-global, self. and class-name dispatch,
expected the base list's "(" right after the class name, so a class
written `class Repo[T](Base[T]):` had no bases for those readers. It
now skips a type parameter list between the name and the bases,
bracket-balanced and wrapped or not, so a constraint tuple inside it
(`[T: (int, str)]`) is not taken for the base list. A parameterized
class without bases still has none. Extraction already gave these
classes their extends edge; the test keeps that as a control.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018hJjBUPFiLSFBssshFwHzq
colbymchenry
pushed a commit
that referenced
this pull request
Oct 30, 2026
pythonBaseList, the resolver's reader of a Python base list behind module-global, self. and class-name dispatch, expected the ( of the list right after the class name. In class Repo[T](Base[T]): it found the [ of the type parameters, so the class seemed to have no bases there, though extraction gave it its extends edge: current = Repo() then current.run(), and Repo.run(x), reached nothing. The reader now skips a type parameter list between the name and the bases, with brackets balanced, so bounds like T: dict[str, int], *Ts and **P go whole, and a constraint tuple like [T: (int, str)] isn't taken for the base list. Either list can wrap over several lines. Anything else after the name and its parameters, such as the : of class NoBases[T]:, still means no base list. Validation: - The test file: 4 of 7 fail on main (the controls pass), 7 pass here, and the multiline, generic-base and type-argument suites still pass. - A fixture of ours on the built CLI, kernel on: Repo.run(None), a wrapped list, a constraint tuple and a module global reach no method on main and Base::run here. class NoBases[T] reaches neither run, and Typed[T](Base[User]) does not reach User.save. - A/B against main on 11 Python repos, 486,377 edges (requests, flask, litestar, mypy, sqlalchemy, polar's and django's packages, and four small apps that use PEP 695 bases): nothing changes. Neither do express and gin, whose full dumps are byte-identical. polar has 39 such classes, and none is reached by a call this reader decides. - Index cost on sqlalchemy, median of 3 interleaved: 23.4 s on main and here. Original PR #3105 by @JosefAschauer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner
|
Thanks @JosefAschauer! This landed as #3111 with you as the commit author, with your fix and test unchanged. On main, a class like |
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.
What
This is a follow-up to #3103, covering the first gap its notes list. A Python class written with PEP 695 type parameters,
class Repo[T](Base[T]):, had no base list for the resolver's readerpythonBaseList. That reader sits behind module-global,self.and class-name dispatch, and since #3103 it also backsdeclaredSupertypes. It expected the(of the base list right after the class name, and found the[of the type parameters instead.pythonBaseListnow skips a type parameter list between the name and the bases:T: dict[str, int],*Tsand**Pare skipped whole.[T: (int, str)], is not taken for the base list.:) still means the class has no base list, soclass NoBases[T]:gets none.Extraction already gave these classes their
extendsedge. The test keeps that as a control; the gap was only in dispatch.Tests
__tests__/python-pep695-bases.test.ts.BaseandOtherboth declarerun, so only the class's own bases can pick one. Each case is checked through a module global and through the class name:Repo[T](Base[T]);*Tsand**P;extendsedges (control);run.Without the change, the 4 PEP 695 dispatch cases fail; with it, all 7 pass.
python-multiline-basesandpython-generic-basesstill pass.Full suite on main 27c904b plus this change: 9336 passed, 8 failed. The 8 are
bundle-launcherx2,cli-syncx2 andgitignore-pattern-parityx4, and they fail the same way on plain main here.tsc --noEmitis clean.The second gap from those notes, a
#or)inside a string in a base list, is left as it is: it would take a tokenizer for close to no real code.🤖 Generated with Claude Code
https://claude.ai/code/session_018hJjBUPFiLSFBssshFwHzq