64 lines
2.4 KiB
Python
64 lines
2.4 KiB
Python
"""Конверт сообщения на `recognition.result`: `recognition-result-message.schema.json` v1.0.
|
||
|
||
`processing` — ack «взял в работу» (до чтения файла из S3); `done | needs_check | error` — итог.
|
||
Условная обязательность — буквально из `allOf` схемы: для `done | needs_check` обязательны `result_s3` и
|
||
`result_schema_version`; для `error` — `error`. Других правил нет (например, `error` при `done` схема не запрещает).
|
||
"""
|
||
|
||
from enum import StrEnum
|
||
from typing import Annotated, Self
|
||
|
||
from pydantic import Field, model_validator
|
||
|
||
from src.contract.common import (
|
||
ContractModel,
|
||
ContractUUID,
|
||
LaxErrorCode,
|
||
Metrics,
|
||
OptionalNotNull,
|
||
ResultSchemaVersion,
|
||
S3Ref,
|
||
SchemaVersion,
|
||
ServiceInfo,
|
||
)
|
||
|
||
|
||
class MessageStatus(StrEnum):
|
||
PROCESSING = "processing"
|
||
DONE = "done"
|
||
NEEDS_CHECK = "needs_check"
|
||
ERROR = "error"
|
||
|
||
|
||
LaxMessageStatus = Annotated[MessageStatus, Field(strict=False)]
|
||
|
||
|
||
class MessageError(ContractModel):
|
||
"""`error {code, message}` конверта: оба поля обязательны."""
|
||
|
||
code: LaxErrorCode
|
||
message: str
|
||
|
||
|
||
class RecognitionResultMessage(ContractModel):
|
||
schema_version: SchemaVersion
|
||
job_id: ContractUUID # recognition_job.id
|
||
file_id: ContractUUID # stored_file.id
|
||
status: LaxMessageStatus
|
||
service: ServiceInfo
|
||
result_s3: OptionalNotNull[S3Ref] = None # results/{file_id}/{job_id}/result.json
|
||
result_schema_version: OptionalNotNull[ResultSchemaVersion] = None # schema_version файла результата
|
||
error: OptionalNotNull[MessageError] = None
|
||
raw_s3_key: str | None = None # scan-gateway: raw/{job_id}.json; в БД не регистрируется
|
||
metrics: OptionalNotNull[Metrics] = None
|
||
|
||
@model_validator(mode="after")
|
||
def _check_status_requirements(self) -> Self:
|
||
if self.status in (MessageStatus.DONE, MessageStatus.NEEDS_CHECK):
|
||
missing = [name for name in ("result_s3", "result_schema_version") if getattr(self, name) is None]
|
||
if missing:
|
||
raise ValueError(f"при status = {self.status.value} обязательны поля: {', '.join(missing)}")
|
||
elif self.status is MessageStatus.ERROR and self.error is None:
|
||
raise ValueError("при status = error обязательно поле error")
|
||
return self
|