Files
Jyotisha/tests/test_python_hygiene_budget.py
T

78 lines
3.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Budgets that only allow the silent-except and scripts-root counts to fall."""
from __future__ import annotations
import ast
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
SCRIPTS = ROOT / "scripts"
# Measured at the end of TASK-python-hygiene-20261013. New silent handlers
# must log or carry ``# noqa: BLE001`` with a reason. New research scripts
# belong in scripts/audit or scripts/research.
# 原值:0
# 新值:1
# 原因:产品 2026-10-18(issue #81 选 A)要求 classical_astrology.py 保持上游原文。
# 其中 scripts/classical_astrology.py:12558 是 except Exception: continue。本单不得改这个文件。
# 本地新写的静默处理仍不得出现;允许的命中只有这一处。
# 原值(2):1 处(只有 classical_astrology.py:12558)
# 新值(2):5 处,新增 4 处都在占星师上游原样文件 scripts/professional_parity_closure.py
# 原因(2):BUG-1698 产品 2026-11-07:完整运行占星师 skill,她 SKILL.md 点名的脚本按原样导入,不改她的原文
UPSTREAM_SILENT_EXCEPTS = [
"scripts/professional_parity_closure.py:100",
"scripts/professional_parity_closure.py:3557",
"scripts/professional_parity_closure.py:4505",
"scripts/professional_parity_closure.py:5003",
"scripts/classical_astrology.py:12558",
]
SILENT_EXCEPT_BUDGET = len(UPSTREAM_SILENT_EXCEPTS)
UPSTREAM_SILENT_EXCEPT = "scripts/classical_astrology.py:12558"
# 原值:448 → 452(issue #94:上游原样文件按上游路径放根目录;本地新写的文件仍不得增加)
# 新值:441
# 原因:issue #138 删除 11 个只被自己的测试引用的 closure 类台账脚本,预算同步下调
# 原值(2):441
# 新值(2):455
# 原因(2):产品 2026-11-07 完整运行占星师 skill:BUG-1698 按上游路径原样导入她 SKILL.md / 子 skill 点名的根目录脚本;
# BUG-1699 的 3 个旁路模块(shadbala_chesta_profiles、ashtakavarga_profiles、book_rule_layer)因 shadbala.py / ashtakavarga.py 冻结(ERR-110)只能另起文件
ROOT_PY_BUDGET = 455
def _silent_handlers() -> list[str]:
hits: list[str] = []
paths = list(SCRIPTS.glob("*.py")) + [ROOT / "mcp_server.py"]
for path in paths:
source = path.read_text(encoding="utf-8")
lines = source.splitlines()
tree = ast.parse(source)
for node in ast.walk(tree):
if not isinstance(node, ast.ExceptHandler):
continue
typ = node.type
broad = typ is None or (isinstance(typ, ast.Name) and typ.id in {"Exception", "BaseException"})
if not broad or len(node.body) != 1:
continue
stmt = node.body[0]
silent = isinstance(stmt, (ast.Pass, ast.Continue)) or (
isinstance(stmt, ast.Return)
and (stmt.value is None or (isinstance(stmt.value, ast.Constant) and stmt.value.value is None))
)
if not silent:
continue
segment = "\n".join(lines[node.lineno - 1: node.end_lineno])
if "noqa: BLE001" in segment:
continue
hits.append(f"{path.relative_to(ROOT).as_posix()}:{node.lineno}")
return hits
def test_silent_except_budget_does_not_grow() -> None:
hits = _silent_handlers()
assert sorted(hits) == sorted(UPSTREAM_SILENT_EXCEPTS)
assert len(hits) <= SILENT_EXCEPT_BUDGET, hits
def test_scripts_root_py_count_does_not_grow() -> None:
count = len(list(SCRIPTS.glob("*.py")))
assert count <= ROOT_PY_BUDGET, count