fix(python): locate places a decorator-line position on the decorated callable - #412
Merged
Merged
Conversation
… callable (#408) PyCallable.start_line is the def line (ast.FunctionDef.lineno) and the AST puts decorators above it, so a position on @http.route(...) sat in no callable span and fell through to module_scope. Both backends now read where the decorator is applied: _find_innermost admits a callable whose decorators[].span starts at or before the line and above its def; _LOCATE_QUERY gains one EXISTS disjunct over PY_DECORATED_BY.start_line, which codeanalyzer-python 1.5.2 emits. An older graph or analysis carries no span there, the comparison is null, and the position stays module scope. Ranking is unchanged (def-based width), so a decorator on a nested callable resolves to the nested one. A class decorator is still module scope, pinned. Fixture gains cached/outer.helper/old/Config; fourteen new tests, parity included.
odoo-slim-19 re-emitted by codeanalyzer-python 1.5.3, 40 positions, median of 5, same graph both ways: 71.0 ms placing 20/40 before the PY_DECORATED_BY disjunct, 70.2 ms placing 40/40 with it; the plan still seeks pysymbol_id.
Collaborator
Author
|
Live tier on the 1.5.3 graph (
Every
|
rahlk
changed the base branch from
chore/issue-410-codeanalyzer-python-1.5.3
to
release/2.0
September 16, 2026 08:20
This was referenced Sep 16, 2026
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 #408. Stacked on #411 (the 1.5.3 bump) so the two
CHANGELOG.mdentries share one rc.8 section; retarget torelease/2.0once #411 merges.PyCallable.start_lineis thedefline (ast.FunctionDef.lineno) and the AST puts decorators above it, so a position on@http.route(...)sat inside no callable span andlocatereportedmodule_scope. Both backends now read where the decorator is applied:_find_innermostadmits the callable whosedecorators[].spanstarts at or before the line and above itsdef(_decorator_covers);_LOCATE_QUERYgains oneEXISTSdisjunct overPY_DECORATED_BY.start_line, which codeanalyzer-python 1.5.2 emits.Ranking is unchanged (def-based width), so a decorator on a nested callable resolves to the nested one. Not changed, and pinned by tests: a blank line with no decorator over it stays
module_scope(no nearest-callable fallback); a class decorator staysmodule_scope; an analysis or graph from 1.5.1 or earlier, which records no decorator span, answers exactly as before and raises nothing.Tests. The shared locate fixture gains
cached(two decorators),outer.helper(decorator on a nested callable inside the enclosing span),old(decorator recorded without a span) and a@dataclassclass. Fourteen new tests over both backends, parity included; the fake driver's responder evaluates the disjunct only when the statement namesPY_DECORATED_BYand only over edges that carrystart_line, so dropping either fails the suite.Measured. odoo-slim-19 re-emitted by codeanalyzer-python 1.5.3 at level 1 (1,626 modules, 15,549 callables, 5,615 decorator edges), 40 positions (20 decorator lines, 20 body lines), median of 5, same graph both ways:
The plan still seeks
pysymbol_id(NodeUniqueIndexSeekByRange); the disjunct runs asSelectOrSemiApplyover the seek's rows. The number is recorded above_LOCATE_QUERY.Verification.
tests/analysis/pythonoffline: 496 passed, 168 skipped (all live-Neo4j tiers). Rest of the offline suite: 1298 passed, 236 skipped.docs/agent-api-reference.mdgains a decorator-line row in thelocateoutcomes table.Siblings checked. TypeScript's callable span starts at the first decorator line (measured with 1.6.0:
start_line 4for a method declared on line 6) and Java's at the first annotation line (measured with 3.3.3: span start[4, 5]for a method declared on line 6), so neither backend has this gap.