Repository navigation
feat(resolution): link Python base methods to their overrides (python-override) - #2076
Open
JosefAschauer wants to merge 3 commits into
Open
JosefAschauer wants to merge 3 commits into
JosefAschauer wants to merge 3 commits into
Conversation
…-override) A call bound to a base method (a base-typed receiver `store: Base; store.fetch()`, or a module global holding one of several backends) runs the subclass override at runtime, but no static edge reaches the override, so `callers`/`impact` of `Leaf.fetch` missed every such call. The interface-impl synthesis that bridges this for Java, Kotlin, C#, TS/JS, Swift, Scala, Go and Rust did not cover Python. The new pass links each Python override to the NEAREST declaration of the same name up its `extends` chain, since Python classes often inherit through a base that does not redeclare the method (`Leaf(Mid(Base))`). Class-creation hooks (`__init__`, `__new__`, `__init_subclass__`, `__class_getitem__`) are not virtual and are skipped. Edges are `calls`, provenance `heuristic`, `synthesizedBy: 'python-override'`, labelled in explore output. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018CQubRS1bXvaoApgPyLf66
…ed supertypes Review follow-up. `Base.make()` on a @staticmethod or @classmethod names its class and never runs the override, and a @Property is read, not called: skip them (and cached_property / .setter / .getter / .deleter) on either side; Python decorators are read from the source lines, since only `isStatic` is on the node. An `extends` edge resolved by bare-name guess (confidence < 0.7, e.g. two `Base` classes and no import) no longer carries dispatch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018CQubRS1bXvaoApgPyLf66
…ypes only Review follow-up. Confidence reflects proximity, not whether a supertype was guessed: a same-file base can score 0.4 while a cross-file bare-name guess under a package path scores 0.7. Follow an `extends` edge when it was resolved through an import or its base is in the same file; skip a cross-file `exact-match` / `fuzzy` guess. Decorators are read past blank and comment lines between them and the def. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018CQubRS1bXvaoApgPyLf66
This branch has not been deployed
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
callers/impactof a Python method override miss every call that binds to the base declaration. In the #2074 repro,QdrantConnection.delete_payload_fieldsshows 0 callers, even thoughgc_typedcalls it through aDocStoreConnection-typed receiver. A module global holding one of several backends (#2075) binds the same way. At runtime those calls run the override, but no static edge reaches it.The existing interface-impl and cpp-override synthesis passes bridge this for Java, Kotlin, C#, TS/JS, Swift, Scala, Go, Rust and C++. They don't cover Python.
Fix
A
pythonOverrideEdgessynthesis pass (synthesizedBy: 'python-override',calls, provenanceheuristic, with a label in explore output):Each Python override is linked from the nearest declaration of the same name up its
extendschain. Python classes often inherit through a base that doesn't redeclare the method (Leaf(Mid(Base))). A branch of the walk stops at its first declaration, so an override of an override links only to its parent.Not dispatch, so skipped on either side:
__init__,__new__,__init_subclass__,__class_getitem__;@staticmethodand@classmethod;@property,cached_property,.setter/.getter/.deleter.Python nodes only carry
isStatic, so decorators are read from the source lines, including past comment and blank lines.Only real supertypes: an
extendsedge is followed when it was resolved through an import or its base is in the same file. A cross-file bare-name guess (exact-match/fuzzy) is not followed, whatever its confidence. Confidence reflects proximity, not whether the base was guessed.No per-base cap: each edge is a real nearest-declaration override, and a cap would drop some silently.
Validation
__tests__/resolution.test.tsadds 2 cases:getCallersof an override reaches the base-typed call site;Every rule was mutation-checked.
npx tsc --noEmit: clean.resolution,frameworks-integration,extraction,function-refandui-flow-apitests: 1014 passed.Full suite on Linux (together with fix(resolution): resolve method values on untyped Python module globals (#2074) #2075): 5386 passed, 4 failed. The failures are environmental:
bundle-launcher×2: nozipbinary.cli-sync×2: the host runs Node 26, which prints the unsupported-Node banner.Real project (RAGFlow, 5.5k files):
python-overrideedges. The samples I checked were all genuine overrides, e.g.ComponentBase._invoke→ each agent tool's_invoke, andLoadConnector.load_credentials→ each connector's.impactofQdrantConnection.delete_payload_fieldsnow reaches its base-typed caller.Independent review (Grok): all findings fixed and pinned. Final verdict SHIP.
Not addressed
class Leaf(Base[str])) produce noextendsedge at extraction time, so no override edge is created. This is a pre-existing extraction gap, better handled as a separate change.Refs #2074 (the "Related, not addressed here" part). Independent of #2075.
🤖 Generated with Claude Code