arm-core/api/src/contract/versions.py
Andrey Epifancev 17141c0a11 feat(contract): копии контракта обоих MAJOR, модели v2.0, приём конвертов 1.x/2.0, предупреждения файла структурами
Копии api/contracts/ побайтно равны docs/contracts/ (тест идентичности плана 0): схемы v2.0 основные, .v1 рядом,
examples/ — v2.0, examples/v1/ — v1.0. Модели result_v2.py и RecognitionResultMessageV2, versions.py выбирает модель
по MAJOR. Приём конвертов принимает оба MAJOR; metrics.warnings в recognition_job пишется структурами (строки 1.x
оборачиваются в LEGACY_WARNING). JobBrief.warnings отдаёт структуры, мусор пропускается, БД не переписывается.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BJKMLHdxMwSUeYcdkwqX4W
2026-10-18 19:26:50 +04:00

52 lines
2.1 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.

"""Выбор модели по MAJOR `schema_version` на окне перехода v1 → v2 (ядро принимает оба MAJOR).
`schema_version` — `MAJOR.MINOR`. Известны MAJOR 1 и 2; иной MAJOR, неверный формат или отсутствие поля —
`pydantic.ValidationError` (разбор отдан модели v1, чей шаблон `^1\\.\\d+$` такое не принимает).
"""
import json
import re
from typing import Any
from src.contract.message import RecognitionResultMessage, RecognitionResultMessageV2
from src.contract.result import RecognitionResult
from src.contract.result_v2 import RecognitionResultV2
_VERSION = re.compile(r"(\d+)\.\d+", re.ASCII)
MAJOR_V2 = 2
__all__ = ["major", "parse_message", "parse_result"]
def major(schema_version: str) -> int:
"""MAJOR из `MAJOR.MINOR`; иная запись — `ValueError`."""
match = _VERSION.fullmatch(schema_version)
if match is None:
raise ValueError(f"schema_version {schema_version!r}: ожидается MAJOR.MINOR")
return int(match.group(1))
def _is_v2(data: Any) -> bool:
version = data.get("schema_version") if isinstance(data, dict) else None
if not isinstance(version, str):
return False
try:
return major(version) == MAJOR_V2
except ValueError:
return False
def parse_message(data: dict[str, Any]) -> RecognitionResultMessage | RecognitionResultMessageV2:
"""Конверт `recognition-result-message`: MAJOR 1 → модель v1, MAJOR 2 → модель v2, иное — `ValidationError`."""
if _is_v2(data):
return RecognitionResultMessageV2.model_validate(data)
return RecognitionResultMessage.model_validate(data)
def parse_result(content: bytes) -> RecognitionResult | RecognitionResultV2:
"""Файл результата: те же правила MAJOR; нечитаемый JSON — `ValueError` (`json.JSONDecodeError`)."""
data = json.loads(content)
if _is_v2(data):
return RecognitionResultV2.model_validate(data)
return RecognitionResult.model_validate(data)