35 lines
1.1 KiB
Python
35 lines
1.1 KiB
Python
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import ast
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
|
||
|
|
MAX_CLASS_LINES = 800
|
||
|
|
SERVER_SOURCE_ROOT = Path(__file__).resolve().parents[1] / "src" / "app"
|
||
|
|
|
||
|
|
|
||
|
|
def iter_python_source_files(root: Path) -> list[Path]:
|
||
|
|
ignored_parts = {"__pycache__", "x_financial_server.egg-info"}
|
||
|
|
return sorted(
|
||
|
|
path
|
||
|
|
for path in root.rglob("*.py")
|
||
|
|
if not ignored_parts.intersection(path.parts)
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
def test_python_classes_do_not_exceed_800_lines() -> None:
|
||
|
|
oversized_classes: list[str] = []
|
||
|
|
|
||
|
|
for path in iter_python_source_files(SERVER_SOURCE_ROOT):
|
||
|
|
tree = ast.parse(path.read_text(encoding="utf-8"))
|
||
|
|
for node in ast.walk(tree):
|
||
|
|
if isinstance(node, ast.ClassDef) and node.end_lineno is not None:
|
||
|
|
line_count = node.end_lineno - node.lineno + 1
|
||
|
|
if line_count > MAX_CLASS_LINES:
|
||
|
|
relative_path = path.relative_to(SERVER_SOURCE_ROOT.parents[1])
|
||
|
|
oversized_classes.append(
|
||
|
|
f"{relative_path}:{node.lineno} {node.name} ({line_count} lines)"
|
||
|
|
)
|
||
|
|
|
||
|
|
assert oversized_classes == []
|