|
5 | 5 |
|
6 | 6 | from __future__ import annotations |
7 | 7 |
|
| 8 | +import importlib |
8 | 9 | import sys |
9 | | -import types |
10 | | -from types import SimpleNamespace |
| 10 | + |
| 11 | +import pytest |
11 | 12 |
|
12 | 13 | import skillspector |
13 | 14 | from skillspector.graph_proxy import LazyGraph |
14 | 15 | from skillspector.graph_proxy import graph as lazy_graph |
15 | 16 |
|
16 | 17 |
|
17 | | -def test_package_graph_export_survives_submodule_load() -> None: |
18 | | - """Re-import after lazy load still exposes an invokable package export. |
| 18 | +@pytest.fixture |
| 19 | +def _graph_import_state(monkeypatch: pytest.MonkeyPatch) -> None: |
| 20 | + """Snapshot and restore all shared graph import state. |
19 | 21 |
|
20 | | - Closes rng1995 review on #436: importing the graph submodule must not leave |
21 | | - later `skillspector.graph` consumers with a non-invokable module object. |
| 22 | + Closes rng1995/yashrajp22 reviews on #436: graph import-order tests must |
| 23 | + exercise the real factory/import paths without leaking ``sys.modules`` |
| 24 | + entries, the package ``graph`` attribute, or ``LazyGraph`` compiled |
| 25 | + state into other tests. |
22 | 26 | """ |
23 | | - compiled = SimpleNamespace(invoke=lambda state: state) |
24 | | - submodule = types.ModuleType("skillspector.graph") |
25 | | - submodule.graph = compiled # type: ignore[attr-defined] |
26 | | - |
27 | | - # CLI tests monkeypatch ``skillspector.cli.graph.invoke``; undo restores the |
28 | | - # real bound method on this shared singleton and bypasses ``__getattr__``. |
| 27 | + monkeypatch.delitem(sys.modules, "skillspector.graph", raising=False) |
| 28 | + monkeypatch.delitem(sys.modules, "skillspector.mcp_server", raising=False) |
| 29 | + monkeypatch.setattr(skillspector, "graph", lazy_graph, raising=False) |
| 30 | + monkeypatch.setattr(lazy_graph, "_compiled", None, raising=False) |
| 31 | + # A leaked instance attribute would shadow __getattr__ delegation; |
| 32 | + # drop it so the proxy is pristine (nothing to restore: the pristine |
| 33 | + # singleton carries no such attribute). |
29 | 34 | lazy_graph.__dict__.pop("invoke", None) |
30 | | - lazy_graph._compiled = compiled |
31 | | - skillspector.graph = lazy_graph |
32 | 35 |
|
33 | | - # Importing the compiled submodule replaces the package export with the module. |
34 | | - skillspector.graph = submodule |
35 | | - sys.modules["skillspector.graph"] = submodule |
36 | 36 |
|
37 | | - # graph_proxy._get_compiled restores the documented lazy export afterward. |
38 | | - skillspector.graph = lazy_graph |
39 | | - sys.modules["skillspector"].graph = lazy_graph |
| 37 | +def _assert_graph_export_invokable() -> None: |
| 38 | + exported = skillspector.graph |
| 39 | + for name in ("invoke", "ainvoke", "stream"): |
| 40 | + assert callable(getattr(exported, name)), ( |
| 41 | + f"skillspector.graph lost {name} after import-order change" |
| 42 | + ) |
| 43 | + |
| 44 | + |
| 45 | +def test_create_graph_first_preserves_lazy_export( |
| 46 | + _graph_import_state: None, |
| 47 | +) -> None: |
| 48 | + """rng1995 #436: create_graph() as first access keeps the lazy export.""" |
| 49 | + skillspector.create_graph() |
| 50 | + assert isinstance(skillspector.graph, LazyGraph) |
| 51 | + _assert_graph_export_invokable() |
| 52 | + |
40 | 53 |
|
| 54 | +def test_mcp_import_first_preserves_lazy_export(_graph_import_state: None) -> None: |
| 55 | + """yashrajp22 #436: importing MCP first keeps the lazy export.""" |
| 56 | + importlib.import_module("skillspector.mcp_server") |
41 | 57 | assert isinstance(skillspector.graph, LazyGraph) |
42 | | - assert lazy_graph.invoke({"ok": True}) == {"ok": True} |
43 | | - assert skillspector.graph.invoke({"again": 1}) == {"again": 1} |
| 58 | + _assert_graph_export_invokable() |
| 59 | + |
| 60 | + |
| 61 | +def test_direct_submodule_import_keeps_graph_invokable( |
| 62 | + _graph_import_state: None, |
| 63 | +) -> None: |
| 64 | + """yashrajp22 #436: direct submodule import keeps skillspector.graph invokable.""" |
| 65 | + importlib.import_module("skillspector.graph") |
| 66 | + _assert_graph_export_invokable() |
0 commit comments