Private
Public Access
test(audit_heuristics): add 5 regression tests for dunder raise (Phase 11)
Five regression-guard tests verify the new dunder-method bare-raise heuristic in scripts/audit_exception_handling.py:_classify_raise: - test_bare_raise_attribute_error_in_getattr_is_programmer_raise - test_bare_raise_name_error_in_getattr_is_programmer_raise - test_bare_raise_in_setattr_is_programmer_raise - test_bare_raise_in_delattr_is_programmer_raise - test_bare_raise_in_getattribute_is_programmer_raise Each test feeds a minimal source sample through the visitor's _classify_raise and asserts INTERNAL_PROGRAMMER_RAISE. The tests cover all 4 dunder methods (__getattr__, __getattribute__, __setattr__, __delattr__) and both programmer-error exception types (AttributeError, NameError). Phase 11 result_migration_gui_2_20260619.
This commit is contained in:
@@ -137,3 +137,87 @@ def test_phase7_migrated_sites_no_longer_silent_swallow():
|
|||||||
f"Phase 7 regression: L{f.line} should not be "
|
f"Phase 7 regression: L{f.line} should not be "
|
||||||
f"INTERNAL_SILENT_SWALLOW after migration; got {f.category}"
|
f"INTERNAL_SILENT_SWALLOW after migration; got {f.category}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Phase 11 Task 11.4 - Regression-guard tests for dunder-method bare-raise heuristic.
|
||||||
|
# Per Phase 11 spec (INTERNAL_RETHROW classification for dunder methods):
|
||||||
|
# - Bare `raise AttributeError(name)` / `raise NameError(name)` in
|
||||||
|
# `__getattr__`, `__getattribute__`, `__setattr__`, `__delattr__` is the
|
||||||
|
# canonical dunder-method programmer-error pattern (per styleguide
|
||||||
|
# "Re-Raise Patterns": bare raises are reserved for programmer errors).
|
||||||
|
# - The audit previously classified these as INTERNAL_RETHROW (suspicious);
|
||||||
|
# the heuristic must reclassify them as INTERNAL_PROGRAMMER_RAISE.
|
||||||
|
|
||||||
|
DUNDER_RAISE_TESTS = {
|
||||||
|
"__getattr__": "def __getattr__(self, name):\n if name == 'controller':\n raise AttributeError(name)\n raise AttributeError(name)",
|
||||||
|
"__getattribute__": "def __getattribute__(self, name):\n if name == 'controller':\n raise AttributeError(name)\n raise AttributeError(name)",
|
||||||
|
"__setattr__": "def __setattr__(self, name, value):\n raise AttributeError(name)",
|
||||||
|
"__delattr__": "def __delattr__(self, name):\n raise AttributeError(name)",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _classify_first_raise(source, func_name):
|
||||||
|
tree = ast.parse(source)
|
||||||
|
for node in ast.walk(tree):
|
||||||
|
if isinstance(node, ast.FunctionDef) and node.name == func_name:
|
||||||
|
visitor = ExceptionVisitor(str(ROOT / "src" / "_test_dummy.py"))
|
||||||
|
visitor._func_stack = [node]
|
||||||
|
for sub in ast.walk(node):
|
||||||
|
if isinstance(sub, ast.Raise) and sub.exc is not None:
|
||||||
|
return visitor._classify_raise(sub)
|
||||||
|
raise AssertionError(f"No raise found in {func_name}")
|
||||||
|
|
||||||
|
|
||||||
|
def test_bare_raise_attribute_error_in_getattr_is_programmer_raise():
|
||||||
|
src = DUNDER_RAISE_TESTS["__getattr__"]
|
||||||
|
category, hint = _classify_first_raise(src, "__getattr__")
|
||||||
|
assert category == "INTERNAL_PROGRAMMER_RAISE", (
|
||||||
|
f"Phase 11 regression: bare `raise AttributeError(name)` in __getattr__ "
|
||||||
|
f"should be INTERNAL_PROGRAMMER_RAISE (canonical dunder-method pattern); "
|
||||||
|
f"got {category}. Hint: {hint}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_bare_raise_name_error_in_getattr_is_programmer_raise():
|
||||||
|
src = (
|
||||||
|
"def __getattr__(self, name):\n"
|
||||||
|
" if not hasattr(self, 'x'):\n"
|
||||||
|
" raise NameError(name)\n"
|
||||||
|
" return self.x"
|
||||||
|
)
|
||||||
|
category, hint = _classify_first_raise(src, "__getattr__")
|
||||||
|
assert category == "INTERNAL_PROGRAMMER_RAISE", (
|
||||||
|
f"Phase 11 regression: bare `raise NameError(name)` in __getattr__ "
|
||||||
|
f"should be INTERNAL_PROGRAMMER_RAISE (canonical dunder-method pattern); "
|
||||||
|
f"got {category}. Hint: {hint}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_bare_raise_in_setattr_is_programmer_raise():
|
||||||
|
src = DUNDER_RAISE_TESTS["__setattr__"]
|
||||||
|
category, hint = _classify_first_raise(src, "__setattr__")
|
||||||
|
assert category == "INTERNAL_PROGRAMMER_RAISE", (
|
||||||
|
f"Phase 11 regression: bare `raise AttributeError` in __setattr__ "
|
||||||
|
f"should be INTERNAL_PROGRAMMER_RAISE (canonical dunder-method pattern); "
|
||||||
|
f"got {category}. Hint: {hint}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_bare_raise_in_delattr_is_programmer_raise():
|
||||||
|
src = DUNDER_RAISE_TESTS["__delattr__"]
|
||||||
|
category, hint = _classify_first_raise(src, "__delattr__")
|
||||||
|
assert category == "INTERNAL_PROGRAMMER_RAISE", (
|
||||||
|
f"Phase 11 regression: bare `raise AttributeError` in __delattr__ "
|
||||||
|
f"should be INTERNAL_PROGRAMMER_RAISE (canonical dunder-method pattern); "
|
||||||
|
f"got {category}. Hint: {hint}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_bare_raise_in_getattribute_is_programmer_raise():
|
||||||
|
src = DUNDER_RAISE_TESTS["__getattribute__"]
|
||||||
|
category, hint = _classify_first_raise(src, "__getattribute__")
|
||||||
|
assert category == "INTERNAL_PROGRAMMER_RAISE", (
|
||||||
|
f"Phase 11 regression: bare `raise AttributeError(name)` in __getattribute__ "
|
||||||
|
f"should be INTERNAL_PROGRAMMER_RAISE (canonical dunder-method pattern); "
|
||||||
|
f"got {category}. Hint: {hint}"
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user