59 lines
1.6 KiB
Python
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
|