Skip to content

Commit e98aae9

Browse files
Add tertiary AST import-helper boundary guards
Co-authored-by: Shri Sukhani <shrisukhani@users.noreply.github.com>
1 parent ce42ba8 commit e98aae9

8 files changed

Lines changed: 130 additions & 0 deletions

CONTRIBUTING.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ This runs lint, format checks, compile checks, tests, and package build.
103103
- `tests/test_ast_secondary_import_helper_usage.py` (shared AST secondary import-helper usage enforcement across AST boundary guard suites),
104104
- `tests/test_ast_symbol_import_helper_import_boundary.py` (shared AST symbol-import helper import boundary enforcement across test modules),
105105
- `tests/test_ast_symbol_import_helper_usage.py` (shared AST symbol-import helper usage enforcement across AST boundary guard suites),
106+
- `tests/test_ast_tertiary_import_helper_import_boundary.py` (shared AST tertiary import-helper import boundary enforcement across test modules),
107+
- `tests/test_ast_tertiary_import_helper_usage.py` (shared AST tertiary import-helper usage enforcement across AST boundary guard suites),
106108
- `tests/test_binary_file_open_helper_usage.py` (shared binary file open helper usage enforcement),
107109
- `tests/test_browser_use_payload_helper_usage.py` (browser-use payload helper usage enforcement),
108110
- `tests/test_ci_workflow_quality_gates.py` (CI guard-stage + make-target enforcement),

tests/ast_import_utils.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,11 @@ def imports_imports_imports_collect_function_sources(module_text: str) -> bool:
6060
module="tests.ast_import_utils",
6161
symbol="imports_imports_collect_function_sources",
6262
)
63+
64+
65+
def imports_imports_imports_imports_collect_function_sources(module_text: str) -> bool:
66+
return imports_symbol_from_module(
67+
module_text,
68+
module="tests.ast_import_utils",
69+
symbol="imports_imports_imports_collect_function_sources",
70+
)

tests/test_architecture_marker_usage.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
"tests/test_ast_secondary_import_helper_usage.py",
3333
"tests/test_ast_symbol_import_helper_import_boundary.py",
3434
"tests/test_ast_symbol_import_helper_usage.py",
35+
"tests/test_ast_tertiary_import_helper_import_boundary.py",
36+
"tests/test_ast_tertiary_import_helper_usage.py",
3537
"tests/test_guardrail_ast_utils.py",
3638
"tests/test_helper_transport_usage_boundary.py",
3739
"tests/test_manager_model_dump_usage.py",

tests/test_ast_call_symbol_helper_usage.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"tests/test_ast_module_import_helper_usage.py",
1414
"tests/test_ast_secondary_import_helper_usage.py",
1515
"tests/test_ast_symbol_import_helper_usage.py",
16+
"tests/test_ast_tertiary_import_helper_usage.py",
1617
)
1718

1819

tests/test_ast_import_utils.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
imports_collect_function_sources,
66
imports_from_module,
77
imports_imports_imports_collect_function_sources,
8+
imports_imports_imports_imports_collect_function_sources,
89
imports_imports_collect_function_sources,
910
imports_symbol_from_module,
1011
)
@@ -211,6 +212,42 @@ def test_imports_imports_imports_collect_function_sources_ignores_non_from_impor
211212
assert imports_imports_imports_collect_function_sources(module_text) is False
212213

213214

215+
def test_imports_imports_imports_imports_collect_function_sources_detects_expected_import():
216+
module_text = (
217+
"from tests.ast_import_utils import imports_imports_imports_collect_function_sources\n"
218+
"imports_imports_imports_collect_function_sources('dummy')\n"
219+
)
220+
221+
assert imports_imports_imports_imports_collect_function_sources(module_text) is True
222+
223+
224+
def test_imports_imports_imports_imports_collect_function_sources_ignores_non_matching_imports():
225+
module_text = (
226+
"from tests.ast_import_utils import imports_imports_collect_function_sources\n"
227+
"imports_imports_collect_function_sources('dummy')\n"
228+
)
229+
230+
assert imports_imports_imports_imports_collect_function_sources(module_text) is False
231+
232+
233+
def test_imports_imports_imports_imports_collect_function_sources_supports_aliased_import():
234+
module_text = (
235+
"from tests.ast_import_utils import imports_imports_imports_collect_function_sources as helper\n"
236+
"helper('dummy')\n"
237+
)
238+
239+
assert imports_imports_imports_imports_collect_function_sources(module_text) is True
240+
241+
242+
def test_imports_imports_imports_imports_collect_function_sources_ignores_non_from_imports():
243+
module_text = (
244+
"import tests.ast_import_utils as import_utils\n"
245+
"import_utils.imports_imports_imports_collect_function_sources('dummy')\n"
246+
)
247+
248+
assert imports_imports_imports_imports_collect_function_sources(module_text) is False
249+
250+
214251
def test_calls_symbol_detects_direct_function_call():
215252
module_text = (
216253
"from tests.ast_function_source_utils import collect_function_sources\n"

tests/test_ast_import_utils_module_import_boundary.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
"tests/test_ast_secondary_import_helper_usage.py",
2323
"tests/test_ast_symbol_import_helper_import_boundary.py",
2424
"tests/test_ast_symbol_import_helper_usage.py",
25+
"tests/test_ast_tertiary_import_helper_import_boundary.py",
26+
"tests/test_ast_tertiary_import_helper_usage.py",
2527
"tests/test_ast_import_utils.py",
2628
"tests/test_ast_import_utils_module_import_boundary.py",
2729
)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from pathlib import Path
2+
3+
import pytest
4+
5+
from tests.ast_import_utils import (
6+
imports_imports_imports_imports_collect_function_sources,
7+
)
8+
from tests.test_ast_tertiary_import_helper_usage import (
9+
AST_TERTIARY_IMPORT_GUARD_MODULES,
10+
)
11+
12+
pytestmark = pytest.mark.architecture
13+
14+
15+
EXPECTED_EXTRA_IMPORTERS = ("tests/test_ast_import_utils.py",)
16+
17+
18+
def test_tertiary_ast_import_helper_imports_are_centralized():
19+
discovered_modules: list[str] = []
20+
for module_path in sorted(Path("tests").glob("test_*.py")):
21+
module_text = module_path.read_text(encoding="utf-8")
22+
if not imports_imports_imports_imports_collect_function_sources(module_text):
23+
continue
24+
discovered_modules.append(module_path.as_posix())
25+
26+
expected_modules = sorted([*AST_TERTIARY_IMPORT_GUARD_MODULES, *EXPECTED_EXTRA_IMPORTERS])
27+
assert discovered_modules == expected_modules
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from pathlib import Path
2+
3+
import pytest
4+
5+
from tests.ast_import_utils import (
6+
calls_symbol,
7+
imports_imports_imports_imports_collect_function_sources,
8+
)
9+
10+
pytestmark = pytest.mark.architecture
11+
12+
13+
AST_TERTIARY_IMPORT_GUARD_MODULES = (
14+
"tests/test_ast_import_helper_secondary_import_boundary.py",
15+
"tests/test_ast_secondary_import_helper_usage.py",
16+
)
17+
18+
19+
def test_ast_tertiary_import_guard_modules_reuse_shared_helper():
20+
violating_modules: list[str] = []
21+
for module_path in AST_TERTIARY_IMPORT_GUARD_MODULES:
22+
module_text = Path(module_path).read_text(encoding="utf-8")
23+
if not imports_imports_imports_imports_collect_function_sources(module_text):
24+
violating_modules.append(module_path)
25+
continue
26+
if not calls_symbol(module_text, "imports_imports_imports_collect_function_sources"):
27+
violating_modules.append(module_path)
28+
continue
29+
if "def _imports_imports_imports_collect_function_sources" in module_text:
30+
violating_modules.append(module_path)
31+
32+
assert violating_modules == []
33+
34+
35+
def test_ast_tertiary_import_guard_inventory_stays_in_sync():
36+
excluded_modules = {
37+
"tests/test_ast_import_utils.py",
38+
"tests/test_ast_tertiary_import_helper_import_boundary.py",
39+
"tests/test_ast_tertiary_import_helper_usage.py",
40+
}
41+
discovered_modules: list[str] = []
42+
for module_path in sorted(Path("tests").glob("test_*.py")):
43+
normalized_path = module_path.as_posix()
44+
if normalized_path in excluded_modules:
45+
continue
46+
module_text = module_path.read_text(encoding="utf-8")
47+
if not imports_imports_imports_imports_collect_function_sources(module_text):
48+
continue
49+
discovered_modules.append(normalized_path)
50+
51+
assert sorted(AST_TERTIARY_IMPORT_GUARD_MODULES) == discovered_modules

0 commit comments

Comments
 (0)