"""Two rows of CLAUDE.md's canonical-patterns table, held in code. Both had drifted while the table said otherwise: seven `db.query(...)` calls stood beside the `select()` the table names, and four modules carried a private `_now` / `now_utc` helper (nine uses) where the table says inline `datetime.now(timezone.utc)`. A rule only prose holds drifts; ruff cannot ban a method call on an instance or a function's name, so this reads the AST of every app module. Pure-logic: no DB. """ import ast import pathlib import re import app APP = pathlib.Path(app.__file__).resolve().parent NOW_HELPER = re.compile(r"_?now(_\w+)?|now_utc|utcnow") def _modules() -> list[tuple[str, ast.Module]]: return [ (p.relative_to(APP.parent).as_posix(), ast.parse(p.read_text(encoding="utf-8"))) for p in sorted(APP.rglob("*.py")) ] def test_queries_use_select_not_the_legacy_query_api(): found = [ f"{path}:{node.lineno}" for path, tree in _modules() for node in ast.walk(tree) if isinstance(node, ast.Call) and isinstance(node.func, ast.Attribute) and node.func.attr == "query" ] assert found == [], "use db.execute(select(...)) — SQLAlchemy 2.0 — not db.query(...)" def test_the_current_time_is_inline_not_a_helper(): found = [ f"{path}:{node.lineno} {node.name}" for path, tree in _modules() for node in ast.walk(tree) if isinstance(node, ast.FunctionDef | ast.AsyncFunctionDef) and NOW_HELPER.fullmatch(node.name) ] assert found == [], "write datetime.now(timezone.utc) inline, not a now()/_now() helper" def test_the_scan_sees_the_app(): # a scan that reads nothing is green over nothing assert len(_modules()) > 50