arm-scan-gateway/api/tests/golden_update.py
2026-10-07 00:47:42 +04:00

74 lines
2.9 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.

"""Golden нормализатора: сбор склейки реального ответа и запись эталонов (`make golden-update`).
Набор задания `<name>` — `<name>.json` + `<name>_*.json` из `../fixtures/ocr` (как у эмулятора); эталон —
`../fixtures/ocr/expected_normalize/<name>.json`. Запуск: `cd api && .venv/bin/python -m tests.golden_update`.
"""
import json
import sys
from pathlib import Path
from typing import Any
from src.gateway.hotfolder import AnswerFile
from src.gateway.merge import merge_answers
from src.normalizer import NormalizeOutcome, OcrNormalizer
from src.normalizer.rules import load_rules
API_DIR = Path(__file__).resolve().parents[1]
REAL_FIXTURES = API_DIR.parent.parent / "fixtures" / "ocr"
GOLDEN_DIR = REAL_FIXTURES / "expected_normalize"
JOB = "3f1c2b7a-0000-4000-8000-000000000001"
def golden_cases() -> list[str]:
"""Имена `<name>` без суффикса `_*`: `aep_3`, `aep_6`, … (по одному на набор)."""
names = sorted(p.name[: -len(".json")] for p in REAL_FIXTURES.glob("*.json") if p.is_file())
stems = {name for name in names if not any(name.startswith(f"{other}_") for other in names if other != name)}
return sorted(stems)
def real_set(name: str) -> dict[str, Any]:
files = []
for path in sorted(REAL_FIXTURES.glob(f"{name}*.json")):
base = path.name[: -len(".json")]
if base == name:
target = f"{JOB}.json"
elif base.startswith(f"{name}_"):
target = f"{JOB}_{base[len(name) + 1 :]}.json"
else:
continue
files.append(AnswerFile(target, path.read_bytes()))
return dict(merge_answers(JOB, files))
def outcome_to_json(outcome: NormalizeOutcome) -> dict[str, Any]:
return {
"status": outcome.status.value,
"warnings": list(outcome.warnings),
"metrics": outcome.metrics.model_dump(mode="json", exclude_none=True) if outcome.metrics else None,
"error": outcome.error.model_dump(mode="json", exclude_none=True) if outcome.error else None,
"documents": [doc.model_dump(mode="json", exclude_none=True) for doc in outcome.documents],
}
def main() -> int:
if not REAL_FIXTURES.is_dir():
print(f"нет каталога {REAL_FIXTURES}", file=sys.stderr)
return 2
rules = load_rules(API_DIR / "rules")
GOLDEN_DIR.mkdir(exist_ok=True)
for name in golden_cases():
payload = outcome_to_json(OcrNormalizer(rules).normalize(real_set(name)))
(GOLDEN_DIR / f"{name}.json").write_text(
json.dumps(payload, ensure_ascii=False, indent=2, sort_keys=True) + "\n", encoding="utf-8"
)
print(
f"{name}: {payload['status']}, документов {len(payload['documents'])}, "
f"предупреждений {len(payload['warnings'])}"
)
return 0
if __name__ == "__main__":
sys.exit(main())