fix(python): avoid false edges for pytest decorators - #2739
Conversation
There was a problem hiding this comment.
Graphify reviewed this change.
Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).
Formal verification. No changes could be formally verified in this run.
Graphify review — findings
This PR adds pytest-decorator filtering to the Python extractor to prevent false decorator edges. It introduces an ordered module-level binding tracker (_python_pytest_bindings / _PythonBindingEvent) and an _is_pytest_decorator_noise check that classifies decorators like @pytest.fixture, @pytest.mark.*, and rebound @fixture names by qualified path or import binding in force at the decorator's location, rather than by bare tail name. It wires this check into the generic decorator extraction branch, adds supporting constants and a changelog entry, and includes a corresponding test.
No blocking issues surfaced. 4 lower-confidence candidates did not survive cross-model review.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 818 functions depend on the 423 functions this change touches.
Health — this change adds coupling hotspots:
- worse:
_extract_generic()— 18 callers, 24 callees - worse:
walk()— 1 callers, 56 callees
Verification — 818 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 759 function(s) in the blast radius were not formally verified this run
Formal verification
Could not verify: Could not verify \_extract\_generic.
The verifier did not have enough to check \_extract\_generic, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set
Could not verify: Could not verify \_python\_decorator\_name.
The verifier did not have enough to check \_python\_decorator\_name, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: not verifiable: all 182 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly AttributeError — names the real obstacle, not a sampling gap)
· 2 more finding(s) on lines outside this diff (see the check run).
Problem
Python decorator extraction currently resolves decorator names using the bare symbol name. This causes third-party pytest decorators such as
@pytest.fixtureand@pytest.mark.parametrizeto be treated as references to same-named functions in the corpus.When a project contains a local
fixture()orparametrize()function, repeated pytest decorators can therefore collapse onto that local node and create spuriousreferencesedges, producing misleading high-degree/"God Node" results.Fixes #2732.
Fix
import pytestand aliased imports such asimport pytest as pt.from pytest import fixtureandfrom pytest import mark.@fixture.delstatements so shadowed pytest names are not incorrectly suppressed.pytest.mark.*decorators without fabricating nodes for marker names.Tests
Adds regression coverage for:
@pytest.fixture@pytest.mark.parametrizewith/for/walrus rebindingdelunbinding@pytest.fixtureremaining a normal corpus referenceAlso updates the changelog for the fix.
Result
Pytest decorators are treated as external test-framework vocabulary when their binding proves they refer to pytest, preventing false cross-file decorator edges and spurious God Nodes while preserving legitimate project-owned decorators.