Newer
Older
TIASDataHub / src / tiasdata / kinds / review.py
"""所見の種類 `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