from datetime import date, datetime from typing import Optional from pydantic import BaseModel, ConfigDict, field_validator def _validate_half_hours(value: float) -> float: if value <= 0: raise ValueError("hours must be greater than 0") scaled = value * 2 if abs(scaled - round(scaled)) > 1e-6: raise ValueError("hours must be in 0.5 increments") return value class ProjectBase(BaseModel): name: str description: Optional[str] = None class ProjectCreate(ProjectBase): pass class ProjectUpdate(BaseModel): name: Optional[str] = None description: Optional[str] = None class ProjectRead(ProjectBase): id: int created_at: datetime model_config = ConfigDict(from_attributes=True) class WorkLogBase(BaseModel): project_id: int date: date hours: float description: str _validate_hours = field_validator("hours")(_validate_half_hours) class WorkLogCreate(WorkLogBase): pass class WorkLogUpdate(BaseModel): project_id: Optional[int] = None date: Optional[date] = None hours: Optional[float] = None description: Optional[str] = None @field_validator("hours") @classmethod def validate_hours(cls, value: Optional[float]) -> Optional[float]: if value is None: return value return _validate_half_hours(value) class WorkLogRead(WorkLogBase): id: int created_at: datetime model_config = ConfigDict(from_attributes=True)