Skip to content

Commit fed05e2

Browse files
gadievronclaude
andcommitted
fix(parsers/python): extract block-scoped def/class units
The extractor recursed only into `FunctionDef`/`ClassDef` bodies, never into block statements, so a `def`/`class` inside an `if`/`elif`/`else`, `try`/ `except`/`finally`, `for`/`while`, `with`, or `match`/`case` block was dropped from both the inventory and the call graph (call_graph_builder consumes the same `functions` dict — no independent traversal). A `def` under `if sys.version_info >= ...`, a `try/except ImportError` fallback, a `with`-guarded handler, or a class-based-view `if/else` dispatcher was never a unit, never a reachability node, and its body — including any sink — leaked verbatim into the synthetic `:__module__` unit (also producing spurious `__module__ -> callee` edges). Add `_descend_into_blocks`: walk block-container bodies (incl. except/finally arms and match cases) at ALL depths and hand any def/class to the existing tree helpers. Descend ONLY into block nodes — direct `FunctionDef`/`ClassDef` children are emitted by the caller, so the node sets are disjoint (no double-processing). Wired into `process_file`, `_process_function_tree`, and `_process_class_tree`. This matches Python's existing baseline (function-nested defs are already units) and reuses the existing keep-both (`#L<line>`) machinery, so sibling-block same-name defs and block-vs-top-level same-name defs both survive. Closes the `:__module__` leak by covering every def/class span (`ast.walk`, not just top-level children) in `extract_module_level_code`. Also adds the canonical per-parser test-infra files (absent for Python until now): `tests/parsers/python/test_callgraph_symmetry.py` and `tests/parsers/python/test_python_schema_completeness.py`. Tests: tests/parsers/python/test_block_scoped_defs.py (if/else/try/except/ finally/for/while/with/match shapes; async + decorated; class-in-block; function- internal block; sibling keep-both; block-vs-top-level keep-both; no __module__ leak): $ pytest tests/parsers/python/test_block_scoped_defs.py -q 15 passed $ pytest tests/parsers/python/ -q 64 passed Full repo suite: 636 passed, 22 skipped. Flask: both views.py `view` dispatchers surfaced (view + view#L115, keep-both); all 6 globals.py `if TYPE_CHECKING:` classes surfaced. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent ad17f3f commit fed05e2

4 files changed

Lines changed: 530 additions & 45 deletions

File tree

0 commit comments

Comments
 (0)