spoolman.py 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546
  1. from typing import Annotated
  2. from pydantic import AfterValidator, BaseModel, Field, model_validator
  3. def _a_slot_ams_id(ams_id: int) -> int:
  4. """The ams_ids spoolman_slot_assignments' CHECK admits: AMS units 0-7,
  5. AMS-HT 128-191, the external slot 255. Checked on the request, so a write
  6. to Spoolman that goes with the slot row is never made for a row the
  7. database then refuses (SSA-9)."""
  8. if 0 <= ams_id <= 7 or 128 <= ams_id <= 191 or ams_id == 255:
  9. return ams_id
  10. raise ValueError("ams_id must be 0-7 (AMS), 128-191 (AMS-HT) or 255 (external)")
  11. SlotAmsId = Annotated[int, AfterValidator(_a_slot_ams_id)]
  12. SlotTrayId = Annotated[int, Field(ge=0, le=3)]
  13. class SpoolmanFilamentPatch(BaseModel):
  14. name: str | None = Field(None, min_length=1, max_length=200)
  15. spool_weight: float | None = Field(None, ge=0.0, le=10_000.0)
  16. keep_existing_spools: bool = False
  17. @model_validator(mode="after")
  18. def keep_existing_requires_weight(self) -> "SpoolmanFilamentPatch":
  19. if self.keep_existing_spools and self.spool_weight is None:
  20. raise ValueError("keep_existing_spools=True requires spool_weight to be provided")
  21. return self
  22. class SpoolmanSlotAssignmentEnriched(BaseModel):
  23. """Slot assignment row enriched with printer name and AMS label.
  24. ``printer_name`` is null only in the cascade-deleted edge case where the
  25. Printer relation has been removed. ``ams_label`` is null when no
  26. ``ams_labels`` row matches the slot's MQTT serial (or the synthetic
  27. ``f"p{printer_id}a{ams_id}"`` fallback key).
  28. """
  29. printer_id: int
  30. printer_name: str | None
  31. ams_id: int
  32. tray_id: int
  33. spoolman_spool_id: int
  34. ams_label: str | None