"""所見の種類 `review`(要確認の印)の値の型(SPEC_02「kinds」).
取り込み元のデータに,基盤では正解を決められない問題(同じ写真の重複・患者 ID やラベルの
食い違い等)があるものに付ける.取り込みでは要確認リスト(`reviews/<取り込み元の名前>.toml`)
から付ける(SPEC_03「要確認リスト」).
"""
from datetime import date
from pydantic import BaseModel, ConfigDict, Field, field_validator
# 所見の種類名(kinds 表の行は catalog/0002_review_kind.sql)
REVIEW_KIND = "review"
_DATE_PATTERN = r"^[0-9]{4}-[0-9]{2}-[0-9]{2}$"
class Review(BaseModel):
"""要確認の印の値(`{"reason": ..., "resolve": ..., "since": ..., "numbers": [...]}`).
Attributes:
reason: 要確認にした理由.
resolve: 確かめる方法.
since: 要確認にした日(`YYYY-MM-DD`).
numbers: 取り込み元での番号(昇順・重複なし・1 以上).同じ中身のファイルが複数の番号に
あったときは,そのすべての番号.
"""
# 未知のキーは拒否する(綴りの誤りで値が黙って欠けるのを防ぐ)
model_config = ConfigDict(extra="forbid", frozen=True, strict=True)
reason: str = Field(min_length=1)
resolve: str = Field(min_length=1)
# JSON から読んだ値と同じ形で比べられるように,日付は文字列のまま持つ
since: str = Field(pattern=_DATE_PATTERN)
numbers: list[int] = Field(min_length=1)
@field_validator("since")
@classmethod
def _valid_date(cls, value: str) -> str:
date.fromisoformat(value)
return value
@field_validator("numbers")
@classmethod
def _sorted_unique_positive(cls, value: list[int]) -> list[int]:
# 同じ印が常に同じ JSON になるように,並びを固定する
if any(number < 1 for number in value):
raise ValueError("numbers は 1 以上")
if value != sorted(set(value)):
raise ValueError("numbers は昇順・重複なしで並べる")
return value