Files
next-tjwater-server/app/domain/schemas/shared.py
T

59 lines
1.6 KiB
Python

"""Small strict value types shared by independent backend features."""
from datetime import datetime
from typing import Annotated, Literal
from uuid import UUID
from pydantic import BaseModel, BeforeValidator, ConfigDict, Field, StringConstraints, model_validator
NonEmptyStr = Annotated[str, StringConstraints(strip_whitespace=True, min_length=1)]
StrictBool = Annotated[bool, Field(strict=True)]
PositiveInt = Annotated[int, Field(strict=True, ge=1)]
NonNegativeInt = Annotated[int, Field(strict=True, ge=0)]
def _datetime_wire_value(value: object) -> datetime | str:
if not isinstance(value, (datetime, str)):
raise ValueError("datetime input must be an RFC3339 string or datetime instance")
return value
WireDateTime = Annotated[datetime, BeforeValidator(_datetime_wire_value)]
class StrictModel(BaseModel):
model_config = ConfigDict(extra="forbid", allow_inf_nan=False)
ObjectType = Literal[
"analysis_task",
"goal",
"state_snapshot",
"action_contract",
"validation",
"run",
"outcome",
"evidence",
"artifact",
"operation",
]
class ObjectRef(StrictModel):
object_type: ObjectType
object_id: UUID
revision: PositiveInt
class TimeRange(StrictModel):
start: WireDateTime
end: WireDateTime
@model_validator(mode="after")
def validate_range(self) -> "TimeRange":
if self.start.tzinfo is None or self.end.tzinfo is None:
raise ValueError("timestamps must include a timezone")
if self.start >= self.end:
raise ValueError("start must be before end")
return self