Repository navigation
fix(python): a base's type argument is no supertype, so Repo.save() is not User.save - #3000
Closed
JosefAschauer wants to merge 1 commit into
Closed
JosefAschauer wants to merge 1 commit into
JosefAschauer wants to merge 1 commit into
Conversation
…s not User.save declaredSupertypes' Python branch took every word of the base list, so `class Repo(Base[User])` declared `Base` and `User`. A call on the class or on a receiver named after it (classStrategyMethod -> inheritedClassMethod), `Repo.save()` / `repo.save()`, then reached `User.save` at 0.85 / 0.8 when `Base` declares no `save`. Bracketed type arguments, nested too, are now dropped before the names are read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018hJjBUPFiLSFBssshFwHzq
This was referenced Oct 29, 2026
colbymchenry
pushed a commit
that referenced
this pull request
Oct 30, 2026
…s not User.save The Python branch of declaredSupertypes read every word of a class's base list, so class Repo(Base[User]) declared both Base and User. A call on the class or on a receiver named after it, Repo.save() or repo.save(), walks those supertypes for the method (classStrategyMethod to inheritedClassMethod), and when Base declares no save it reached User.save at 0.85 or 0.8. In class Mixed(Base[Optional[User]], Mixin) the type argument also came ahead of Mixin, so Mixed.save() reached User.save instead of Mixin.save. Bracketed type arguments, nested ones and quoted forward references too, are now dropped before the names are read. The base itself is still read and searched. Other languages are untouched. Validation: - The new test file: red on main (the type-argument and later-base cases fail, the case that a base's own method is still reached passes), green here. We added the Mixed and quoted forward-reference cases to the contributor's test. - A/B against main on 7 Python repos, 670,226 edges on main: requests, flask, litestar, mypy, polar's server, django unchanged, sqlalchemy 1 edge removed, 0 added, 0 retargeted. That edge is a.references(b) in relationships.py. Its local a named a test's class a(TypedColumns), and TypedColumns' type argument "Column[Any]" reached Column.references: the right method by chance, by the path this fixes. Its twin b.references(a) two lines down has no edge in either arm. - Controls express and gin: full dumps byte-identical. - Kernel parity on flask and requests: 43/43 in both arms (the kernel is not touched). Index cost on sqlalchemy, median of 3 interleaved: 29.5 s on main, 25.7 s here, so nothing measurable. Original PR #3000 by @JosefAschauer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner
|
Thanks @JosefAschauer! This landed as #3083 with you as the commit author, and your fix went in unchanged. We added two test cases, a type argument ahead of a real base and a quoted forward reference, and moved the CHANGELOG bullet next to the other Python entries. |
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.
Problem
declaredSupertypes' Python branch reads every word of a class's base list, soclass Repo(Base[User])declares bothBaseandUser. A call on the class, or on a receiver named after it, walks those supertypes for the method (classStrategyMethod→inheritedClassMethod). WhenBasedeclares nosave, it findsUser.save:Repo.save()User::save(qualified-name, 0.85)repo.save()User::save(instance-method, 0.8)Useris only a type argument, so both edges are confidently wrong. Found while working on #2998.Fix
The Python branch drops bracketed type arguments, nested ones too, before reading the names.
Baseis still read and searched. Other languages are untouched.Validation
New
__tests__/python-supertype-type-arguments.test.ts:Repo.save(),repo.save(), a nestedPair[str, dict[str, User]]and ametaclass=head no longer reachUser::save(a decoyOther.saveexists too);Repo.load()/Store.load()still reachBase::load/Pair::load.Mutation-checked: with the stripping disabled, the first test fails.
npx tsc --noEmit: clean.Full suite on Linux: 8762 passed, 4 failed. The failures are environmental and also fail on
main:bundle-launcher×2: nozipbinary.cli-sync×2: Node 26 prints the unsupported-Node banner.Independent review (Grok): SHIP.
Not addressed
classline plus two, so a base list wrapped over more lines is still read only in part. That limit predates this change.Independent of #2076, #2998 and #2999.
🤖 Generated with Claude Code
https://claude.ai/code/session_018hJjBUPFiLSFBssshFwHzq