32 lines
1.5 KiB
Python
32 lines
1.5 KiB
Python
"""S04 只能持久化自己的结构定义,实例值由具名业务 owner 保存。"""
|
|
|
|
import ast
|
|
import re
|
|
from pathlib import Path
|
|
|
|
|
|
def test_元数据仅访问自有定义且无动态表名__a40020() -> None:
|
|
根 = Path(__file__).resolve().parents[2] / "src/muse/元数据"
|
|
数据表 = set()
|
|
for 文件 in 根.glob("*.py"):
|
|
树 = ast.parse(文件.read_text())
|
|
for 节点 in ast.walk(树):
|
|
if isinstance(节点, ast.ImportFrom) and 节点.level:
|
|
assert 节点.level == 1, f"{文件.name} 跨入其他模块内部"
|
|
if isinstance(节点, ast.ImportFrom) and 节点.module and not 节点.level:
|
|
assert not 节点.module.startswith("muse.") or 节点.module.startswith("muse.共享.")
|
|
if isinstance(节点, ast.Call) and getattr(节点.func, "attr", None) == "Identifier":
|
|
raise AssertionError(f"{文件.name} 不得接受动态表列名")
|
|
if isinstance(节点, ast.Constant) and isinstance(节点.value, str):
|
|
表 = re.findall(
|
|
r"\b(?:FROM|JOIN|INSERT\s+INTO|UPDATE(?!\s+SET))\s+([\w.]+)",
|
|
节点.value,
|
|
flags=re.I,
|
|
)
|
|
if 表:
|
|
assert 文件.name == "存储.py", f"{文件.name} 绕过 S04 存储归属"
|
|
assert all(t.startswith("metadata.") for t in 表), 表
|
|
数据表.update(表)
|
|
assert "metadata.schema_version" in 数据表
|
|
assert "metadata.schema_binding" in 数据表
|