"""Shared Pydantic field helpers for workplan / workstream compatibility.""" from __future__ import annotations import uuid from pydantic import AliasChoices, Field, computed_field, model_validator def workplan_id_field(*, default: uuid.UUID | None = None) -> uuid.UUID | None: return Field( default=default, validation_alias=AliasChoices("workplan_id", "workstream_id"), ) class WorkplanIdCompatMixin: """Accept ``workplan_id`` or legacy ``workstream_id`` on input; emit both on output.""" workplan_id: uuid.UUID = workplan_id_field() @computed_field # type: ignore[prop-decorator] @property def workstream_id(self) -> uuid.UUID: return self.workplan_id class WorkplanIdCreateMixin: workplan_id: uuid.UUID | None = workplan_id_field(default=None) @model_validator(mode="after") def _require_workplan_id(self): if self.workplan_id is None: raise ValueError("workplan_id is required") return self class OptionalWorkplanIdCompatMixin: workplan_id: uuid.UUID | None = workplan_id_field(default=None) @computed_field # type: ignore[prop-decorator] @property def workstream_id(self) -> uuid.UUID | None: return self.workplan_id