Skip to content

DIMSE networking

pydcm.dimse is a drop-in DIMSE API over the native stack — import pydcm.dimse as pynetdicom and existing code mostly just works. SCU and a full SCP are both supported, over a single persistent association.

Verify connectivity (C-ECHO)

import pydcm.dimse as pynetdicom

ae = pynetdicom.AE(ae_title="PYDCM")
assoc = ae.associate("pacs.local", 11112, ae_title="ANY-SCP")
if assoc.is_established:
    assoc.send_c_echo()
assoc.release()

Store instances (C-STORE)

The association is persistent — negotiate once, send many, release once:

ae = pynetdicom.AE(ae_title="PYDCM")
assoc = ae.associate("pacs.local", 11112)
for path in ["a.dcm", "b.dcm", "c.dcm"]:
    assoc.send_c_store(pydcm.dcmread(path))
assoc.release()

Query & retrieve (C-FIND / C-GET / C-MOVE)

from pydcm.sop_class import StudyRootQueryRetrieveInformationModelFind

query = pydcm.Dataset()
query.QueryRetrieveLevel = "STUDY"
query.PatientID = "42"
query.StudyInstanceUID = ""

assoc = ae.associate("pacs.local", 11112)
for status, identifier in assoc.send_c_find(query, StudyRootQueryRetrieveInformationModelFind):
    if identifier:
        print(identifier.StudyInstanceUID)
assoc.release()

query_model is the Q/R model's FIND SOP Class UID — use the sop_class constants (spelled-out service names), not a one-letter shorthand.

send_c_get retrieves over the same association (role-flip storage receive); send_c_move ships matches to a third-party destination AE.

Run an SCP

def handle_store(event):
    event.dataset.save_as(f"{event.dataset.SOPInstanceUID}.dcm", write_like_original=False)
    return 0x0000   # Success

ae = pynetdicom.AE(ae_title="PYDCM-SCP")
ae.add_supported_context(pynetdicom.sop_class.CTImageStorage)
ae.start_server(("0.0.0.0", 11112), evt_handlers=[(pynetdicom.evt.EVT_C_STORE, handle_store)])

start_server wires EVT_C_STORE / EVT_C_ECHO / EVT_C_FIND / EVT_C_GET / EVT_C_MOVE plus the DIMSE-N events.