Private
Public Access
test(gui_2): add 2 Phase 11 invariant tests + Phase 11 checkpoint
Two Phase 11 invariant tests in tests/test_gui_2_result.py verify
INTERNAL_RETHROW count for src/gui_2.py is 0 after the dunder-method
bare-raise heuristic:
- test_phase_11_invariant_rethrow_count_zero: scans audit --json
output, asserts 0 INTERNAL_RETHROW findings in gui_2.py
- test_phase_11_invariant_l757_l760_reclassified: scans audit --json
output, asserts no INTERNAL_RETHROW findings in any dunder-method
context (__getattr__/__getattribute__/__setattr__/__delattr__)
State.toml updates:
- phase_11 status: completed, checkpointsha: 6e03f5a
- phase_11_complete: true
- rethrow_count_zero: true
- t11_0/t11_1/t11_2 marked completed with their commit SHAs
Pre-Phase 11: gui_2.py had 2 INTERNAL_RETHROW sites (L778 + L781 in
App.__getattr__). Post-Phase 11: 0 sites. The heuristic in
scripts/audit_exception_handling.py:_classify_raise reclassifies
bare AttributeError/NameError raises in __getattr__/__getattribute__/
__setattr__/__delattr__ as INTERNAL_PROGRAMMER_RAISE (canonical
dunder-method pattern per error_handling.md lines 625-690).
Phase 11 result_migration_gui_2_20260619.
This commit is contained in:
@@ -2394,3 +2394,87 @@ def test_phase_10_invariant_all_13_sites_have_tests():
|
||||
|
||||
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Phase 11 Invariant Tests (result_migration_gui_2_20260619)
|
||||
# Lock the INTERNAL_RETHROW count: 2 sites reclassified as INTERNAL_PROGRAMMER_RAISE
|
||||
# via the dunder-method bare-raise heuristic in audit_exception_handling.py.
|
||||
# The 2 sites are bare `raise AttributeError(name)` in the App class's
|
||||
# __getattr__ dunder method (L778 and L781 in src/gui_2.py at the time
|
||||
# of Phase 11 closure; line numbers may shift slightly with future edits
|
||||
# but the audit's category-based invariant is stable).
|
||||
# =============================================================================
|
||||
|
||||
|
||||
def test_phase_11_invariant_rethrow_count_zero():
|
||||
"""
|
||||
Phase 11 invariant: the audit's INTERNAL_RETHROW count for src/gui_2.py
|
||||
is now 0. The 2 sites in the App class's __getattr__ method have been
|
||||
reclassified as INTERNAL_PROGRAMMER_RAISE via the new dunder-method
|
||||
bare-raise heuristic in scripts/audit_exception_handling.py:_classify_raise.
|
||||
|
||||
Per the styleguide (error_handling.md lines 625-690, Re-Raise Patterns),
|
||||
bare raises of AttributeError/NameError in __getattr__/__getattribute__/
|
||||
__setattr__/__delattr__ are the canonical dunder-method programmer-error
|
||||
pattern, NOT suspicious rethrows. The new heuristic recognizes this and
|
||||
reclassifies the sites as INTERNAL_PROGRAMMER_RAISE.
|
||||
|
||||
Pre-Phase 11 baseline: 2. Post-Phase 11 baseline: 0.
|
||||
"""
|
||||
result = subprocess.run(
|
||||
["uv", "run", "python", "scripts/audit_exception_handling.py", "--src", "src", "--json"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
assert result.returncode == 0, (
|
||||
f"audit_exception_handling.py exited {result.returncode}; stderr:\n"
|
||||
f"{result.stderr[:2000]}"
|
||||
)
|
||||
data = json.loads(result.stdout)
|
||||
gui2 = [f for f in data.get("files", []) if "gui_2" in f.get("filename", "")][0]
|
||||
rethrows = [f for f in gui2.get("findings", []) if f.get("category") == "INTERNAL_RETHROW"]
|
||||
assert len(rethrows) == 0, (
|
||||
f"Phase 11 invariant: expected 0 INTERNAL_RETHROW sites in src/gui_2.py "
|
||||
f"(post-Phase 11 baseline; the 2 dunder-method sites reclassified as "
|
||||
f"INTERNAL_PROGRAMMER_RAISE); found {len(rethrows)}. "
|
||||
f"Lines: {[f.get('line') for f in rethrows]}"
|
||||
)
|
||||
|
||||
|
||||
def test_phase_11_invariant_l757_l760_reclassified():
|
||||
"""
|
||||
Phase 11 invariant: the 2 dunder-method raise sites at L778 and L781
|
||||
(formerly documented as L757/L760; line numbers shifted slightly with
|
||||
subsequent edits) in src/gui_2.py are no longer in INTERNAL_RETHROW.
|
||||
|
||||
The heuristic reclassifies any `raise AttributeError` / `raise NameError`
|
||||
in a dunder method (__getattr__/__getattribute__/__setattr__/__delattr__)
|
||||
as INTERNAL_PROGRAMMER_RAISE. The audit must NOT report these sites as
|
||||
INTERNAL_RETHROW after Phase 11.
|
||||
|
||||
Note: the line numbers may shift with future edits to src/gui_2.py.
|
||||
This test scans ALL gui_2.py findings and asserts that no finding in
|
||||
the __getattr__ / __setattr__ method context is INTERNAL_RETHROW.
|
||||
"""
|
||||
result = subprocess.run(
|
||||
["uv", "run", "python", "scripts/audit_exception_handling.py", "--src", "src", "--json"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
assert result.returncode == 0, (
|
||||
f"audit_exception_handling.py exited {result.returncode}; stderr:\n"
|
||||
f"{result.stderr[:2000]}"
|
||||
)
|
||||
data = json.loads(result.stdout)
|
||||
gui2 = [f for f in data.get("files", []) if "gui_2" in f.get("filename", "")][0]
|
||||
rethrows = [
|
||||
f for f in gui2.get("findings", [])
|
||||
if f.get("category") == "INTERNAL_RETHROW"
|
||||
and f.get("context") in ("__getattr__", "__getattribute__", "__setattr__", "__delattr__")
|
||||
]
|
||||
assert len(rethrows) == 0, (
|
||||
f"Phase 11 invariant: expected 0 INTERNAL_RETHROW findings in "
|
||||
f"gui_2.py dunder-method contexts (__getattr__/__getattribute__/"
|
||||
f"__setattr__/__delattr__); found {len(rethrows)}. "
|
||||
f"Sites: {[(f.get('line'), f.get('context'), f.get('snippet')) for f in rethrows]}"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user