refactor: establish standalone application boundary
This commit is contained in:
@@ -7,6 +7,27 @@ from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
FEATURES = ROOT / "backend" / "features"
|
||||
RETIRED_ROOT_MODULES = {
|
||||
"advanced_strategies",
|
||||
"alert_service",
|
||||
"app_config",
|
||||
"assistant_agent",
|
||||
"chart_data_provider",
|
||||
"heaven_agent",
|
||||
"heaven_engine",
|
||||
"ifind_client",
|
||||
"llm_strategy",
|
||||
"llm_stream",
|
||||
"market_insights",
|
||||
"mentor_agent",
|
||||
"realtime_aggregator",
|
||||
"screener",
|
||||
"security",
|
||||
"sentiment_engine",
|
||||
"strategy_tracking",
|
||||
"trade_journal",
|
||||
"tushare_client",
|
||||
}
|
||||
|
||||
|
||||
class FeatureBoundaryTests(unittest.TestCase):
|
||||
@@ -32,34 +53,7 @@ class FeatureBoundaryTests(unittest.TestCase):
|
||||
violations.append(f"{path.relative_to(ROOT)} -> {name}")
|
||||
self.assertEqual(violations, [])
|
||||
|
||||
def test_backend_uses_root_compatibility_modules_only_at_declared_boundaries(self) -> None:
|
||||
compatibility_modules = {
|
||||
"advanced_strategies",
|
||||
"alert_service",
|
||||
"api_access",
|
||||
"app_config",
|
||||
"assistant_agent",
|
||||
"chart_data_provider",
|
||||
"heaven_agent",
|
||||
"heaven_engine",
|
||||
"ifind_client",
|
||||
"llm_strategy",
|
||||
"llm_stream",
|
||||
"market_insights",
|
||||
"mentor_agent",
|
||||
"realtime_aggregator",
|
||||
"screener",
|
||||
"security",
|
||||
"sentiment_engine",
|
||||
"server",
|
||||
"strategy_tracking",
|
||||
"trade_journal",
|
||||
"tushare_client",
|
||||
}
|
||||
allowed = {
|
||||
"backend/application.py": {"api_access"},
|
||||
"backend/features/screener/repository.py": {"sentiment_engine"},
|
||||
}
|
||||
def test_backend_does_not_import_retired_root_modules(self) -> None:
|
||||
violations = []
|
||||
for path in (ROOT / "backend").rglob("*.py"):
|
||||
relative = path.relative_to(ROOT).as_posix()
|
||||
@@ -72,21 +66,15 @@ class FeatureBoundaryTests(unittest.TestCase):
|
||||
names = [node.module]
|
||||
for name in names:
|
||||
root_name = name.split(".")[0]
|
||||
if (
|
||||
root_name in compatibility_modules
|
||||
and root_name not in allowed.get(relative, set())
|
||||
):
|
||||
if root_name in RETIRED_ROOT_MODULES:
|
||||
violations.append(f"{relative} -> {name}")
|
||||
self.assertEqual(violations, [])
|
||||
|
||||
def test_legacy_service_modules_are_compatibility_exports_only(self) -> None:
|
||||
for filename in ("alert_service.py", "trade_journal.py", "strategy_tracking.py"):
|
||||
tree = ast.parse((ROOT / filename).read_text(encoding="utf-8"))
|
||||
definitions = [
|
||||
node for node in tree.body
|
||||
if isinstance(node, (ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef))
|
||||
]
|
||||
self.assertEqual(definitions, [], filename)
|
||||
def test_retired_root_modules_are_absent(self) -> None:
|
||||
present = sorted(
|
||||
name for name in RETIRED_ROOT_MODULES if (ROOT / f"{name}.py").exists()
|
||||
)
|
||||
self.assertEqual(present, [])
|
||||
|
||||
def test_each_migrated_feature_owns_one_application_service(self) -> None:
|
||||
expected = {
|
||||
|
||||
Reference in New Issue
Block a user