Skip to content

Commit ec1c636

Browse files
committed
fix: require boundary-check handlers to raise on every path
1 parent a92f8ae commit ec1c636

2 files changed

Lines changed: 37 additions & 6 deletions

File tree

‎scripts/python_boundary/_helpers/native_errors.py‎

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def _native_names(tree: ast.Module) -> frozenset[str]:
4040
names.update(
4141
alias.asname or alias.name
4242
for alias in node.names
43-
if native_module or NATIVE_MARKER in alias.name
43+
if native_module or _names_native(alias.name)
4444
)
4545
elif isinstance(node, ast.Import):
4646
names.update(
@@ -53,7 +53,11 @@ def _native_names(tree: ast.Module) -> frozenset[str]:
5353

5454
def _is_native_module(module: str) -> bool:
5555
parts: list[str] = module.split(".")
56-
return parts[0] == NATIVE_PACKAGE and any(NATIVE_MARKER in part for part in parts[1:])
56+
return parts[0] == NATIVE_PACKAGE and any(_names_native(part) for part in parts[1:])
57+
58+
59+
def _names_native(name: str) -> bool:
60+
return NATIVE_MARKER in name.split("_")
5761

5862

5963
def _guarded_blocks(tree: ast.Module) -> list[tuple[str, ast.stmt]]:
@@ -89,7 +93,17 @@ def _swallowing_lines(*, node: ast.stmt, native: frozenset[str]) -> list[int]:
8993

9094

9195
def _always_raises(handler: ast.ExceptHandler) -> bool:
92-
return any(isinstance(statement, ast.Raise) for statement in handler.body)
96+
return isinstance(handler.body[-1], ast.Raise) and not any(
97+
_exits_early(statement) for statement in handler.body
98+
)
99+
100+
101+
def _exits_early(node: ast.AST) -> bool:
102+
if isinstance(node, ast.Return | ast.Break | ast.Continue):
103+
return True
104+
if isinstance(node, ast.FunctionDef | ast.AsyncFunctionDef | ast.Lambda | ast.ClassDef):
105+
return False
106+
return any(_exits_early(child) for child in ast.iter_child_nodes(node))
93107

94108

95109
def _is_suppress(expression: ast.expr) -> bool:

‎tests/unit/scripts/python_boundary/main/test_check.py‎

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@
3434
" try:\n"
3535
" return content_digest([text])\n"
3636
" except ValueError:\n"
37-
" if strict:\n"
38-
" raise\n"
39-
" return None\n"
37+
" if not strict:\n"
38+
" return None\n"
39+
" raise\n"
4040
)
4141
SUPPRESSED: str = (
4242
"import contextlib\n"
@@ -65,6 +65,23 @@
6565
policy="remaining_lines = 2\n" + STAYS,
6666
expected_messages=("2 movable Python lines remain",),
6767
),
68+
PythonBoundaryTestCase(
69+
description="names that only contain the letters native are not native calls",
70+
source_files={
71+
"compiler/plan.py": (
72+
"from sqlbuild.compiler.alternatives import alternative_plan\n"
73+
"\n"
74+
"\n"
75+
"def plan():\n"
76+
" try:\n"
77+
" return alternative_plan()\n"
78+
" except ValueError:\n"
79+
" return None\n"
80+
)
81+
},
82+
policy="remaining_lines = 8\n",
83+
expected_messages=("8 movable Python lines remain",),
84+
),
6885
PythonBoundaryTestCase(
6986
description="re-raised native failures are allowed",
7087
source_files={"compiler/keys.py": RERAISED},

0 commit comments

Comments
 (0)