fix(extract): emit references edges for Python decorators (#2154)#2175
Open
Rishet11 wants to merge 2 commits into
Open
fix(extract): emit references edges for Python decorators (#2154)#2175Rishet11 wants to merge 2 commits into
Rishet11 wants to merge 2 commits into
Conversation
…abs#2154) Applying a Python decorator emitted no edge to the decorator symbol, so `affected <decorator>` answered "No affected nodes found" for every function it wraps — a silent false negative on reverse-impact queries. TS/JS already emit these edges via `_ts_emit_decorator_edges`. The Python `decorated_definition` branch walked its children only to propagate the parent class id (Graphify-Labs#1050) and never looked at the `decorator` children. Python now emits the same shape: a `references` edge with context="decorator" from the decorated function/class to each decorator symbol. Owner ids reuse the definition branches' own formulas, so the edge lands on the node the walk creates. Targets go through `ensure_named_node`, so an imported decorator becomes a sourceless stub the corpus rewire collapses onto its real definition. Stacked, called (`@retry(3)`) and attribute (`@app.route`) decorators are covered; the attribute form targets the symbol, not the module alias, matching `_ts_decorator_name`.
…2154) Nine cases: the issue's imported-decorator repro, same-file resolution to the local definition, called and attribute decorators, stacked decorators, class-qualified method owners, a decorated class, the Graphify-Labs#1050 @Property class-qualification regression guard, and an absence control.
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.
Closes #2154
Python now emits the same decorator edges TS/JS already emits.
Problem
Applying a Python decorator emitted no edge to the decorator symbol, so
affected <decorator>answered "No affected nodes found" for every function it wraps — a silent false negative on reverse-impact queries.decorated_definitionwas handled as a transparent wrapper so a decorated method keeps its class-qualified node id (#1050). Itsdecoratorchildren were walked, but no branch consumed them:TS/JS already handled this via
_ts_emit_decorator_edges. Python was never wired up.Fix
A
_python_decorator_namehelper placed directly above its twin_ts_decorator_name, differing only in grammar node names (Pythoncall/attributevs TScall_expression/member_expression), plus emission inside the existingdecorated_definitionbranch.referencesedge withcontext="decorator"from the decorated function/class to each decorator symbol. No new edge type, so no schema, HTML exporter, MCP server, oraffectedchange._make_id(stem, ns, name)for classes,_make_id(parent_class_nid, name)for methods,_make_id(stem, name)for module-level functions), so the edge lands on the node the walk is about to create.ensure_named_node, so an imported decorator becomes a sourceless stub the corpus rewire collapses onto its real definition — this is what makes cross-fileaffectedwork.config.ts_module == "tree_sitter_python";decorated_definitionis a Python-only grammar node.#1050parent_class_nidpropagation is untouched, with a regression test pinning it.Covered forms:
@deco,@deco(arg),@mod.deco(arg)(targets the symbol, not the module alias, matching_ts_decorator_name), stacked decorators, decorated classes, and decorated methods. Names thatnormalize_id()empties are skipped, matching the#1899guard in the definition branches, so no edge can dangle.Verification
End-to-end on the issue's repro, before:
after:
tests/test_ts_decorators.py+ Python extraction subsets66d8110ruff checkpython -m tools.skillgen --checkThe 15 pre-existing failures are unrelated (
test_ollama.pybackend-detection and similar) and identical before and after; measured with-p no:randomlyin the same env.Known limitation
A comment placed between
@and the decorator expression (@ # notenewlinedeco) drops that one edge. It is a missed edge, never an incorrect one, and does not affect decorators written in normal style. Left out of scope to keep the diff surgical; happy to fold in a fix if you would prefer it here.