Skip to content

Commit 8bca886

Browse files
authored
test(benchmarks): isolate synthetic module loading (#746)
1 parent bf44e7a commit 8bca886

3 files changed

Lines changed: 123 additions & 20 deletions

File tree

benchmarks/validation/test_benchmark_planner.py

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import sys
1010
from importlib.machinery import SourceFileLoader
1111
from pathlib import Path
12-
from types import SimpleNamespace
12+
from types import ModuleType, SimpleNamespace
1313

1414
import pytest
1515

@@ -18,13 +18,21 @@
1818
PATH_POLICY_PATH = ROOT / ".github" / "scripts" / "_ci_paths.py"
1919
VALIDATION_PLAN_PATH = ROOT / "benchmarks" / "tooling" / "validation_plan.py"
2020
VALIDATOR_PATH = ROOT / ".github" / "scripts" / "validate-benchmark-plan"
21-
_SPEC = importlib.util.spec_from_loader(
22-
"benchmark_planner", SourceFileLoader("benchmark_planner", str(PLANNER_PATH))
23-
)
24-
assert _SPEC is not None and _SPEC.loader is not None
25-
planner = importlib.util.module_from_spec(_SPEC)
26-
sys.modules["benchmark_planner"] = planner
27-
_SPEC.loader.exec_module(planner)
21+
22+
23+
def _load_script(module_name: str, path: Path) -> ModuleType:
24+
spec = importlib.util.spec_from_loader(
25+
module_name, SourceFileLoader(module_name, str(path))
26+
)
27+
assert spec is not None and spec.loader is not None
28+
module = importlib.util.module_from_spec(spec)
29+
with pytest.MonkeyPatch.context() as module_state:
30+
module_state.setitem(sys.modules, module_name, module)
31+
spec.loader.exec_module(module)
32+
return module
33+
34+
35+
planner = _load_script("benchmark_planner", PLANNER_PATH)
2836

2937

3038
@pytest.fixture(autouse=True)
@@ -38,6 +46,34 @@ def stable_digests(monkeypatch: pytest.MonkeyPatch) -> None:
3846
)
3947

4048

49+
@pytest.mark.parametrize("preserve_existing", [False, True])
50+
def test_load_script_scopes_sys_modules_registration(
51+
tmp_path: Path,
52+
monkeypatch: pytest.MonkeyPatch,
53+
*,
54+
preserve_existing: bool,
55+
) -> None:
56+
module_name = "_benchmark_planner_module_probe"
57+
source = tmp_path / "module_probe.py"
58+
source.write_text(
59+
"import sys\nregistered_while_loading = sys.modules[__name__]\n",
60+
encoding="utf-8",
61+
)
62+
sentinel = ModuleType("sentinel")
63+
if preserve_existing:
64+
monkeypatch.setitem(sys.modules, module_name, sentinel)
65+
else:
66+
monkeypatch.delitem(sys.modules, module_name, raising=False)
67+
68+
loaded = _load_script(module_name, source)
69+
70+
assert vars(loaded)["registered_while_loading"] is loaded
71+
if preserve_existing:
72+
assert sys.modules[module_name] is sentinel
73+
else:
74+
assert module_name not in sys.modules
75+
76+
4177
def _matrix(result: dict[str, str]) -> list[dict[str, object]]:
4278
return json.loads(result["benchmark-oracle-matrix"])
4379

benchmarks/validation/test_harbor_task_workflow.py

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,56 @@
77
import sys
88
from importlib.machinery import SourceFileLoader
99
from pathlib import Path
10+
from types import ModuleType
1011
from typing import Any
1112

1213
import pytest
1314

1415
ROOT = Path(__file__).resolve().parents[2]
1516
TOOL_PATH = ROOT / "tools" / "harbor_task_workflow.py"
16-
_SPEC = importlib.util.spec_from_loader(
17-
"harbor_task_workflow", SourceFileLoader("harbor_task_workflow", str(TOOL_PATH))
18-
)
19-
assert _SPEC is not None and _SPEC.loader is not None
20-
workflow = importlib.util.module_from_spec(_SPEC)
21-
sys.modules[_SPEC.name] = workflow
22-
_SPEC.loader.exec_module(workflow)
17+
18+
19+
def _load_script(module_name: str, path: Path) -> ModuleType:
20+
spec = importlib.util.spec_from_loader(
21+
module_name, SourceFileLoader(module_name, str(path))
22+
)
23+
assert spec is not None and spec.loader is not None
24+
module = importlib.util.module_from_spec(spec)
25+
with pytest.MonkeyPatch.context() as module_state:
26+
module_state.setitem(sys.modules, module_name, module)
27+
spec.loader.exec_module(module)
28+
return module
29+
30+
31+
workflow = _load_script("harbor_task_workflow", TOOL_PATH)
32+
33+
34+
@pytest.mark.parametrize("preserve_existing", [False, True])
35+
def test_load_script_scopes_sys_modules_registration(
36+
tmp_path: Path,
37+
monkeypatch: pytest.MonkeyPatch,
38+
*,
39+
preserve_existing: bool,
40+
) -> None:
41+
module_name = "_harbor_task_workflow_module_probe"
42+
source = tmp_path / "module_probe.py"
43+
source.write_text(
44+
"import sys\nregistered_while_loading = sys.modules[__name__]\n",
45+
encoding="utf-8",
46+
)
47+
sentinel = ModuleType("sentinel")
48+
if preserve_existing:
49+
monkeypatch.setitem(sys.modules, module_name, sentinel)
50+
else:
51+
monkeypatch.delitem(sys.modules, module_name, raising=False)
52+
53+
loaded = _load_script(module_name, source)
54+
55+
assert vars(loaded)["registered_while_loading"] is loaded
56+
if preserve_existing:
57+
assert sys.modules[module_name] is sentinel
58+
else:
59+
assert module_name not in sys.modules
2360

2461

2562
def test_resolve_selection_uses_planner_owned_host_matrix() -> None:

benchmarks/validation/test_verifier_support_schema.py

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import json
77
import sys
88
from pathlib import Path
9+
from types import ModuleType
910

1011
import pytest
1112

@@ -18,16 +19,45 @@
1819
)
1920

2021

21-
def _load_module():
22-
spec = importlib.util.spec_from_file_location("_vs_under_test", _TEMPLATE)
22+
def _load_module(module_name: str, path: Path) -> ModuleType:
23+
spec = importlib.util.spec_from_file_location(module_name, path)
2324
assert spec is not None and spec.loader is not None
2425
module = importlib.util.module_from_spec(spec)
25-
sys.modules["_vs_under_test"] = module
26-
spec.loader.exec_module(module)
26+
with pytest.MonkeyPatch.context() as module_state:
27+
module_state.setitem(sys.modules, module_name, module)
28+
spec.loader.exec_module(module)
2729
return module
2830

2931

30-
_VS = _load_module()
32+
_VS = _load_module("_vs_under_test", _TEMPLATE)
33+
34+
35+
@pytest.mark.parametrize("preserve_existing", [False, True])
36+
def test_load_module_scopes_sys_modules_registration(
37+
tmp_path: Path,
38+
monkeypatch: pytest.MonkeyPatch,
39+
*,
40+
preserve_existing: bool,
41+
) -> None:
42+
module_name = "_verifier_support_schema_module_probe"
43+
source = tmp_path / "module_probe.py"
44+
source.write_text(
45+
"import sys\nregistered_while_loading = sys.modules[__name__]\n",
46+
encoding="utf-8",
47+
)
48+
sentinel = ModuleType("sentinel")
49+
if preserve_existing:
50+
monkeypatch.setitem(sys.modules, module_name, sentinel)
51+
else:
52+
monkeypatch.delitem(sys.modules, module_name, raising=False)
53+
54+
loaded = _load_module(module_name, source)
55+
56+
assert vars(loaded)["registered_while_loading"] is loaded
57+
if preserve_existing:
58+
assert sys.modules[module_name] is sentinel
59+
else:
60+
assert module_name not in sys.modules
3161

3262

3363
@pytest.fixture

0 commit comments

Comments
 (0)