Skip to content

Fix Python @property read edges and call resolution - #1065

Merged
7 commits merged into
tirth8205:stagingfrom
Ha1baraA11:pr/code-review-graph-1060
Nov 6, 2026
Merged

7 commits merged into
tirth8205:stagingfrom
Ha1baraA11:pr/code-review-graph-1060

Conversation

@Ha1baraA11

Copy link
Copy Markdown
Contributor

Linked issue

Closes #1060

What & why

  • Emit a CALLS edge for reads of explicitly declared @property getters when the owner class is known from local or imported bindings.
  • Use the property's return annotation to resolve methods called on an assigned property value.
  • Keep property reads on unknown receivers unresolved; cover cross-file classes, same-named properties, and unknown receivers in regression tests.

How it was tested

uv run ruff check code_review_graph/  # passed
uv run pytest tests/ --tb=short -q  # 4,269 passed, 850 skipped, 2 xfailed, 2 xpassed
uv run mypy code_review_graph/ --ignore-missing-imports --no-strict-optional  # reports an error at code_review_graph/embeddings.py:253, an unchanged file

The full test suite ran on Python 3.12.13 with watchdog's polling observer because the native macOS FSEvents observer crashed during full-suite runs on this host.

Checklist

  • Tests added for new functionality
  • All tests pass: uv run pytest tests/ --tb=short -q
  • Linting passes: uv run ruff check code_review_graph/
  • Type checking passes: uv run mypy code_review_graph/ --ignore-missing-imports --no-strict-optional
  • Lines are at most 100 characters
  • Docs updated where behavior changed (README, docs/, docstrings)

@tirth8205

Copy link
Copy Markdown
Owner

Thank you for this PR.

I tested small examples on this branch and on staging.

Before I can merge it, please fix these:

  1. Reading a property through cls makes a getter read edge. code_review_graph/parser.py:6687-6688 treats cls like self. Example: @classmethod def inspect(cls): return cls.value gives C.inspect -> C.value. A @staticmethod with a parameter named self does the same.

  2. Writing to a property also makes a read edge. code_review_graph/parser.py:6414-6449 does not check for stores. Examples: self.value = 2, del self.value, self.value, x = 2, 3 and for self.value in range(3). Please keep the edge for self.value += 1. That one is correct.

Please add tests for both cases.

After you push the fix, I will test it again.

@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

code-review-graph review

Overall risk: 0.65 (MEDIUM) — 43 changed function(s)/class(es), 52 affected flow(s), 30 test gap(s) (25 with no tested caller found, 5 reached only through a caller)

Risk-scored changes

Risk Level Symbol Location Tested
0.65 medium code_review_graph/graph.py::GraphStore._receiver_backed_candidates code_review_graph/graph.py:1718 indirect
0.65 medium code_review_graph/graph.py::GraphStore._resolve_bare_endpoints code_review_graph/graph.py:2121 indirect
0.65 medium code_review_graph/parser.py::_python_qualified_class_identity code_review_graph/parser.py:110 no
0.65 medium code_review_graph/parser.py::_python_split_class_identity code_review_graph/parser.py:115 no
0.65 medium code_review_graph/parser.py::_PythonScopeBindingVisitor code_review_graph/parser.py:170 no
0.65 medium code_review_graph/parser.py::_python_unreachable_call_positions code_review_graph/parser.py:436 no
0.65 medium code_review_graph/parser.py::CodeParser.scan_declarations code_review_graph/parser.py:6304 no
0.65 medium code_review_graph/parser.py::CodeParser.bind_targets code_review_graph/parser.py:6429 no
0.65 medium code_review_graph/parser.py::CodeParser.first_parameter_name code_review_graph/parser.py:6443 no
0.65 medium code_review_graph/parser.py::CodeParser._python_property_definition code_review_graph/parser.py:6795 no

Affected execution flows

  • process — criticality 0.74, 552 node(s) across 14 file(s)
  • _run — criticality 0.74, 579 node(s) across 16 file(s)
  • build_or_update_graph_tool — criticality 0.73, 633 node(s) across 24 file(s)
  • refactor_tool — criticality 0.72, 159 node(s) across 12 file(s)
  • main — criticality 0.72, 939 node(s) across 40 file(s)
  • ...and 47 more affected flow(s)

Test gaps

  • code_review_graph/parser.py::_python_qualified_class_identity (code_review_graph/parser.py:110)
  • code_review_graph/parser.py::_python_split_class_identity (code_review_graph/parser.py:115)
  • code_review_graph/parser.py::_PyReceiverContext (code_review_graph/parser.py:128)
  • code_review_graph/parser.py::_PythonScopeBindingVisitor (code_review_graph/parser.py:170)
  • code_review_graph/parser.py::_PythonScopeBindingVisitor.visit_Global (code_review_graph/parser.py:204)
  • ...and 20 more with no direct test

Reached only through a caller

No test names these directly, but a tested caller reaches them along the call path shown. That is a path in the call graph, not a record of execution -- the caller's tests may never take this branch. Treat it as where to look, not as coverage: these count as gaps and are scored as untested.

  • code_review_graph/graph.py::GraphStore._receiver_backed_candidates (code_review_graph/graph.py:1718) — via code_review_graph/graph.py::GraphStore.get_transitive_tests, 2 hop(s)
  • code_review_graph/graph.py::GraphStore._resolve_bare_endpoints (code_review_graph/graph.py:2121) — via code_review_graph/graph.py::GraphStore.resolve_bare_call_targets, 1 hop(s)
  • code_review_graph/parser.py::CodeParser._extract_bytes (code_review_graph/parser.py:3263) — via code_review_graph/parser.py::CodeParser.parse_bytes, 1 hop(s)
  • code_review_graph/parser.py::CodeParser._collect_python_receiver_evidence (code_review_graph/parser.py:6274) — via code_review_graph/parser.py::CodeParser.parse_bytes, 2 hop(s)
  • code_review_graph/parser.py::CodeParser._apply_python_receiver_evidence (code_review_graph/parser.py:7666) — via code_review_graph/parser.py::CodeParser.parse_bytes, 2 hop(s)

Powered by code-review-graph — local-first analysis; no code leaves the CI runner.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved binding, reachability, and scope-resolution defects produce false or missing property-getter call edges, making caller and dead-code analysis unreliable.

6 open issues
What changed in this PR

This PR addresses #1060 by adding Python property-read edges to the knowledge graph, improving caller discovery and dead-code analysis for explicitly declared getters.

Changes:

  • Emit CALLS edges for property reads with known receiver types.
  • Use getter return annotations to resolve calls on assigned property values.
  • Add regression coverage for cross-file resolution, unknown receivers, class receivers, and store targets.
File Description
tests/​test_python_property_reads.py Adds property-read and return-type resolution regression tests.
code_review_graph/​parser.py Collects property metadata, infers receiver types, and emits getter-call edges.

Review effort: Balanced

Comment thread code_review_graph/parser.py Resolved
Comment thread code_review_graph/parser.py Resolved
Comment thread code_review_graph/parser.py Resolved
Comment thread code_review_graph/parser.py Resolved
Comment thread code_review_graph/parser.py Resolved
Comment thread code_review_graph/parser.py Resolved
@tirth8205 tirth8205 closed this pull request by merging all changes into tirth8205:staging in 0160eb0 Nov 6, 2026
gowrishacv pushed a commit to gowrishacv/code-review-graph that referenced this pull request Nov 6, 2026
…8205#1065)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gowrishacv pushed a commit to gowrishacv/code-review-graph that referenced this pull request Nov 6, 2026
Take the head's class identity through receiver_class_file, candidate-set import conflicts, ast scope map and store-target checks: they cover more than our fix. Keep our depth guard on the imported-module walk and our tests that the head lacks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gowrishacv pushed a commit to gowrishacv/code-review-graph that referenced this pull request Nov 6, 2026
# Conflicts:
#	code_review_graph/graph.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Python @property reads produce no edge, so callers_of and find_dead_code miss every consumer

3 participants