Skip to main content

A Python implementation of the DICOM networking protocol

Project description

https://codecov.io/gh/pydicom/pynetdicom/branch/master/graph/badge.svg https://travis-ci.org/pydicom/pynetdicom.svg?branch=master https://circleci.com/gh/pydicom/pynetdicom/tree/master.svg?style=shield https://badge.fury.io/py/pynetdicom.svg https://img.shields.io/pypi/pyversions/pynetdicom.svg https://img.shields.io/conda/vn/conda-forge/pynetdicom.svg https://zenodo.org/badge/DOI/10.5281/zenodo.3995765.svg https://badges.gitter.im/pydicom/Lobby.svg

pynetdicom

A Python implementation of the DICOM networking protocol, originally based on (legacy) pynetdicom.

Description

DICOM is the international standard for medical images and related information. It defines the formats and communication protocols for media exchange in radiology, cardiology, radiotherapy and other medical domains.

pynetdicom is a pure Python (2.7/3.5+) package that implements the DICOM networking protocol. Working with pydicom, it allows the easy creation of DICOM Service Class Users (SCUs) and Service Class Providers (SCPs).

pynetdicom’s main user class is AE, which is used to represent a DICOM Application Entity. Once an AE has been created you can:

  • Start the application as an SCP by specifying the supported presentation contexts then calling AE.start_server() and waiting for incoming association requests

  • Use the application as an SCU by specifying the presentation contexts you want the peer SCP to support, then requesting an association via the AE.associate() method, which returns an Association thread.

Once associated, the services available to the association can be used by sending DIMSE-C and DIMSE-N messages.

Documentation

The pynetdicom tutorials, user guide, code examples, application and API reference documentation is available for the current release as well as the development version.

Installation

Dependencies

pydicom

Installing current release

Using pip:

$ pip install pynetdicom

Using conda:

$ conda install -c conda-forge pynetdicom

Installing development version

$ pip install git+git://github.com/pydicom/pynetdicom.git

Supported DIMSE Services

SCU Services

When the AE is acting as an SCU and an association has been established with a peer SCP, the following DIMSE-C and -N services are available:

DIMSE service

Association method

C-ECHO

Association.send_c_echo()

C-FIND

Association.send_c_find(dataset, query_model)

C-GET

Association.send_c_get(dataset, query_model)

C-MOVE

Association.send_c_move(dataset, move_aet, query_model)

C-STORE

Association.send_c_store(dataset)

N-ACTION

Association.send_n_action(dataset, action_type, class_uid, instance_uid)

N-CREATE

Association.send_n_create(dataset, class_uid, instance_uid)

N-DELETE

Association.send_n_delete(class_uid, instance_uid)

N-EVENT-REPORT

Association.send_n_event_report(dataset, event_type, class_uid, instance_uid)

N-GET

Association.send_n_get(identifier_list, class_uid, instance_uid)

N-SET

Association.send_n_set(dataset, class_uid, instance_uid)

Where dataset is a pydicom Dataset object, query_model is a UID string, identifier_list is a list of pydicom Tag objects, event_type and action_type are ints and class_uid and instance_uid are UID strings. See the Association documentation for more information.

SCP Services

When the AE is acting as an SCP the following DIMSE-C and -N services are available to the peer once an association has been established:

DIMSE service

Intervention Event

Handler documentation

C-ECHO

evt.EVT_C_ECHO

Handle C-ECHO

C-FIND

evt.EVT_C_FIND

Handle C-FIND

C-GET

evt.EVT_C_GET

Handle C-GET

C-MOVE

evt.EVT_C_MOVE

Handle C-MOVE

C-STORE

evt.EVT_C_STORE

Handle C-STORE

N-ACTION

evt.EVT_N_ACTION

Handle N-ACTION

N-CREATE

evt.EVT_N_CREATE

Handle N-CREATE

N-DELETE

evt.EVT_N_DELETE

Handle N-DELETE

N-EVENT-REPORT

evt.EVT_N_EVENT_REPORT

Handle N-EVENT-REPORT

N-GET

evt.EVT_N_GET

Handle N-GET

N-SET

evt.EVT_N_SET

Handle N-SET

With the exception of the C-ECHO service, a user-defined callable function, handler, must be bound to the corresponding intervention event in order to complete a DIMSE service request. Events can be imported with from pynetdicom import evt and a handler can be bound to an event prior to starting an association through the evt_handlers keyword arguments in AE.start_server() and AE.associate().

When an event occurs the handler function is called and passed a single parameter, event, which is an Event object whose specific attributes are dependent on the type of event that occurred. Handlers bound to intervention events must return or yield certain values. See the handler documentation for information on what attributes and properties are available in Event for each event type and the expected returns/yields for the corresponding handlers.

Applications

Some basic DICOM applications are included with pynetdicom:

Code Examples

More code examples are available in the documentation.

Echo SCU

Send a C-ECHO request to a Verification SCP (at TCP/IP address addr, listen port number port):

from pynetdicom import AE

ae = AE(ae_title=b'MY_ECHO_SCU')
# Verification SOP Class has a UID of 1.2.840.10008.1.1
#   we can use the UID str directly when adding the requested
#   presentation context
ae.add_requested_context('1.2.840.10008.1.1')

# Associate with a peer AE
assoc = ae.associate(addr, port)

if assoc.is_established:
    # Send a DIMSE C-ECHO request to the peer
    status = assoc.send_c_echo()

    # Print the response from the peer
    if status:
        print('C-ECHO Response: 0x{0:04x}'.format(status.Status))

    # Release the association
    assoc.release()

Echo SCP

Create a blocking Echo SCP on port 11112 (you may optionally bind a handler to the evt.EVT_C_ECHO event if you want to return something other than an 0x0000 Success status):

from pynetdicom import AE, VerificationPresentationContexts

ae = AE(ae_title=b'MY_ECHO_SCP')
# Or we can use the inbuilt VerificationPresentationContexts list,
#   there's one for each of the supported Service Classes
# In this case, we are supporting any requests to use Verification SOP
#   Class in the association
ae.supported_contexts = VerificationPresentationContexts

# Start the SCP on (host, port) in blocking mode
ae.start_server(('', 11112), block=True)

Alternatively, you can start the SCP in non-blocking mode, which returns the running server instance. This can be useful when you want to run a Storage SCP and make C-MOVE requests within the same AE.

In the next example we’ll create a non-blocking Verification SCP and bind a handler for the C-ECHO service request event evt.EVT_C_ECHO that logs the requestor’s address and port number and the timestamp for the event.

import logging

from pynetdicom import AE, evt, debug_logger
from pynetdicom.sop_class import VerificationSOPClass

# Setup logging to use the StreamHandler at the debug level
debug_logger()

ae = AE(ae_title=b'MY_ECHO_SCP')
ae.add_supported_context(VerificationSOPClass)

# Implement the EVT_C_ECHO handler
def handle_echo(event, logger):
    """Handle a C-ECHO service request.

    Parameters
    ----------
    event : evt.Event
        The C-ECHO service request event, this parameter is always
        present.
    logger : logging.Logger
        The logger to use, this parameter is only present because we
        bound ``evt.EVT_C_ECHO`` using a 3-tuple.

    Returns
    -------
    int or pydicom.dataset.Dataset
        The status returned to the peer AE in the C-ECHO response.
        Must be a valid C-ECHO status value as either an ``int`` or a
        ``Dataset`` object containing an (0000,0900) *Status* element.
    """
    # Every *Event* includes `assoc` and `timestamp` attributes
    #   which are the *Association* instance the event occurred in
    #   and the *datetime.datetime* the event occurred at
    requestor = event.assoc.requestor
    timestamp = event.timestamp.strftime("%Y-%m-%d %H:%M:%S")
    msg = (
        "Received C-ECHO service request from ({}, {}) at {}"
        .format(requestor.address, requestor.port, timestamp)
    )
    logger.info(msg)

    # Return a *Success* status
    return 0x0000

# By binding using a 3-tuple we can pass extra arguments to
#   the handler
handlers = [(evt.EVT_C_ECHO, handle_echo, [logging.getLogger('pynetdicom')])]

# Start the SCP in non-blocking mode
scp = ae.start_server(('', 11112), block=False, evt_handlers=handlers)

# Associate and send a C-ECHO request to our own Verification SCP
ae.add_requested_context(VerificationSOPClass)
assoc = ae.associate('localhost', 11112)
if assoc.is_established:
    status = assoc.send_c_echo()
    assoc.release()

# Shutdown the SCP
scp.shutdown()

Storage SCU

Send the DICOM CT Image Storage dataset in file-in.dcm to a peer Storage SCP (at TCP/IP address addr, listen port number port):

from pydicom import dcmread
from pydicom.uid import ImplicitVRLittleEndian

from pynetdicom import AE, VerificationPresentationContexts
from pynetdicom.sop_class import CTImageStorage, MRImageStorage

ae = AE(ae_title=b'MY_STORAGE_SCU')
# We can also do the same thing with the requested contexts
ae.requested_contexts = VerificationPresentationContexts
# Or we can use inbuilt objects like CTImageStorage.
# The requested presentation context's transfer syntaxes can also
#   be specified using a str/UID or list of str/UIDs
ae.add_requested_context(CTImageStorage,
                         transfer_syntax=ImplicitVRLittleEndian)
# Adding a presentation context with multiple transfer syntaxes
ae.add_requested_context(MRImageStorage,
                         transfer_syntax=[ImplicitVRLittleEndian,
                                          '1.2.840.10008.1.2.1'])

assoc = ae.associate(addr, port)
if assoc.is_established:
    dataset = dcmread('file-in.dcm')
    # `status` is the response from the peer to the store request
    # but may be an empty pydicom Dataset if the peer timed out or
    # sent an invalid dataset.
    status = assoc.send_c_store(dataset)

    assoc.release()

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pynetdicom-1.5.5.tar.gz (1.5 MB view details)

Uploaded Source

Built Distribution

pynetdicom-1.5.5-py2.py3-none-any.whl (1.6 MB view details)

Uploaded Python 2 Python 3

File details

Details for the file pynetdicom-1.5.5.tar.gz.

File metadata

  • Download URL: pynetdicom-1.5.5.tar.gz
  • Upload date:
  • Size: 1.5 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.22.0 setuptools/44.0.0 requests-toolbelt/0.9.1 tqdm/4.46.1 CPython/3.8.5

File hashes

Hashes for pynetdicom-1.5.5.tar.gz
Algorithm Hash digest
SHA256 052ff79353aaa3b8a3e4c3f000535eb9a765937f056d57f2a48829b512dfc223
MD5 b08f1d5382fcb5f96bbb3b4f29a2cd1d
BLAKE2b-256 f4647fb2d309e9ebd55842c5b42384eefaf82c8ad72d8580331711416fcdbd80

See more details on using hashes here.

File details

Details for the file pynetdicom-1.5.5-py2.py3-none-any.whl.

File metadata

  • Download URL: pynetdicom-1.5.5-py2.py3-none-any.whl
  • Upload date:
  • Size: 1.6 MB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.22.0 setuptools/44.0.0 requests-toolbelt/0.9.1 tqdm/4.46.1 CPython/3.8.5

File hashes

Hashes for pynetdicom-1.5.5-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 83a6194aead39b2e876115a92d1fb027a2af81ef8b18ab17eb4aba024a0c5a9e
MD5 d950d488f88bc50176c4be2c836b83da
BLAKE2b-256 bff0aaf3c239a9f4d0a72f5f3f6c65d34dccf6fd779e2be8dbc0a97741d016bb

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page