test(statements): помощники golden — ocr_result, все документы файла в map_golden_snapshot
Добавлены: - Константы GOLDEN_STATEMENTS и OCR_EXPECTED в fixtures_helpers - Функция ocr_result для создания RecognitionResult из эталона нормализатора - Тест test_ocr_result_wraps_normalizer_golden, проверяющий порядок документов Изменены: - map_golden_snapshot теперь принимает параметр result_builder для переопределения функции создания RecognitionResult (по умолчанию golden_result) - Документы сортируются по (document_type, osv_account_code) вместо только osv_account_code Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
This commit is contained in:
parent
3a72702c3d
commit
29f516db3c
@ -3,6 +3,7 @@
|
||||
import json
|
||||
import os
|
||||
import uuid
|
||||
from collections.abc import Callable
|
||||
from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
@ -16,6 +17,8 @@ if TYPE_CHECKING:
|
||||
from src.models.files import Document
|
||||
|
||||
FIXTURES_ENV = "ARM_KA_FIXTURES"
|
||||
GOLDEN_STATEMENTS = Path("golden") / "expected_statement_parse"
|
||||
OCR_EXPECTED = Path("ocr") / "expected_normalize"
|
||||
|
||||
|
||||
def resolve_fixtures_dir() -> Path:
|
||||
@ -40,6 +43,28 @@ def fixtures_skip_reason() -> str | None:
|
||||
)
|
||||
|
||||
|
||||
def ocr_result(path: Path, *, job_id: uuid.UUID, file_id: uuid.UUID) -> "RecognitionResult":
|
||||
"""Эталон нормализатора scan-gateway (`ocr/expected_normalize/<name>.json`)
|
||||
как `RecognitionResult` контракта v1.2.
|
||||
"""
|
||||
from src.contract.result import RecognitionResult # noqa: PLC0415 - цикл с conftest
|
||||
|
||||
data = json.loads(path.read_text("utf-8"))
|
||||
payload: dict[str, object] = {
|
||||
"schema_version": "1.2",
|
||||
"job_id": str(job_id),
|
||||
"file_id": str(file_id),
|
||||
"service": {"name": "scan-gateway", "version": "golden"},
|
||||
"status": data["status"],
|
||||
"documents": data["documents"],
|
||||
}
|
||||
if data.get("error"):
|
||||
payload["error"] = data["error"]
|
||||
if data.get("metrics"):
|
||||
payload["metrics"] = data["metrics"]
|
||||
return RecognitionResult.model_validate(payload)
|
||||
|
||||
|
||||
def golden_result(path: Path, *, job_id: uuid.UUID, file_id: uuid.UUID) -> "RecognitionResult":
|
||||
"""Golden-снимок парсера как `RecognitionResult`: подставляет `job_id`/`file_id` и версию сервиса."""
|
||||
from src.contract.result import RecognitionResult # noqa: PLC0415 - тяжёлые импорты лениво: цикл с conftest
|
||||
@ -50,13 +75,19 @@ def golden_result(path: Path, *, job_id: uuid.UUID, file_id: uuid.UUID) -> "Reco
|
||||
|
||||
|
||||
async def map_golden_snapshot(
|
||||
session: AsyncSession, *, entity: "LegalEntity", path: Path, uploaded_by: uuid.UUID | None
|
||||
session: AsyncSession,
|
||||
*,
|
||||
entity: "LegalEntity",
|
||||
path: Path,
|
||||
uploaded_by: uuid.UUID | None,
|
||||
result_builder: Callable[..., "RecognitionResult"] | None = None,
|
||||
) -> "list[Document]":
|
||||
"""Golden-снимок `path` → файл ЮЛ `entity` и его документы ОСВ в БД теста (`flush`, без commit).
|
||||
"""Golden-снимок `path` → файл ЮЛ `entity` и его документы в БД теста (`flush`, без commit).
|
||||
|
||||
Как маппер: файл `PROCESSING` с текущим заданием `done`, затем боевой `map_file` с планом счетов seed и настоящим
|
||||
`CounterpartyIndex` (справочник читается на момент вызова — ЮЛ и алиасы должны быть созданы до маппинга).
|
||||
Возвращает документы файла (после автозамены прежних версий — только документы этого файла).
|
||||
Как маппер: файл `PROCESSING` с текущим заданием `done`, затем боевой `map_file` с планом счетов seed и
|
||||
настоящим `CounterpartyIndex` (справочник читается на момент вызова — ЮЛ и алиасы должны быть созданы
|
||||
до маппинга). Возвращает документы файла отсортированные по (document_type, osv_account_code).
|
||||
`result_builder` — функция создания RecognitionResult (по умолчанию golden_result).
|
||||
"""
|
||||
# ленивые импорты: `conftest` импортирует этот модуль раньше `tests.factories` (цикл)
|
||||
from src.models.accounting import ChartOfAccount # noqa: PLC0415
|
||||
@ -78,9 +109,12 @@ async def map_golden_snapshot(
|
||||
code: account_id for code, account_id in await session.execute(select(ChartOfAccount.code, ChartOfAccount.id))
|
||||
}
|
||||
index = await CounterpartyIndex.load(session)
|
||||
result = golden_result(path, job_id=job.id, file_id=file.id)
|
||||
builder = result_builder or golden_result
|
||||
result = builder(path, job_id=job.id, file_id=file.id)
|
||||
await map_file(session, job=job, file=file, result=result, chart=chart, index=index, now=datetime.now(UTC))
|
||||
documents = await session.execute(
|
||||
select(Document).where(Document.stored_file_id == file.id).order_by(Document.osv_account_code)
|
||||
select(Document)
|
||||
.where(Document.stored_file_id == file.id)
|
||||
.order_by(Document.document_type, Document.osv_account_code)
|
||||
)
|
||||
return list(documents.scalars())
|
||||
|
||||
@ -1,10 +1,17 @@
|
||||
"""Маркер `fixtures`: путь к реальным данным и пропуск с причиной (spec quality-checks, «Фикстуры … опциональны»)."""
|
||||
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from tests.fixtures_helpers import FIXTURES_ENV, fixtures_skip_reason, resolve_fixtures_dir
|
||||
from tests.fixtures_helpers import (
|
||||
FIXTURES_ENV,
|
||||
OCR_EXPECTED,
|
||||
fixtures_skip_reason,
|
||||
ocr_result,
|
||||
resolve_fixtures_dir,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.fixtures
|
||||
@ -34,3 +41,15 @@ def test_skip_reason_names_variable_and_path(monkeypatch: pytest.MonkeyPatch, tm
|
||||
assert reason is not None
|
||||
assert "ARM_KA_FIXTURES недоступен" in reason
|
||||
assert str(missing) in reason
|
||||
|
||||
|
||||
@pytest.mark.fixtures
|
||||
def test_ocr_result_wraps_normalizer_golden(fixtures_dir: Path) -> None:
|
||||
"""ocr_result читает эталон нормализатора и создаёт RecognitionResult
|
||||
с правильным порядком документов.
|
||||
"""
|
||||
job_id, file_id = uuid.uuid4(), uuid.uuid4()
|
||||
result = ocr_result(fixtures_dir / OCR_EXPECTED / "aep_6.json", job_id=job_id, file_id=file_id)
|
||||
assert result.job_id == job_id and result.file_id == file_id
|
||||
assert result.service.name == "scan-gateway"
|
||||
assert [doc.document_type for doc in result.documents] == ["BALANCE", "INCOME"]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user