### Query/Retrieve (Get) SCP Initialization Example using pynetdicom Source: https://pydicom.github.io/pynetdicom/stable/examples/qr_get Provides a basic setup for a Query/Retrieve (Get) SCP using pynetdicom. It initializes an Application Entity and imports necessary components for handling C-GET requests. The implementation of the `evt.EVT_C_GET` handler is crucial for managing stored SOP Instances and responding to queries. ```python import os from pydicom import dcmread from pydicom.dataset import Dataset from pynetdicom import AE, StoragePresentationContexts, evt from pynetdicom.sop_class import PatientRootQueryRetrieveInformationModelGet ``` -------------------------------- ### Verification SCP: Basic Server Setup Source: https://pydicom.github.io/pynetdicom/stable/examples/verification Sets up a Verification Service SCP. It initializes an Application Entity, adds the Verification SOP Class as supported, and starts a server listening on port 11112. It relies on the default handler for `evt.EVT_C_ECHO` to return a success status. ```python from pynetdicom import AE from pynetdicom.sop_class import Verification # Initialise the Application Entity ae = AE() # Add the supported presentation context ae.add_supported_context(Verification) # Start listening for incoming association requests in blocking mode ae.start_server(("127.0.0.1", 11112), block=True) ``` -------------------------------- ### Clone and install pynetdicom development version Source: https://pydicom.github.io/pynetdicom/stable/user/installation Clones the pynetdicom repository from GitHub and installs it in a virtual environment. This allows for development and easy updates using Git commands. It requires Git to be installed and involves creating and activating a virtual environment. ```bash git clone https://github.com/pydicom/pynetdicom cd pynetdicom/ python -m pip install -e .[dev] ``` -------------------------------- ### Initialise and Start SCP Server with All Storage Contexts (Python) Source: https://pydicom.github.io/pynetdicom/stable/examples/storage Initializes a pynetdicom Application Entity (AE), sets unlimited PDU size, adds all supported storage presentation contexts, and starts a server to listen for incoming association requests on a specified address and port. It requires the `AllStoragePresentationContexts` definition. ```python from pynetdicom import AE from pynetdicom.sop_class import AllStoragePresentationContexts # Initialise the Application Entity ae = AE() # Unlimited PDU size ae.maximum_pdu_size = 0 # Add the supported presentation contexts ae.supported_contexts = AllStoragePresentationContexts # Start listening for incoming association requests # Assuming 'handlers' is defined elsewhere, e.g., from event handlers # ae.start_server(("127.0.0.1", 11112), evt_handlers=handlers) ``` -------------------------------- ### Add Presentation Context and Start Server - pynetdicom Source: https://pydicom.github.io/pynetdicom/stable/examples/qr_find Configures the Application Entity (AE) to support a specific presentation context (PatientRootQueryRetrieveInformationModelFind) and starts a server to listen for incoming association requests on a specified address and port. It requires the pynetdicom library and event handlers. ```python from pynetdicom import AE from pynetdicom.sop_class import PatientRootQueryRetrieveInformationModelFind # Placeholder for event handlers handlers = [] # Create an AE ae = AE() # Add the supported presentation context ae.add_supported_context(PatientRootQueryRetrieveInformationModelFind) # Start listening for incoming association requests ae.start_server(("127.0.0.1", 11112), evt_handlers=handlers) ``` -------------------------------- ### Start SCP Server with Specific Context and Event Handler (Python) Source: https://pydicom.github.io/pynetdicom/stable/examples/storage Initializes a pynetdicom AE, adds a specific presentation context (CTImageStorage), defines a handler for C-STORE events to return success, and starts the server. This allows for more granular control over supported DICOM SOP Classes. Requires `pynetdicom`, `evt`, and `CTImageStorage`. ```python from pynetdicom import AE, evt from pynetdicom.sop_class import CTImageStorage def handle_store(event): # Don't store anything but respond with `Success` return 0x0000 handlers = [(evt.EVT_C_STORE, handle_store)] ae = AE() # Add a supported presentation context ae.add_supported_context(CTImageStorage) ae.start_server(("127.0.0.1", 11112), evt_handlers=handlers) ``` -------------------------------- ### DICOM Query/Retrieve - Get (C-GET and C-STORE) Example Source: https://pydicom.github.io/pynetdicom/stable/examples/index Illustrates Query/Retrieve using C-GET, which requires a C-STORE SCP to receive the retrieved objects. This example shows the client initiating a get request and expecting to receive data via C-STORE. ```python from pynetdicom import AE from pynetdicom.sop_class import PatientRootQueryRetrieveInformationGet # Initialise an Application Entity ae = AE(ae_title='PYNETDICOM-AE') # Add the C-GET presentation context ae.add_requested_context(PatientRootQueryRetrieveInformationGet) # Start a server to listen for C-STORE responses tp = ae.start_server(('127.0.0.1', 11112), block=False) # Create a C-GET request dataset # get_dataset = Dataset() # get_dataset.QueryRetrieveLevel = 'PATIENT' # get_dataset.PatientID = '123456' # Create the C-GET request # request = CGETRequest(get_dataset) # Send the C-GET request # ... (details of sending and receiving the response would follow) ``` -------------------------------- ### Install pynetdicom development version from GitHub Source: https://pydicom.github.io/pynetdicom/stable/user/installation Installs the latest development version of pynetdicom directly from the GitHub repository using pip. This method is useful for developers who want to use the most recent code, which may be unstable. It requires Git to be installed. ```bash pip install git+https://github.com/pydicom/pynetdicom ``` -------------------------------- ### Start Non-Blocking SCP Server with Event Handler (Python) Source: https://pydicom.github.io/pynetdicom/stable/examples/storage Initializes a pynetdicom AE, adds a CTImageStorage context, defines a C-STORE event handler, and starts the server in non-blocking mode. It returns a server object that can be used to shut down the server later. Requires `pynetdicom`, `evt`, `time`, and `CTImageStorage`. ```python import time from pynetdicom import AE, evt from pynetdicom.sop_class import CTImageStorage def handle_store(event): return 0x0000 handlers = [(evt.EVT_C_STORE, handle_store)] ae = AE() ae.add_supported_context(CTImageStorage) scp = ae.start_server(("127.0.0.1", 11112), block=False, evt_handlers=handlers) # Zzzz time.sleep(60) scp.shutdown() ``` -------------------------------- ### Storage SCU: Set All Storage Contexts Source: https://pydicom.github.io/pynetdicom/stable/examples/storage Shows how to configure an Application Entity to support all standard DICOM Storage SOP Classes. This is achieved by assigning `StoragePresentationContexts` to the `ae.requested_contexts` attribute, simplifying the setup when dealing with various storage types. ```python from pynetdicom import AE, StoragePresentationContexts ae = AE() ae.requested_contexts = StoragePresentationContexts ``` -------------------------------- ### Starting a Server Source: https://pydicom.github.io/pynetdicom/stable/user/association_accepting Demonstrates how to start a server to listen for association requests, supporting the Verification Service Class. ```APIDOC ## POST /start_server ### Description Starts listening for association requests from peers. ### Method POST ### Endpoint /start_server ### Parameters #### Query Parameters - **host** (string) - Required - The IP address to listen on (e.g., "127.0.0.1"). - **port** (integer) - Required - The port number to listen on (e.g., 11112). - **block** (boolean) - Optional - Whether the server should run in blocking mode (default: true). - **ae_title** (string) - Optional - The AE title for the SCP. Defaults to the parent AE's title. - **contexts** (list) - Optional - A list of presentation contexts to support on a per-SCP basis. - **evt_handlers** (list) - Optional - A list of event handlers to bind to association events. - **ssl_context** (ssl.SSLContext) - Optional - An SSLContext instance for enabling TLS. ### Request Example ```python from pynetdicom import AE from pynetdicom.sop_class import Verification ae = AE() ae.add_supported_context(Verification) # Listen for association requests on a IPv4 address ae.start_server(("127.0.0.1", 11112)) ``` ### Response #### Success Response (200) - **server_instance** (ThreadedAssociationServer or None) - An instance of ThreadedAssociationServer if block=False, otherwise None. #### Response Example ```json { "server_instance": "" // or null if block=True } ``` ``` -------------------------------- ### DICOM Basic Grayscale Print Management (N-CREATE, N-SET, N-GET, N-DELETE, N-ACTION) Example Source: https://pydicom.github.io/pynetdicom/stable/examples/index Provides examples for comprehensive Basic Grayscale Print Management, utilizing N-CREATE, N-SET, N-GET, N-DELETE, and N-ACTION services. This covers the lifecycle of print job management. ```python from pynetdicom import AE from pynetdicom.sop_class import BasicGrayscalePrintManagementMeta # Initialise an Application Entity ae = AE(ae_title='PYNETDICOM-AE') # Add the Print Management presentation context ae.add_requested_context(BasicGrayscalePrintManagementMeta) # Connect to the SCP tp = ae.start_server(('127.0.0.1', 11112), block=False) # --- N-CREATE --- # request_create = NCREATERequest(print_job_dataset) # ... Send request_create ... # --- N-SET --- # request_set = NSETRequest(print_job_uid, attribute_dataset) # ... Send request_set ... # --- N-GET --- # request_get = NGETRequest(print_job_uid, attribute_list) # ... Send request_get ... # --- N-DELETE --- # request_delete = NDELETERequest(print_job_uid) # ... Send request_delete ... # --- N-ACTION --- # request_action = NACTIONRequest(print_job_uid, action_dataset) # ... Send request_action ... # (Full implementation details for sending requests and handling responses are omitted for brevity) ``` -------------------------------- ### Python Storage SCP Server Start Source: https://pydicom.github.io/pynetdicom/stable/tutorials/create_scp This code snippet demonstrates how to initiate the Storage SCP server using pynetdicom. The `start_server` method is called with the network address (host and port) and `block=True` to run the server in a blocking mode, continuously listening for incoming DICOM association requests. This is the final step in making the SCP operational. ```python ae.start_server(("127.0.0.1", 11112), block=True) ``` -------------------------------- ### DICOM Basic Worklist Management (C-FIND) Example Source: https://pydicom.github.io/pynetdicom/stable/examples/index Demonstrates how to perform basic Worklist Management using the C-FIND service. This example shows the client-side interaction for requesting worklist information. ```python from pynetdicom import AE from pynetdicom.sop_class import WorklistQuery # Initialise an Application Entity ae = AE(ae_title='PYNETDICOM-AE') # Add the Worklist Query presentation context ae.add_requested_context(WorklistQuery) # Connect to the SCP tp = ae.start_server(('127.0.0.1', 11112), block=False) # Create a C-FIND request request =). # Send the C-FIND request # ... (details of sending and receiving the response would follow) ``` -------------------------------- ### Install pynetdicom using pip Source: https://pydicom.github.io/pynetdicom/stable/user/installation Installs or upgrades the pynetdicom package using pip, Python's package installer. This method is recommended for most users and requires Python and pydicom to be installed. It also ensures pip is up-to-date. ```bash python -m pip install -U pip python -m pip install -U pynetdicom ``` -------------------------------- ### DICOM Display System Management (N-GET) Example Source: https://pydicom.github.io/pynetdicom/stable/examples/index Illustrates how to use the N-GET service for Display System Management. This involves retrieving information about a display system resource. ```python from pynetdicom import AE from pynetdicom.sop_class import BasicGrayscaleDisplayablePatientInformationRETIRE # Initialise an Application Entity ae = AE(ae_title='PYNETDICOM-AE') # Add the N-GET presentation context for the relevant SOP Class # Note: BasicGrayscaleDisplayablePatientInformationRETIRE is used as an example SOP Class ae.add_requested_context(BasicGrayscaleDisplayablePatientInformationRETIRE) # Connect to the SCP tp = ae.start_server(('127.0.0.1', 11112), block=False) # Create an N-GET request for a specific UID # request = NGETRequest(dataset.uid, uid_type='dataset') # Send the N-GET request # ... (details of sending and receiving the response would follow) ``` -------------------------------- ### Initialize and Start MPPS SCP Server with pynetdicom Source: https://pydicom.github.io/pynetdicom/stable/examples/mpps Sets up and starts a pynetdicom Application Entity (AE) to act as an MPPS SCP. It adds the supported presentation context for ModalityPerformedProcedureStep and registers the N-CREATE and N-SET event handlers. The server then listens for incoming association requests on a specified IP address and port. ```python from pydicom.dataset import Dataset from pynetdicom import AE, evt from pynetdicom.sop_class import ModalityPerformedProcedureStep # Assuming handle_create and handle_set functions are defined elsewhere # def handle_create(event): # ... # def handle_set(event): # ... handlers = [(evt.EVT_N_CREATE, handle_create), (evt.EVT_N_SET, handle_set)] # Initialise the Application Entity and specify the listen port ae = AE() # Add the supported presentation context ae.add_supported_context(ModalityPerformedProcedureStep) # Start listening for incoming association requests # ae.start_server(("127.0.0.1", 11112), evt_handlers=handlers) ``` -------------------------------- ### DICOM Query/Retrieve - Find (C-FIND) Example Source: https://pydicom.github.io/pynetdicom/stable/examples/index Demonstrates how to perform a C-FIND operation for Query/Retrieve. This example shows the client initiating a query to find DICOM objects based on specified criteria. ```python from pynetdicom import AE from pynetdicom.sop_class import PatientRootQueryRetrieveInformationFind # Initialise an Application Entity ae = AE(ae_title='PYNETDICOM-AE') # Add the C-FIND presentation context ae.add_requested_context(PatientRootQueryRetrieveInformationFind) # Connect to the SCP tp = ae.start_server(('127.0.0.1', 11112), block=False) # Create a C-FIND request dataset # find_dataset = Dataset() # find_dataset.QueryRetrieveLevel = 'PATIENT' # find_dataset.PatientName = 'Smith*' # Create the C-FIND request # request = CFINDRequest(find_dataset) # Send the C-FIND request # ... (details of sending and receiving the response would follow) ``` -------------------------------- ### Query/Retrieve (Get) SCU using pynetdicom Source: https://pydicom.github.io/pynetdicom/stable/examples/qr_get Demonstrates an SCU sending a C-GET request to retrieve CT datasets for a specific patient and series. It includes setting up the Application Entity, adding presentation contexts, building SCP/SCU role selection, creating the identifier dataset, associating with a peer, sending the C-GET request, and handling responses. The handler for `evt.EVT_C_STORE` is implemented to save received datasets. ```python from pydicom.dataset import Dataset from pynetdicom import AE, evt, build_role, debug_logger from pynetdicom.sop_class import ( PatientRootQueryRetrieveInformationModelGet, CTImageStorage ) debug_logger() # Implement the handler for evt.EVT_C_STORE def handle_store(event): """Handle a C-STORE request event.""" ds = event.dataset ds.file_meta = event.file_meta # Save the dataset using the SOP Instance UID as the filename ds.save_as(ds.SOPInstanceUID, enforce_file_format=True) # Return a 'Success' status return 0x0000 handlers = [(evt.EVT_C_STORE, handle_store)] # Initialise the Application Entity ae = AE() # Add the requested presentation contexts (QR SCU) ae.add_requested_context(PatientRootQueryRetrieveInformationModelGet) # Add the requested presentation context (Storage SCP) ae.add_requested_context(CTImageStorage) # Create an SCP/SCU Role Selection Negotiation item for CT Image Storage role = build_role(CTImageStorage, scp_role=True) # Create our Identifier (query) dataset # We need to supply a Unique Key Attribute for each level above the # Query/Retrieve level ds = Dataset() ds.QueryRetrieveLevel = 'SERIES' # Unique key for PATIENT level ds.PatientID = '1234567' # Unique key for STUDY level ds.StudyInstanceUID = '1.2.3' # Unique key for SERIES level ds.SeriesInstanceUID = '1.2.3.4' # Associate with peer AE at IP 127.0.0.1 and port 11112 assoc = ae.associate("127.0.0.1", 11112, ext_neg=[role], evt_handlers=handlers) if assoc.is_established: # Use the C-GET service to send the identifier responses = assoc.send_c_get(ds, PatientRootQueryRetrieveInformationModelGet) for (status, identifier) in responses: if status: print(f"C-GET query status: 0x{status.Status:04x}") else: print('Connection timed out, was aborted or received invalid response') # Release the association assoc.release() else: print('Association rejected, aborted or never connected') ``` -------------------------------- ### N-SET Client Usage Example Source: https://pydicom.github.io/pynetdicom/stable/examples/mpps Demonstrates how a client can use the N-SET service to update an MPPS SOP Instance, including building the modification list. ```APIDOC ## N-SET Client Usage Example ### Description Demonstrates how a client can use the N-SET service to update an MPPS SOP Instance, including building the modification list. ### Method POST / (via pynetdicom's `assoc.send_n_set`) ### Endpoint N/A (client-side network communication) ### Parameters #### `build_mod_list` function parameters - **series_instance** (str) - The Series Instance UID. - **sop_instances** (list of str) - A list of SOP Instance UIDs to be referenced. #### `assoc.send_n_set` parameters - **Dataset** - The modification list dataset (e.g., from `build_mod_list`). - **SOP Class UID** (str) - The SOP Class UID of the service (e.g., `ModalityPerformedProcedureStep`). - **SOP Instance UID** (str) - The UID of the SOP Instance to be modified. ### Request Example ```python # Assume 'assoc' is an established association, 'ct_series_uid' and 'ct_instance_uids' are defined from pynetdicom.sop_class import ModalityPerformedProcedureStep def build_mod_list(series_instance, sop_instances): ds = Dataset() ds.PerformedSeriesSequence = [Dataset()] series_seq = ds.PerformedSeriesSequence series_seq[0].PerformingPhysicianName = None series_seq[0].ProtocolName = "Some protocol" series_seq[0].OperatorName = None series_seq[0].SeriesInstanceUID = series_instance series_seq[0].SeriesDescription = "some description" series_seq[0].RetrieveAETitle = None series_seq[0].ReferencedImageSequence = [] img_seq = series_seq[0].ReferencedImageSequence for uid in sop_instances: img_ds = Dataset() img_ds.ReferencedSOPClassUID = CTImageStorage # Assuming CTImageStorage is defined img_ds.ReferencedSOPInstanceUID = uid img_seq.append(img_ds) series_seq[0].ReferencedNonImageCompositeSOPInstanceSequence = [] return ds # Use the N-SET service to update the SOP Instance status, attr_list = assoc.send_n_set( build_mod_list(ct_series_uid, ct_instance_uids), ModalityPerformedProcedureStep, mpps_instance_uid # Assuming mpps_instance_uid is defined ) if status: print(f"N-SET request status: 0x{status.Status:04x}") # ... handle status else: print('Connection timed out, was aborted or received invalid response') # Send completion final_ds = Dataset() final_ds.PerformedProcedureStepStatus = "COMPLETED" final_ds.PerformedProcedureStepEndDate = "20000101" final_ds.PerformedProcedureStepEndTime = "1300" status, attr_list = assoc.send_n_set( final_ds, ModalityPerformedProcedureStep, mpps_instance_uid ) if status: print(f"Final N-SET request status: 0x{status.Status:04x}") # ... handle status ``` ### Response #### Success Response - **status** (pydicom.dataset.Dataset) - Contains the status of the N-SET operation. - **attr_list** (pydicom.dataset.Dataset) - Contains attributes returned by the SCP. #### Response Example (Status) ```python # If status is not None status_response = Dataset({ "Status": 0x0000 # Success }) ``` #### Error Handling - If `status` is `None`, the connection timed out, was aborted, or received an invalid response. ``` -------------------------------- ### DICOM Storage (C-STORE) Example Source: https://pydicom.github.io/pynetdicom/stable/examples/index Demonstrates how to send DICOM objects to a remote SCP using the C-STORE service. This example covers the client-side initiation of sending a DICOM file. ```python from pydicom import dcmread from pynetdicom import AE from pynetdicom.sop_class import SecondaryCaptureImageStorage # Initialise an Application Entity ae = AE(ae_title='PYNETDICOM-AE') # Add the C-STORE presentation context ae.add_requested_context(SecondaryCaptureImageStorage) # Connect to the SCP tp = ae.start_server(('127.0.0.1', 11112), block=False) # Read a DICOM file # ds = dcmread('image.dcm') # Create the C-STORE request # request = CSTORERequest(ds) # Send the C-STORE request # ... (details of sending and receiving the response would follow) ``` -------------------------------- ### DICOM MPPS (N-CREATE and N-SET) Example Source: https://pydicom.github.io/pynetdicom/stable/examples/index Shows how to manage Modality Performed Procedure Step (MPPS) using N-CREATE and N-SET operations. This is used to create and update the status of a performed procedure step. ```python from pynetdicom import AE from pynetdicom.sop_class import ModalityPerformedProcedureStepSMC # Initialise an Application Entity ae = AE(ae_title='PYNETDICOM-AE') # Add the MPPS presentation context ae.add_requested_context(ModalityPerformedProcedureStepSMC) # Connect to the SCP tp = ae.start_server(('127.0.0.1', 11112), block=False) # --- N-CREATE --- # Create an N-CREATE request dataset # mpps_create_dataset = ... # request_create = NCREATERequest(mpps_create_dataset) # Send the N-CREATE request # ... # --- N-SET --- # Create an N-SET request dataset # mpps_set_dataset = ... # request_set = NSETRequest(mpps_set_dataset) # Send the N-SET request # ... (details of sending and receiving responses would follow) ``` -------------------------------- ### Storage SCP with Query/Retrieve (Move) SCU using pynetdicom Source: https://pydicom.github.io/pynetdicom/stable/examples/qr_move This example demonstrates setting up a Storage SCP within the same AE that acts as the Move Destination for a C-MOVE operation. It configures the AE to support both the Query/Retrieve (Move) SCU and the Storage SCP roles. A handler is defined for the EVT_C_STORE event to manage incoming DICOM objects. ```python from pydicom.dataset import Dataset from pynetdicom import AE, evt, StoragePresentationContexts, debug_logger from pynetdicom.sop_class import PatientRootQueryRetrieveInformationModelMove debug_logger() def handle_store(event): """Handle a C-STORE service request""" # Ignore the request and return Success return 0x0000 handlers = [(evt.EVT_C_STORE, handle_store)] # Initialise the Application Entity ae = AE() # Add a requested presentation context ae.add_requested_context(PatientRootQueryRetrieveInformationModelMove) # Add the Storage SCP's supported presentation contexts ae.supported_contexts = StoragePresentationContexts # Start our Storage SCP in non-blocking mode, listening on port 11120 ae.ae_title = 'OUR_STORE_SCP' scp = ae.start_server(("127.0.0.1", 11120), block=False, evt_handlers=handlers) # Create out identifier (query) dataset ds = Dataset() ds.QueryRetrieveLevel = 'SERIES' # Unique key for PATIENT level ds.PatientID = '1234567' # Unique key for STUDY level ds.StudyInstanceUID = '1.2.3' # Unique key for SERIES level ds.SeriesInstanceUID = '1.2.3.4' # Associate with peer AE at IP 127.0.0.1 and port 11112 assoc = ae.associate("127.0.0.1", 11112) if assoc.is_established: # Use the C-MOVE service to send the identifier responses = assoc.send_c_move(ds, 'OUR_STORE_SCP', PatientRootQueryRetrieveInformationModelMove) for (status, identifier) in responses: if status: print(f"C-MOVE query status: 0x{status.Status:04x}") else: print('Connection timed out, was aborted or received invalid response') # Release the association assoc.release() else: print('Association rejected, aborted or never connected') # Stop our Storage SCP scp.shutdown() ``` -------------------------------- ### DICOM Query/Retrieve - Move (C-MOVE and C-STORE) Example Source: https://pydicom.github.io/pynetdicom/stable/examples/index Demonstrates Query/Retrieve using C-MOVE, which involves instructing a remote SCP to move DICOM objects to a specified destination. This also requires a C-STORE SCP at the destination to receive the data. ```python from pynetdicom import AE from pynetdicom.sop_class import PatientRootQueryRetrieveInformationMove # Initialise an Application Entity ae = AE(ae_title='PYNETDICOM-AE') # Add the C-MOVE presentation context ae.add_requested_context(PatientRootQueryRetrieveInformationMove) # Start a server to listen for C-STORE responses tp = ae.start_server(('127.0.0.1', 11112), block=False) # Create a C-MOVE request dataset # move_dataset = Dataset() # move_dataset.QueryRetrieveLevel = 'PATIENT' # move_dataset.PatientID = '123456' # move_dataset.DestinationAE = 'DESTINATION-AE' # Create the C-MOVE request # request = CMODERequest(move_dataset) # Send the C-MOVE request # ... (details of sending and receiving the response would follow) ``` -------------------------------- ### Start Echo SCP with pynetdicom Source: https://pydicom.github.io/pynetdicom/stable/tutorials/create_scu This command starts the pynetdicom Echo SCP application, making it listen for incoming DICOM association requests on a specified port. The '-v' flag enables verbose output for monitoring. ```bash python -m pynetdicom echoscp 11112 -v ``` -------------------------------- ### Server Control: start_server() Source: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.ae Starts the Application Entity (AE) as an association acceptor (SCP). ```APIDOC ## Server Control: start_server() ### Description Starts the AE as an association acceptor (SCP). Can be run in blocking or non-blocking mode. In non-blocking mode, it returns a `ThreadedAssociationServer` instance that can be managed. ### Method `start_server(_address : tuple[str, int] | tuple[str, int, int, int]_, _block : bool = True_, _ssl_context : SSLContext | None = None_, _evt_handlers : list[tuple[NotificationEvent | InterventionEvent, Callable] | tuple[NotificationEvent | InterventionEvent, Callable, list[Any]]] | None = None_, _ae_title : str | None = None_, _contexts : list[PresentationContext] | None = None_) → ThreadedAssociationServer | None` ### Endpoint N/A (Local method) ### Parameters * **address** (_tuple[str, int] | tuple[str, int, int, int]_) – Required. The host IP address and port number to listen on. Can be IPv4 or IPv6 format. * `tuple[str, int]`: e.g., `("192.168.1.2", 104)` or `("::1", 11112)` * `tuple[str, int, int, int]`: IPv6 with flowinfo and scope_id, e.g., `("::1", 11112, 0, 0)` * **block** (_bool_, optional) – Defaults to `True`. If `True`, the server runs in the current thread (blocking). If `False`, it runs in a new thread (non-blocking). * **ssl_context** (_ssl.SSLContext | None_, optional) – SSL context for TLS encryption. If `None`, TLS is not used. * **evt_handlers** (_list[tuple[NotificationEvent | InterventionEvent, Callable] | tuple[NotificationEvent | InterventionEvent, Callable, list[Any]]]_ | None_, optional) – List of event handlers to register for notifications and interventions. * **ae_title** (_str_ | None_, optional) – The AE title for the local SCP. Defaults to the AE's `ae_title` property if not provided. * **contexts** (_list[PresentationContext]_ | None_, optional) – The presentation contexts the SCP will support. Defaults to the AE's `supported_contexts` property if not provided. ### Request Example ```python from pynetdicom import AE, evt from pynetdicom.apps.common import STDOUT_LOGGER from pynetdicom.sop_class import VerificationSOPClass from pynetdicom.presentation import PresentationContext # Example event handler def handle_verification_request(event): print("Received Verification Request") return 0xC000 # Success ae = AE() # Set up presentation contexts pc = PresentationContext() pc.abstract_syntax = VerificationSOPClass pc.transfer_syntax = [ImplicitVRLittleEndian, ExplicitVRLittleEndian] events = [ (evt.EVT_VERIFICATION_REQUEST, handle_verification_request) ] # Start server in non-blocking mode server = ae.start_server( ("127.0.0.1", 11112), block=False, evt_handlers=events, ae_title="MY_SCP", contexts=[pc] ) # If non-blocking, server is a ThreadedAssociationServer instance if server: print("Server started in a new thread") # ... do other things ... # To stop: server.shutdown() else: print("Server started in blocking mode") ``` ### Response Returns `ThreadedAssociationServer` if `block` is `False`, otherwise returns `None`. ### Response Example ```json { "message": "Server started successfully" } ``` ``` -------------------------------- ### Query/Retrieve (Find) SCP Example: Handler for C-FIND Source: https://pydicom.github.io/pynetdicom/stable/examples/qr_find This Python code defines a handler function (`handle_find`) for the `evt.EVT_C_FIND` event, intended for a Query/Retrieve SCP implementation. It processes incoming C-FIND requests, retrieves DICOM instances from a specified directory, and yields responses based on the query criteria and supported SOP Classes. ```python import os from pydicom import dcmread from pydicom.dataset import Dataset from pynetdicom import AE, evt from pynetdicom.sop_class import PatientRootQueryRetrieveInformationModelFind # Implement the handler for evt.EVT_C_FIND def handle_find(event): """Handle a C-FIND request event.""" ds = event.identifier # Import stored SOP Instances instances = [] fdir = '/path/to/directory' for fpath in os.listdir(fdir): instances.append(dcmread(os.path.join(fdir, fpath))) if 'QueryRetrieveLevel' not in ds: # Failure yield 0xC000, None return if ds.QueryRetrieveLevel == 'PATIENT': if 'PatientName' in ds: if ds.PatientName not in ['*', '', '?']: matching = [ inst for inst in instances if inst.PatientName == ds.PatientName ] # Skip the other possible values... # Skip the other possible attributes... # Skip the other QR levels... for instance in matching: # Check if C-CANCEL has been received if event.is_cancelled: yield (0xFE00, None) return identifier = Dataset() identifier.PatientName = instance.PatientName identifier.QueryRetrieveLevel = ds.QueryRetrieveLevel # Pending yield (0xFF00, identifier) handlers = [(evt.EVT_C_FIND, handle_find)] # Initialise the Application Entity and specify the listen port ae = AE() ``` -------------------------------- ### Python Imports for Storage SCP Source: https://pydicom.github.io/pynetdicom/stable/tutorials/create_scp This snippet shows the essential imports required for the Storage SCP example. It includes importing the ExplicitVRLittleEndian transfer syntax UID from pydicom, and the AE class, debug_logger function, and CTImageStorage SOP class UID from pynetdicom. These are fundamental for setting up the DICOM network entity and defining supported services. ```python from pydicom.uid import ExplicitVRLittleEndian from pynetdicom import AE, debug_logger from pynetdicom.sop_class import CTImageStorage ``` -------------------------------- ### Query/Retrieve (Get) SCP Identifier Dataset Example using pynetdicom Source: https://pydicom.github.io/pynetdicom/stable/examples/qr_get Shows an example of an Identifier dataset sent by an SCU to a Query/Retrieve (Get) SCP. This dataset specifies the query level and attributes to filter by, such as PatientID. This is typically used in conjunction with the `evt.EVT_C_GET` handler on the SCP. ```python ds = Dataset() ds.QueryRetrieveLevel = 'PATIENT' ds.PatientID = '1234567' ``` -------------------------------- ### Verification SCU: Using Predefined Contexts Source: https://pydicom.github.io/pynetdicom/stable/examples/verification An alternative method for a Verification SCU to set up requested presentation contexts using the `VerificationPresentationContexts` constant provided by pynetdicom. ```python from pynetdicom import AE, VerificationPresentationContexts ae = AE() ae.requested_contexts = VerificationPresentationContexts ``` -------------------------------- ### Install pynetdicom using conda Source: https://pydicom.github.io/pynetdicom/stable/user/installation Installs or upgrades the pynetdicom package from the conda-forge channel. This is an alternative to pip for users managing their environments with conda. It's suitable for installing the official release. ```bash conda install -c conda-forge pynetdicom ``` ```bash conda update pynetdicom ``` -------------------------------- ### Python: pynetdicom AE Initialization and Context Setup Source: https://pydicom.github.io/pynetdicom/stable/tutorials/create_scu This snippet focuses on the initialization of a pynetdicom Application Entity (AE) and the addition of a presentation context. It imports the AE class, instantiates it, and then uses add_requested_context() to propose the abstract syntax for the Verification Service (1.2.840.10008.1.1). ```python from pynetdicom import AE ae = AE() ae.add_requested_context("1.2.840.10008.1.1") ``` -------------------------------- ### Start DICOM Server (Basic) Source: https://pydicom.github.io/pynetdicom/stable/user/association_accepting Initiates a DICOM server to listen for association requests on a specified IP address and port. This basic example is suitable for the Verification Service Class. Ensure presentation contexts are added before starting the server. ```python from pynetdicom import AE from pynetdicom.sop_class import Verification ae = AE() ae.add_supported_context(Verification) # Listen for association requests on a IPv4 address, IPv6 is also supported ae.start_server(("127.0.0.1", 11112)) ``` -------------------------------- ### movescu Example: With Storage SCP Source: https://pydicom.github.io/pynetdicom/stable/apps/movescu Illustrates running `movescu` with the `--store` option enabled, which starts a local Storage SCP. This example shows the C-MOVE request, the association and reception of DICOM data by the local Storage SCP, and the final C-MOVE response. ```bash $ python -m pynetdicom movescu 127.0.0.1 11112 -k QueryRetrieveLevel=PATIENT -k PatientName= --store I: Requesting Association I: Association Accepted I: Sending Move Request: MsgID 1 I: I: # Request Identifier I: (0008,0052) CS [PATIENT] # 1 QueryRetrieveLevel I: (0010,0010) PN (no value available) # 0 PatientName I: I: Accepting Association I: Received Store Request I: Storing DICOM file: CT.1.3.6.1.4.1.5962.1.1.1.1.1.20040119072730.12322 I: Association Released I: Move SCP Response: 1 - 0xFF00 (Pending) I: Sub-Operations Remaining: 0, Completed: 1, Failed: 0, Warning: 0 I: Move SCP Result: 0x0000 (Success) I: Sub-Operations Remaining: 0, Completed: 1, Failed: 0, Warning: 0 I: Releasing Association ``` -------------------------------- ### Basic Echo SCU Implementation with pynetdicom Source: https://pydicom.github.io/pynetdicom/stable/tutorials/create_scu This Python code snippet demonstrates how to set up an AE (Application Entity), add a presentation context for the Verification SOP Class, associate with a server, send a C-ECHO request, and release the association. It's a foundational example for creating DICOM SCU clients. ```python from pynetdicom import AE, debug_logger debug_logger() ae = AE() ae.add_requested_context("1.2.840.10008.1.1") assoc = ae.associate("127.0.0.1", 11112) if assoc.is_established: status = assoc.send_c_echo() assoc.release() ``` -------------------------------- ### AssociationServer Initialization Source: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.transport Creates a new AssociationServer instance, binds a socket, and starts listening for incoming connections. ```APIDOC ## AssociationServer Constructor ### Description Create a new `AssociationServer`, bind a socket and start listening. ### Method `__init__` ### Parameters - **ae** (ae.ApplicationEntity) - Required - The parent AE that’s running the server. - **address** (tuple[str, int] | tuple[str, int, int, int]) - Required - The `(host: str, port: int)` or `(host: str, port: int, flowinfo: int, scope_id: int)` that the server should run on. - **ae_title** (str) - Required - The AE title of the SCP. - **contexts** (list[presentation.PresentationContext]) - Required - The SCPs supported presentation contexts. - **ssl_context** (ssl.SSLContext | None) - Optional - If TLS is to be used then this should be the `ssl.SSLContext` used to wrap the client sockets, otherwise if `None` then no TLS will be used (default). - **evt_handlers** (list[tuple[NotificationEvent | InterventionEvent, Callable] | tuple[NotificationEvent | InterventionEvent, Callable, list[Any]]] | None) - Optional - A list of `(event, callable)` or `(event, callable, args)`, the `callable` function to run when `event` occurs and the optional extra `args` to pass to the callable. - **request_handler** (Callable[..., BaseRequestHandler] | None) - Optional - The request handler class; an instance of this class is created for each request. Should be a subclass of `BaseRequestHandler`. ``` -------------------------------- ### Get Printer Status using pynetdicom Source: https://pydicom.github.io/pynetdicom/stable/examples/print Establishes an association with a print management SCP and retrieves the printer status using an N-GET request. It checks for a status of 'NORMAL' before proceeding with print operations. ```python from pynetdicom import AE, evt from pynetdicom.sop_class import BasicGrayscalePrintManagementMeta, Printer, PrinterInstance, BasicFilmSession, BasicFilmBox import sys # ... (previous function definitions) ae = AE() ae.add_requested_context(BasicGrayscalePrintManagementMeta) assoc = ae.associate("127.0.0.1", 11112, evt_handlers=handlers) if assoc.is_established: # Step 1: Check the status of the printer # (2110,0010) Printer Status # (2110,0020) Printer Status Info # Because the association was negotiated using a presentation context # with a Meta SOP Class we need to use the `meta_uid` keyword # parameter to ensure we use the correct context status, attr_list = assoc.send_n_get( [0x21100010, 0x21100020], # Attribute Identifier List Printer, # Affected SOP Class UID PrinterInstance, # Well-known Printer SOP Instance meta_uid=BasicGrayscalePrintManagementMeta ) if status and status.Status == 0x0000: if getattr(attr_list, 'PrinterStatus', None) != "NORMAL": print("Printer status is not 'NORMAL'") assoc.release() sys.exit() else: print("Failed to get the printer status") assoc.release() sys.exit() else: print("Failed to get the printer status") assoc.release() sys.exit() print('Printer ready') ``` -------------------------------- ### Verification SCU: Associate and Send C-ECHO Source: https://pydicom.github.io/pynetdicom/stable/examples/verification Demonstrates how to configure a Verification Service SCU. It initializes an Application Entity, requests the Verification SOP Class, associates with a peer AE, sends a C-ECHO request, and prints the status. It then releases the association. Handles connection timeouts, rejections, and invalid responses. ```python from pynetdicom import AE from pynetdicom.sop_class import Verification # Initialise the Application Entity ae = AE() # Add a requested presentation context ae.add_requested_context(Verification) # Associate with peer AE at IP 127.0.0.1 and port 11112 assoc = ae.associate("127.0.0.1", 11112) if assoc.is_established: # Use the C-ECHO service to send the request # returns the response status a pydicom Dataset status = assoc.send_c_echo() # Check the status of the verification request if status: # If the verification request succeeded this will be 0x0000 print(f"C-ECHO request status: 0x{status.Status:04x}") else: print('Connection timed out, was aborted or received invalid response') # Release the association assoc.release() else: print('Association rejected, aborted or never connected') ``` -------------------------------- ### Specify Server Bind Address in pynetdicom Source: https://pydicom.github.io/pynetdicom/stable/user/ae_scp This snippet illustrates how to specify the bind address for a pynetdicom server using the `start_server` method. It shows examples for both IPv4 and IPv6 addresses, demonstrating the use of a 2-tuple for IPv4/IPv6 and a 4-tuple for IPv6 with flowinfo and scope_id. The server is started in non-blocking mode and then shut down. ```python from pynetdicom import AE ae = AE() ae.add_supported_context('1.2.840.10008.1.1') server = ae.start_server(("127.0.0.1", 11112), block=False) server.shutdown() server = ae.start_server(("::1", 11112), block=False) server.shutdown() ``` -------------------------------- ### DICOM Verification (C-ECHO) Example Source: https://pydicom.github.io/pynetdicom/stable/examples/index Provides an example of the C-ECHO service for verifying communication with a DICOM SCP. This is a fundamental test to ensure connectivity. ```python from pynetdicom import AE from pynetdicom.sop_class import Verification # Initialise an Application Entity ae = AE(ae_title='PYNETDICOM-AE') # Add the Verification presentation context ae.add_requested_context(Verification) # Connect to the SCP tp = ae.start_server(('127.0.0.1', 11112), block=False) # Create a C-ECHO request # request = CECHORequest() # Send the C-ECHO request # ... (details of sending and receiving the response would follow) ```