Skip to content

Commit b6f30c6

Browse files
committed
Support N-SET on modality worklist server
1 parent 6e94826 commit b6f30c6

4 files changed

Lines changed: 78 additions & 2 deletions

File tree

src/server.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from services.dicom.c_store import CStore
1818
from services.mwl.c_find import CFindHandler
1919
from services.mwl.n_create import NCreate
20+
from services.mwl.n_set import NSet
2021
from services.storage import MWLStorage, PACSStorage
2122

2223
logger = logging.getLogger(__name__)
@@ -107,6 +108,7 @@ def start(self):
107108
handlers = [
108109
(evt.EVT_C_FIND, CFindHandler(self.storage).call),
109110
(evt.EVT_N_CREATE, NCreate(self.storage).call),
111+
(evt.EVT_N_SET, NSet(self.storage).call),
110112
]
111113

112114
logger.info(f"MWL server listening on 0.0.0.0:{self.port}")

src/services/storage.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,8 +522,11 @@ def mpps_instance_exists(self, mpps_instance_uid: str) -> bool:
522522
cursor = conn.execute("SELECT 1 FROM worklist_items WHERE mpps_instance_uid = ?", (mpps_instance_uid,))
523523
return cursor.fetchone() is not None
524524

525-
def get_worklist_item_by_mpps_instance_uid(self, mpps_instance_uid: str) -> Optional[WorklistItem]:
525+
def get_worklist_item_by_mpps_instance_uid(self, mpps_instance_uid: str | None) -> Optional[WorklistItem]:
526526
"""Get a worklist item by its associated MPPS instance UID."""
527+
if mpps_instance_uid is None:
528+
return None
529+
527530
with self._get_connection() as conn:
528531
cursor = conn.execute(
529532
(
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import datetime
2+
3+
import pytest
4+
from pydicom.dataset import Dataset
5+
from pydicom.uid import generate_uid
6+
from pynetdicom import AE
7+
from pynetdicom.sop_class import ModalityPerformedProcedureStep # pyright: ignore[reportAttributeAccessIssue]
8+
9+
from server import MWLServer
10+
from services.dicom import SUCCESS
11+
from services.storage import MWLStorage, WorklistItem
12+
13+
14+
class TestNSetUpdatesWorklistStatus:
15+
@pytest.fixture(autouse=True)
16+
def with_mwl_server(self, tmp_dir):
17+
server = MWLServer("SCREENING_MWL", 4243, f"{tmp_dir}/test.db", block=False)
18+
server.start()
19+
20+
yield
21+
22+
server.stop()
23+
24+
@pytest.fixture
25+
def mpps_instance_uid(self):
26+
return generate_uid()
27+
28+
@pytest.fixture
29+
def worklist_item(self):
30+
return WorklistItem(
31+
accession_number="ACC123",
32+
patient_id="999123456",
33+
patient_name="SMITH^JANE",
34+
patient_birth_date="19800101",
35+
patient_sex="F",
36+
scheduled_date="20240101",
37+
scheduled_time="090000",
38+
modality="MG",
39+
procedure_code="12345-6",
40+
study_description="MAMMOGRAPHY SCREENING",
41+
study_instance_uid=generate_uid(),
42+
source_message_id="MSGID123456",
43+
)
44+
45+
def test_n_set_updates_worklist_status(self, tmp_dir, worklist_item, mpps_instance_uid):
46+
storage = MWLStorage(f"{tmp_dir}/test.db")
47+
accession_number = storage.store_worklist_item(worklist_item)
48+
storage.update_status(accession_number, "IN_PROGRESS", mpps_instance_uid)
49+
50+
ae = AE(ae_title="MODALITY_SCU")
51+
ae.add_requested_context(ModalityPerformedProcedureStep)
52+
53+
assoc = ae.associate("localhost", 4243, ae_title="SCREENING_MWL")
54+
55+
mpps_ds = Dataset()
56+
mpps_ds.SOPClassUID = ModalityPerformedProcedureStep
57+
mpps_ds.PerformedProcedureStepStatus = "COMPLETED"
58+
now = datetime.datetime.now()
59+
mpps_ds.PerformedProcedureStepStartDate = now.strftime("%Y%m%d")
60+
mpps_ds.PerformedProcedureStepStartTime = now.strftime("%H%M%S")
61+
62+
response = assoc.send_n_set(mpps_ds, ModalityPerformedProcedureStep, mpps_instance_uid)
63+
64+
assert response[0].Status == SUCCESS
65+
66+
updated_item = storage.get_worklist_item_by_mpps_instance_uid(mpps_instance_uid)
67+
68+
assert updated_item is not None
69+
assert updated_item.mpps_instance_uid == mpps_instance_uid
70+
assert updated_item.status == "COMPLETED"
71+
assert updated_item.accession_number == accession_number

tests/test_server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def test_start(self, mock_ae, _):
109109
assert args[0] == ("0.0.0.0", 4243)
110110
assert kwargs["block"] is True
111111
assert "evt_handlers" in kwargs
112-
assert len(kwargs["evt_handlers"]) == 2
112+
assert len(kwargs["evt_handlers"]) == 3
113113

114114
@patch(f"{MWLServer.__module__}.AE")
115115
def test_stop(self, *_):

0 commit comments

Comments
 (0)