Skip to content

Commit ed5fc8c

Browse files
committed
Formalise MWL status as an enum
The database values and check constraint mirror DICOM PACS statuses
1 parent 71499e0 commit ed5fc8c

6 files changed

Lines changed: 26 additions & 13 deletions

File tree

src/services/init_worklist_db.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ CREATE TABLE IF NOT EXISTS worklist_items (
2626
procedure_code TEXT,
2727

2828
-- Status tracking
29-
status TEXT DEFAULT 'SCHEDULED' CHECK(status IN ('SCHEDULED', 'IN_PROGRESS', 'COMPLETED', 'DISCONTINUED')),
29+
status TEXT DEFAULT 'SCHEDULED' CHECK(status IN ('SCHEDULED', 'IN PROGRESS', 'COMPLETED', 'DISCONTINUED')),
3030

3131
-- DICOM identifiers
3232
study_instance_uid TEXT,

src/services/mwl/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
"""Modality Worklist (MWL) services for DICOM worklist management."""
22

3+
from enum import Enum
4+
35
from services.mwl.c_find import CFindHandler
46

57
__all__ = ["CFindHandler"]
8+
9+
10+
class MWLStatus(Enum):
11+
SCHEDULED = "SCHEDULED"
12+
IN_PROGRESS = "IN PROGRESS"
13+
COMPLETED = "COMPLETED"
14+
DISCONTINUED = "DISCONTINUED"

src/services/mwl/n_create.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@
55
from pynetdicom.sop_class import ModalityPerformedProcedureStep # pyright: ignore[reportAttributeAccessIssue]
66

77
from services.dicom import DUPLICATE_SOP_INSTANCE, INVALID_ATTRIBUTE, MISSING_ATTRIBUTE, PROCESSING_FAILURE, SUCCESS
8+
from services.mwl import MWLStatus
89
from services.storage import MWLStorage
910

1011
logger = logging.getLogger(__name__)
1112

12-
UNKNOWN = "UNKNOWN"
13-
1413

1514
class NCreate:
1615
def __init__(self, storage: MWLStorage):
@@ -31,11 +30,14 @@ def call(self, event: Event) -> tuple[int, Dataset | None]:
3130
return DUPLICATE_SOP_INSTANCE, None
3231

3332
attr_list = event.attribute_list
33+
status = getattr(attr_list, "PerformedProcedureStepStatus", None)
3434

35-
if "PerformedProcedureStepStatus" not in attr_list:
35+
if not status:
36+
logger.warning("MPPS N-CREATE: Missing PerformedProcedureStepStatus in request")
3637
return MISSING_ATTRIBUTE, None
3738

38-
if attr_list.PerformedProcedureStepStatus.upper() != "IN PROGRESS":
39+
if status.upper() != MWLStatus.IN_PROGRESS.value:
40+
logger.warning("MPPS N-CREATE: Invalid PerformedProcedureStepStatus value: %s", status)
3941
return INVALID_ATTRIBUTE, None
4042

4143
ds.SOPClassUID = ModalityPerformedProcedureStep
@@ -50,20 +52,22 @@ def call(self, event: Event) -> tuple[int, Dataset | None]:
5052
sps = attr_list.ScheduledStepAttributesSequence[0]
5153
accession_number = sps.get("AccessionNumber")
5254

53-
logger.info("MPPS N-CREATE: Started procedure for Accession Number: %w", accession_number)
55+
logger.info("MPPS N-CREATE: Started procedure for Accession Number: %s", accession_number)
5456

5557
if not accession_number:
5658
logger.warning("MPPS N-CREATE: Missing Accession Number in ScheduledStepAttributesSequence")
5759
return MISSING_ATTRIBUTE, None
5860

59-
source_message_id = self.storage.update_status(accession_number, "IN_PROGRESS", ds.SOPInstanceUID)
61+
source_message_id = self.storage.update_status(
62+
accession_number, MWLStatus.IN_PROGRESS.value, ds.SOPInstanceUID
63+
)
6064
if source_message_id:
61-
logger.info(f"Worklist item updated: {accession_number} -> IN_PROGRESS")
65+
logger.info("Worklist item updated: %s -> %s", accession_number, MWLStatus.IN_PROGRESS.value)
6266
else:
63-
logger.warning(f"Could not find accession {accession_number} in database")
67+
logger.warning("Could not find accession %s in database", accession_number)
6468

6569
except Exception as e:
66-
logger.error(f"Error in handle_create: {str(e)}", exc_info=True)
70+
logger.error("Error in handle_create: %s", str(e), exc_info=True)
6771
return PROCESSING_FAILURE, None
6872

6973
# Success - return the created dataset

tests/integration/test_n_create_updates_worklist_status.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,4 @@ def test_n_create_updates_worklist_status(self, tmp_dir, worklist_item):
7373

7474
assert updated_item is not None
7575
assert updated_item.mpps_instance_uid == mpps_instance_uid
76-
assert updated_item.status == "IN_PROGRESS"
76+
assert updated_item.status == "IN PROGRESS"

tests/integration/test_n_set_updates_worklist_status.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def worklist_item(self):
4545
def test_n_set_updates_worklist_status(self, tmp_dir, worklist_item, mpps_instance_uid):
4646
storage = MWLStorage(f"{tmp_dir}/test.db")
4747
accession_number = storage.store_worklist_item(worklist_item)
48-
storage.update_status(accession_number, "IN_PROGRESS", mpps_instance_uid)
48+
storage.update_status(accession_number, "IN PROGRESS", mpps_instance_uid)
4949

5050
ae = AE(ae_title="MODALITY_SCU")
5151
ae.add_requested_context(ModalityPerformedProcedureStep)

tests/services/mwl/test_n_create.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def test_ncreate_success(self, storage, event, sop_instance_uid):
5959
assert ds.PerformedProcedureStepStatus == "IN PROGRESS"
6060

6161
storage.mpps_instance_exists.assert_called_once_with(sop_instance_uid)
62-
storage.update_status.assert_called_once_with("ACC123", "IN_PROGRESS", sop_instance_uid)
62+
storage.update_status.assert_called_once_with("ACC123", "IN PROGRESS", sop_instance_uid)
6363

6464
def test_ncreate_missing_sop_instance_uid(self, storage, event):
6565
event.request.AffectedSOPInstanceUID = None

0 commit comments

Comments
 (0)