generated from coulomb/repo-seed
feat(tasks): adopt canonical task statuses
This commit is contained in:
84
api/task_status.py
Normal file
84
api/task_status.py
Normal file
@@ -0,0 +1,84 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
CANONICAL_TASK_STATUSES: tuple[str, ...] = (
|
||||
"wait",
|
||||
"todo",
|
||||
"progress",
|
||||
"done",
|
||||
"cancel",
|
||||
)
|
||||
|
||||
TASK_STATUS_CODES: dict[str, str] = {
|
||||
"WAIT": "wait",
|
||||
"TODO": "todo",
|
||||
"PROG": "progress",
|
||||
"DONE": "done",
|
||||
"CNCL": "cancel",
|
||||
}
|
||||
|
||||
LEGACY_TASK_STATUS_ALIASES: dict[str, str] = {
|
||||
"blocked": "wait",
|
||||
"waiting": "wait",
|
||||
"in_progress": "progress",
|
||||
"in-progress": "progress",
|
||||
"prog": "progress",
|
||||
"cancelled": "cancel",
|
||||
"canceled": "cancel",
|
||||
"cncl": "cancel",
|
||||
}
|
||||
|
||||
OPEN_TASK_STATUSES: frozenset[str] = frozenset({"wait", "todo", "progress"})
|
||||
ACTIVE_TASK_STATUSES: frozenset[str] = frozenset({"wait", "progress"})
|
||||
TERMINAL_TASK_STATUSES: frozenset[str] = frozenset({"done", "cancel"})
|
||||
|
||||
TASK_STATUS_ORDER: dict[str, int] = {
|
||||
"todo": 0,
|
||||
"wait": 1,
|
||||
"progress": 1,
|
||||
"done": 2,
|
||||
"cancel": 2,
|
||||
}
|
||||
|
||||
TASK_STATUS_LABELS: dict[str, str] = {
|
||||
"wait": "wait",
|
||||
"todo": "todo",
|
||||
"progress": "progress",
|
||||
"done": "done",
|
||||
"cancel": "cancel",
|
||||
}
|
||||
|
||||
|
||||
def raw_status_value(status: Any) -> str:
|
||||
if hasattr(status, "value"):
|
||||
status = status.value
|
||||
return str(status or "").strip()
|
||||
|
||||
|
||||
def normalize_task_status(status: Any, *, default: str | None = None) -> str:
|
||||
"""Normalize canon task statuses plus legacy aliases to stored values."""
|
||||
value = raw_status_value(status).lower()
|
||||
if not value:
|
||||
if default is not None:
|
||||
return default
|
||||
raise ValueError("task status is required")
|
||||
value = LEGACY_TASK_STATUS_ALIASES.get(value, value)
|
||||
if value not in CANONICAL_TASK_STATUSES:
|
||||
allowed = ", ".join(CANONICAL_TASK_STATUSES)
|
||||
aliases = ", ".join(sorted(LEGACY_TASK_STATUS_ALIASES))
|
||||
raise ValueError(f"task status must be one of {allowed}; legacy aliases: {aliases}")
|
||||
return value
|
||||
|
||||
|
||||
def status_value(status: Any, *, default: str | None = None) -> str:
|
||||
"""Compatibility wrapper used by lifecycle and reconciliation code."""
|
||||
return normalize_task_status(status, default=default)
|
||||
|
||||
|
||||
def is_open_task_status(status: Any) -> bool:
|
||||
return normalize_task_status(status, default="todo") in OPEN_TASK_STATUSES
|
||||
|
||||
|
||||
def is_terminal_task_status(status: Any) -> bool:
|
||||
return normalize_task_status(status, default="todo") in TERMINAL_TASK_STATUSES
|
||||
Reference in New Issue
Block a user