65 lines
2.1 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
import re
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
ALLOW_PREFIXES = (
ROOT / "devplacepy" / "database",
ROOT / "devplacepy" / "db_client.py",
ROOT / "devplacepy_services" / "database",
ROOT / "scripts" / "migrate_db_imports.py",
ROOT / "scripts" / "check_database_imports.py",
)
PATTERNS = [
re.compile(r"from devplacepy\.database(?:\.[a-z_]+)? import"),
re.compile(r"import devplacepy\.database\b"),
]
# Only flagged outside tests/: unit tests may legitimately use `local_db` /
# `from devplacepy import database` directly (Section 13.4). Source code must
# always go through `devplacepy.db_client` so the remote broker patch applies.
SOURCE_ONLY_PATTERNS = [
re.compile(r"from devplacepy import(?:\s+\w+,)*\s+database\b"),
]
def allowed(path: Path) -> bool:
for prefix in ALLOW_PREFIXES:
if path == prefix or str(path).startswith(str(prefix) + "/"):
return True
return False
def main() -> int:
errors: list[str] = []
for pattern in ("devplacepy/**/*.py", "devplacepy_services/**/*.py", "tests/**/*.py"):
is_source = not pattern.startswith("tests/")
for path in ROOT.glob(pattern):
if not path.is_file() or allowed(path):
continue
try:
text = path.read_text(encoding="utf-8", errors="ignore")
except OSError:
continue
active_patterns = PATTERNS + SOURCE_ONLY_PATTERNS if is_source else PATTERNS
for lineno, line in enumerate(text.splitlines(), 1):
for rx in active_patterns:
if rx.search(line):
errors.append(f"{path.relative_to(ROOT)}:{lineno}: {line.strip()}")
break
if errors:
print("FORBIDDEN database imports (use devplacepy.db_client):")
for line in sorted(errors)[:80]:
print(f" {line}")
if len(errors) > 80:
print(f" ... and {len(errors) - 80} more")
return 1
print("check_database_imports: ok")
return 0
if __name__ == "__main__":
raise SystemExit(main())