|coverage| |unit-tests| |type-hints| |docs| |black| |pypi-versions| |python-versions| |conda| |zenodo|
.. |coverage| image:: https://codecov.io/gh/pydicom/pynetdicom/branch/main/graph/badge.svg
:target: https://codecov.io/gh/pydicom/pynetdicom
.. |unit-tests| image:: https://github.com/pydicom/pynetdicom/workflows/unit-tests/badge.svg
:target: https://github.com/pydicom/pynetdicom/actions?query=workflow%3Aunit-tests
.. |type-hints| image:: https://github.com/pydicom/pynetdicom/workflows/type-hints/badge.svg
:target: https://github.com/pydicom/pynetdicom/actions?query=workflow%3Atype-hints
.. |docs| image:: https://circleci.com/gh/pydicom/pynetdicom/tree/main.svg?style=shield
:target: https://circleci.com/gh/pydicom/pynetdicom/tree/main
.. |black| image:: https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/psf/black
.. |pypi-versions| image:: https://badge.fury.io/py/pynetdicom.svg
:target: https://badge.fury.io/py/pynetdicom
.. |python-versions| image:: https://img.shields.io/pypi/pyversions/pynetdicom.svg
:target: https://img.shields.io/pypi/pyversions/pynetdicom.svg
.. |conda| image:: https://img.shields.io/conda/vn/conda-forge/pynetdicom.svg
:target: https://anaconda.org/conda-forge/pynetdicom
.. |zenodo| image:: https://zenodo.org/badge/DOI/10.5281/zenodo.3880767.svg
:target: https://doi.org/10.5281/zenodo.3880767
pynetdicom
==========
A Python implementation of the `DICOM <https://www.dicomstandard.org>`_
networking protocol, originally based on (legacy)
`pynetdicom <https://github.com/patmun/pynetdicom_legacy>`_.
Description
-----------
`DICOM <https://www.dicomstandard.org>`_ 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 package that implements the DICOM
networking protocol. Working with
`pydicom <https://github.com/pydicom/pydicom>`_, it allows the easy creation
of DICOM *Service Class Users* (SCUs) and *Service Class Providers* (SCPs).
*pynetdicom's* main user class is
`AE <https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.ae.ApplicationEntity.html>`_
and is used to represent a DICOM Application Entity. With it you can:
- Start the application as an SCP by specifying the supported presentation
contexts then calling
`AE.start_server() <https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.ae.ApplicationEntity.html#pynetdicom.ae.ApplicationEntity.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() <https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.ae.ApplicationEntity.html#pynetdicom.ae.ApplicationEntity.associate>`_
method, which returns an
`Association <https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html#pynetdicom.association.Association>`_
thread.
Once associated, the services available to the association can
be used by sending
`DIMSE-C <https://dicom.nema.org/medical/dicom/current/output/html/part07.html#chapter_9>`_
and
`DIMSE-N <https://dicom.nema.org/medical/dicom/current/output/html/part07.html#chapter_10>`_
messages.
Documentation
-------------
The *pynetdicom*
`tutorials <https://pydicom.github.io/pynetdicom/stable/tutorials/index.html>`_,
`user guide <https://pydicom.github.io/pynetdicom/stable/user/index.html>`_,
`code examples <https://pydicom.github.io/pynetdicom/stable/examples/index.html>`_,
`application <https://pydicom.github.io/pynetdicom/stable/apps/index.html>`_ and
`API reference <https://pydicom.github.io/pynetdicom/stable/reference/index.html>`_
documentation is available for the
`current release <https://pydicom.github.io/pynetdicom/>`_ as well as the
`development version <https://pydicom.github.io/pynetdicom/dev>`_.
Installation
------------
Dependencies
~~~~~~~~~~~~
`pydicom <https://github.com/pydicom/pydicom>`_
Installing current release
~~~~~~~~~~~~~~~~~~~~~~~~~~
Using pip:
.. code-block:: sh
pip install -U pynetdicom
Using conda:
.. code-block:: sh
conda install -c conda-forge pynetdicom
For more detailed instructions, including how to install the
current development version, please see the `installation guide
<https://pydicom.github.io/pynetdicom/stable/tutorials/installation.html>`_.
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:
.. _assoc: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html
.. _echo: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html#pynetdicom.association.Association.send_c_echo
.. _find: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html#pynetdicom.association.Association.send_c_find
.. _c_get: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html#pynetdicom.association.Association.send_c_get
.. _move: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html#pynetdicom.association.Association.send_c_move
.. _store: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html#pynetdicom.association.Association.send_c_store
.. _action: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html#pynetdicom.association.Association.send_n_action
.. _create: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html#pynetdicom.association.Association.send_n_create
.. _delete: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html#pynetdicom.association.Association.send_n_delete
.. _er: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html#pynetdicom.association.Association.send_n_event_report
.. _n_get: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html#pynetdicom.association.Association.send_n_get
.. _set: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html#pynetdicom.association.Association.send_n_set
+----------------+----------------------------------------------------------------------------------------+
| DIMSE service | `Association <assoc_>`_ method |
+================+========================================================================================+
| C-ECHO | `Association.send_c_echo() <echo_>`_ |
+----------------+----------------------------------------------------------------------------------------+
| C-FIND | `Association.send_c_find(dataset, query_model) <find_>`_ |
+----------------+----------------------------------------------------------------------------------------+
| C-GET | `Association.send_c_get(dataset, query_model) <c_get_>`_ |
+----------------+----------------------------------------------------------------------------------------+
| C-MOVE | `Association.send_c_move(dataset, move_aet, query_model) <move_>`_ |
+----------------+----------------------------------------------------------------------------------------+
| C-STORE | `Association.send_c_store(dataset) <store_>`_ |
+----------------+----------------------------------------------------------------------------------------+
| N-ACTION | `Association.send_n_action(dataset, action_type, class_uid, instance_uid) <action_>`_ |
+----------------+----------------------------------------------------------------------------------------+
| N-CREATE | `Association.send_n_create(dataset, class_uid, instance_uid) <create_>`_ |
+----------------+----------------------------------------------------------------------------------------+
| N-DELETE | `Association.send_n_delete(class_uid, instance_uid) <delete_>`_ |
+----------------+----------------------------------------------------------------------------------------+
| N-EVENT-REPORT | `Association.send_n_event_report(dataset, event_type, class_uid, instance_uid) <er_>`_ |
+----------------+----------------------------------------------------------------------------------------+
| N-GET | `Association.send_n_get(identifier_list, class_uid, instance_uid) <n_get_>`_ |
+----------------+----------------------------------------------------------------------------------------+
| N-SET | `Association.send_n_set(dataset, class_uid, instance_uid) <set_>`_ |
+----------------+----------------------------------------------------------------------------------------+
Where *dataset* is a pydicom
`Dataset <https://pydicom.github.io/pydicom/stable/ref_guide.html#dataset>`_
object, *query_model* is a UID string, *identifier_list* is a list of pydicom
`Tag <https://pydicom.github.io/pydicom/stable/api_ref.html#pydicom.tag.Tag>`_
objects, *event_type* and *action_type* are ints and *class_uid* and
*instance_uid* are UID strings. See the
`Association documentation <https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html>`_
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:
.. _hecho: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom._handlers.doc_handle_echo.html
.. _hfind: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom._handlers.doc_handle_find.html
.. _hc_get: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom._handlers.doc_handle_c_get.html
.. _hmove: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom._handlers.doc_handle_move.html
.. _hstore: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom._handlers.doc_handle_store.html
.. _haction: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom._handlers.doc_handle_action.html
.. _hcreate: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom._handlers.doc_handle_create.html
.. _hdelete: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom._handlers.doc_handle_delete.html
.. _her: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom._handlers.doc_handle_event_report.html
.. _hn_get: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom._handlers.doc_handle_n_get.html
.. _hset: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom._handlers.doc_handle_set.html
+----------------+----------------------------+---------------------------------+
| DIMSE service | Intervention Event | Handler documentation |
+================+============================+=================================+
| C-ECHO | ``evt.EVT_C_ECHO`` | `Handle C-ECHO <hecho_>`_ |
+----------------+----------------------------+---------------------------------+
| C-FIND | ``evt.EVT_C_FIND`` | `Handle C-FIND <hfind_>`_ |
+----------------+----------------------------+---------------------------------+
| C-GET | ``evt.EVT_C_GET`` | `Handle C-GET <hc_get_>`_ |
+----------------+----------------------------+---------------------------------+
| C-MOVE | ``evt.EVT_C_MOVE`` | `Handle C-MOVE <hmove_>`_ |
+----------------+----------------------------+---------------------------------+
| C-STORE | ``evt.EVT_C_STORE`` | `Handle C-STORE <hstore_>`_ |
+----------------+----------------------------+---------------------------------+
| N-ACTION | ``evt.EVT_N_ACTION`` | `Handle N-ACTION <haction_>`_ |
+----------------+----------------------------+---------------------------------+
| N-CREATE | ``evt.EVT_N_CREATE`` | `Handle N-CREATE <hcreate_>`_ |
+----------------+----------------------------+---------------------------------+
| N-DELETE | ``evt.EVT_N_DELETE`` | `Handle N-DELETE <hdelete_>`_ |
+----------------+----------------------------+---------------------------------+
| N-EVENT-REPORT | ``evt.EVT_N_EVENT_REPORT`` | `Handle N-EVENT-REPORT <her_>`_ |
+----------------+----------------------------+---------------------------------+
| N-GET | ``evt.EVT_N_GET`` | `Handle N-GET <hn_get_>`_ |
+----------------+----------------------------+---------------------------------+
| N-SET | ``evt.EVT_N_SET`` | `Handle N-SET <hset_>`_ |
+----------------+----------------------------+---------------------------------+
With the exception of the C-ECHO service, a user-defined callable function,
*handler*, must be bound to the corresponding
`intervention event <https://pydicom.github.io/pynetdicom/stable/user/events#intervention-events>`_
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() <https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.ae.ApplicationEntity.html#pynetdicom.ae.ApplicationEntity.start_server>`_
and
`AE.associate() <https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.ae.ApplicationEntity.html#pynetdicom.ae.ApplicationEntity.associate>`_.
When an event occurs the *handler* function is called and passed a single
parameter, *event*, which is an
`Event <https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.events.Event.html>`_
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 <https://pydicom.github.io/pynetdicom/stable/reference/events>`_
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*:
* `echoscp <https://pydicom.github.io/pynetdicom/stable/apps/echoscp.html>`_
* `echoscu <https://pydicom.github.io/pynetdicom/stable/apps/echoscu.html>`_
* `findscu <https://pydicom.github.io/pynetdicom/stable/apps/findscu.html>`_
* `getscu <https://pydicom.github.io/pynetdicom/stable/apps/getscu.html>`_
* `qrscp <https://pydicom.github.io/pynetdicom/stable/apps/qrscp.html>`_
(requires `sqlalchemy <https://www.sqlalchemy.org/>`_)
* `movescu <https://pydicom.github.io/pynetdicom/stable/apps/movescu.html>`_
* `storescp <https://pydicom.github.io/pynetdicom/stable/apps/storescp.html>`_
* `storescu <https://pydicom.github.io/pynetdicom/stable/apps/storescu.html>`_
Code Examples
-------------
More
`code examples <https://pydicom.github.io/pynetdicom/stable/examples/index.html>`_
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*):
.. code-block:: python
from pynetdicom import AE
ae = AE(ae_title='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):
.. code-block:: python
from pynetdicom import AE, VerificationPresentationContexts
ae = AE(ae_title='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(("localhost", 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.
.. code-block:: python
import logging
from pynetdicom import AE, evt, debug_logger
from pynetdicom.sop_class import Verification
# Setup logging to use the StreamHandler at the debug level
debug_logger()
ae = AE(ae_title='MY_ECHO_SCP')
ae.add_supported_context(Verification)
# 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(("localhost", 11112), block=False, evt_handlers=handlers)
# Associate and send a C-ECHO request to our own Verification SCP
ae.add_requested_context(Verification)
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*):
.. code-block:: python
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='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()
Raw data
{
"_id": null,
"home_page": "https://github.com/pydicom/pynetdicom",
"name": "pynetdicom",
"maintainer": "scaramallion",
"docs_url": "https://pythonhosted.org/pynetdicom/",
"requires_python": "<4.0,>=3.10",
"maintainer_email": "scaramallion@users.noreply.github.com",
"keywords": "dicom, networking, pydicom",
"author": "pynetdicom contributors",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/bf/0e/6209b1957aad95564a72c998dd42846c75b2073c763ec4bc5964917ba8d3/pynetdicom-2.1.1.tar.gz",
"platform": null,
"description": "|coverage| |unit-tests| |type-hints| |docs| |black| |pypi-versions| |python-versions| |conda| |zenodo|\n\n.. |coverage| image:: https://codecov.io/gh/pydicom/pynetdicom/branch/main/graph/badge.svg\n :target: https://codecov.io/gh/pydicom/pynetdicom\n\n.. |unit-tests| image:: https://github.com/pydicom/pynetdicom/workflows/unit-tests/badge.svg\n :target: https://github.com/pydicom/pynetdicom/actions?query=workflow%3Aunit-tests\n\n.. |type-hints| image:: https://github.com/pydicom/pynetdicom/workflows/type-hints/badge.svg\n :target: https://github.com/pydicom/pynetdicom/actions?query=workflow%3Atype-hints\n\n.. |docs| image:: https://circleci.com/gh/pydicom/pynetdicom/tree/main.svg?style=shield\n :target: https://circleci.com/gh/pydicom/pynetdicom/tree/main\n\n.. |black| image:: https://img.shields.io/badge/code%20style-black-000000.svg\n :target: https://github.com/psf/black\n\n.. |pypi-versions| image:: https://badge.fury.io/py/pynetdicom.svg\n :target: https://badge.fury.io/py/pynetdicom\n\n.. |python-versions| image:: https://img.shields.io/pypi/pyversions/pynetdicom.svg\n :target: https://img.shields.io/pypi/pyversions/pynetdicom.svg\n\n.. |conda| image:: https://img.shields.io/conda/vn/conda-forge/pynetdicom.svg\n :target: https://anaconda.org/conda-forge/pynetdicom\n\n.. |zenodo| image:: https://zenodo.org/badge/DOI/10.5281/zenodo.3880767.svg\n :target: https://doi.org/10.5281/zenodo.3880767\n\n\npynetdicom\n==========\n\nA Python implementation of the `DICOM <https://www.dicomstandard.org>`_\nnetworking protocol, originally based on (legacy)\n`pynetdicom <https://github.com/patmun/pynetdicom_legacy>`_.\n\n\nDescription\n-----------\n\n`DICOM <https://www.dicomstandard.org>`_ is the international standard for\nmedical images and related information. It defines the formats and communication\nprotocols for media exchange in radiology, cardiology, radiotherapy and other\nmedical domains.\n\n*pynetdicom* is a pure Python package that implements the DICOM\nnetworking protocol. Working with\n`pydicom <https://github.com/pydicom/pydicom>`_, it allows the easy creation\nof DICOM *Service Class Users* (SCUs) and *Service Class Providers* (SCPs).\n\n*pynetdicom's* main user class is\n`AE <https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.ae.ApplicationEntity.html>`_\nand is used to represent a DICOM Application Entity. With it you can:\n\n- Start the application as an SCP by specifying the supported presentation\n contexts then calling\n `AE.start_server() <https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.ae.ApplicationEntity.html#pynetdicom.ae.ApplicationEntity.start_server>`_\n and waiting for incoming association requests\n- Use the application as an SCU by specifying the presentation contexts you\n want the peer SCP to support, then requesting an association\n via the\n `AE.associate() <https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.ae.ApplicationEntity.html#pynetdicom.ae.ApplicationEntity.associate>`_\n method, which returns an\n `Association <https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html#pynetdicom.association.Association>`_\n thread.\n\nOnce associated, the services available to the association can\nbe used by sending\n`DIMSE-C <https://dicom.nema.org/medical/dicom/current/output/html/part07.html#chapter_9>`_\nand\n`DIMSE-N <https://dicom.nema.org/medical/dicom/current/output/html/part07.html#chapter_10>`_\nmessages.\n\nDocumentation\n-------------\nThe *pynetdicom*\n`tutorials <https://pydicom.github.io/pynetdicom/stable/tutorials/index.html>`_,\n`user guide <https://pydicom.github.io/pynetdicom/stable/user/index.html>`_,\n`code examples <https://pydicom.github.io/pynetdicom/stable/examples/index.html>`_,\n`application <https://pydicom.github.io/pynetdicom/stable/apps/index.html>`_ and\n`API reference <https://pydicom.github.io/pynetdicom/stable/reference/index.html>`_\ndocumentation is available for the\n`current release <https://pydicom.github.io/pynetdicom/>`_ as well as the\n`development version <https://pydicom.github.io/pynetdicom/dev>`_.\n\nInstallation\n------------\nDependencies\n~~~~~~~~~~~~\n`pydicom <https://github.com/pydicom/pydicom>`_\n\nInstalling current release\n~~~~~~~~~~~~~~~~~~~~~~~~~~\nUsing pip:\n\n.. code-block:: sh\n\n pip install -U pynetdicom\n\nUsing conda:\n\n.. code-block:: sh\n\n conda install -c conda-forge pynetdicom\n\nFor more detailed instructions, including how to install the\ncurrent development version, please see the `installation guide\n<https://pydicom.github.io/pynetdicom/stable/tutorials/installation.html>`_.\n\n\nSupported DIMSE Services\n------------------------\nSCU Services\n~~~~~~~~~~~~\n\nWhen the AE is acting as an SCU and an association has been established with a\npeer SCP, the following DIMSE-C and -N services are available:\n\n.. _assoc: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html\n.. _echo: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html#pynetdicom.association.Association.send_c_echo\n.. _find: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html#pynetdicom.association.Association.send_c_find\n.. _c_get: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html#pynetdicom.association.Association.send_c_get\n.. _move: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html#pynetdicom.association.Association.send_c_move\n.. _store: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html#pynetdicom.association.Association.send_c_store\n.. _action: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html#pynetdicom.association.Association.send_n_action\n.. _create: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html#pynetdicom.association.Association.send_n_create\n.. _delete: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html#pynetdicom.association.Association.send_n_delete\n.. _er: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html#pynetdicom.association.Association.send_n_event_report\n.. _n_get: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html#pynetdicom.association.Association.send_n_get\n.. _set: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html#pynetdicom.association.Association.send_n_set\n\n\n+----------------+----------------------------------------------------------------------------------------+\n| DIMSE service | `Association <assoc_>`_ method |\n+================+========================================================================================+\n| C-ECHO | `Association.send_c_echo() <echo_>`_ |\n+----------------+----------------------------------------------------------------------------------------+\n| C-FIND | `Association.send_c_find(dataset, query_model) <find_>`_ |\n+----------------+----------------------------------------------------------------------------------------+\n| C-GET | `Association.send_c_get(dataset, query_model) <c_get_>`_ |\n+----------------+----------------------------------------------------------------------------------------+\n| C-MOVE | `Association.send_c_move(dataset, move_aet, query_model) <move_>`_ |\n+----------------+----------------------------------------------------------------------------------------+\n| C-STORE | `Association.send_c_store(dataset) <store_>`_ |\n+----------------+----------------------------------------------------------------------------------------+\n| N-ACTION | `Association.send_n_action(dataset, action_type, class_uid, instance_uid) <action_>`_ |\n+----------------+----------------------------------------------------------------------------------------+\n| N-CREATE | `Association.send_n_create(dataset, class_uid, instance_uid) <create_>`_ |\n+----------------+----------------------------------------------------------------------------------------+\n| N-DELETE | `Association.send_n_delete(class_uid, instance_uid) <delete_>`_ |\n+----------------+----------------------------------------------------------------------------------------+\n| N-EVENT-REPORT | `Association.send_n_event_report(dataset, event_type, class_uid, instance_uid) <er_>`_ |\n+----------------+----------------------------------------------------------------------------------------+\n| N-GET | `Association.send_n_get(identifier_list, class_uid, instance_uid) <n_get_>`_ |\n+----------------+----------------------------------------------------------------------------------------+\n| N-SET | `Association.send_n_set(dataset, class_uid, instance_uid) <set_>`_ |\n+----------------+----------------------------------------------------------------------------------------+\n\nWhere *dataset* is a pydicom\n`Dataset <https://pydicom.github.io/pydicom/stable/ref_guide.html#dataset>`_\nobject, *query_model* is a UID string, *identifier_list* is a list of pydicom\n`Tag <https://pydicom.github.io/pydicom/stable/api_ref.html#pydicom.tag.Tag>`_\nobjects, *event_type* and *action_type* are ints and *class_uid* and\n*instance_uid* are UID strings. See the\n`Association documentation <https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.association.Association.html>`_\nfor more information.\n\n\nSCP Services\n~~~~~~~~~~~~\n\nWhen the AE is acting as an SCP the following DIMSE-C and -N services are\navailable to the peer once an association has been established:\n\n.. _hecho: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom._handlers.doc_handle_echo.html\n.. _hfind: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom._handlers.doc_handle_find.html\n.. _hc_get: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom._handlers.doc_handle_c_get.html\n.. _hmove: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom._handlers.doc_handle_move.html\n.. _hstore: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom._handlers.doc_handle_store.html\n.. _haction: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom._handlers.doc_handle_action.html\n.. _hcreate: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom._handlers.doc_handle_create.html\n.. _hdelete: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom._handlers.doc_handle_delete.html\n.. _her: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom._handlers.doc_handle_event_report.html\n.. _hn_get: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom._handlers.doc_handle_n_get.html\n.. _hset: https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom._handlers.doc_handle_set.html\n\n+----------------+----------------------------+---------------------------------+\n| DIMSE service | Intervention Event | Handler documentation |\n+================+============================+=================================+\n| C-ECHO | ``evt.EVT_C_ECHO`` | `Handle C-ECHO <hecho_>`_ |\n+----------------+----------------------------+---------------------------------+\n| C-FIND | ``evt.EVT_C_FIND`` | `Handle C-FIND <hfind_>`_ |\n+----------------+----------------------------+---------------------------------+\n| C-GET | ``evt.EVT_C_GET`` | `Handle C-GET <hc_get_>`_ |\n+----------------+----------------------------+---------------------------------+\n| C-MOVE | ``evt.EVT_C_MOVE`` | `Handle C-MOVE <hmove_>`_ |\n+----------------+----------------------------+---------------------------------+\n| C-STORE | ``evt.EVT_C_STORE`` | `Handle C-STORE <hstore_>`_ |\n+----------------+----------------------------+---------------------------------+\n| N-ACTION | ``evt.EVT_N_ACTION`` | `Handle N-ACTION <haction_>`_ |\n+----------------+----------------------------+---------------------------------+\n| N-CREATE | ``evt.EVT_N_CREATE`` | `Handle N-CREATE <hcreate_>`_ |\n+----------------+----------------------------+---------------------------------+\n| N-DELETE | ``evt.EVT_N_DELETE`` | `Handle N-DELETE <hdelete_>`_ |\n+----------------+----------------------------+---------------------------------+\n| N-EVENT-REPORT | ``evt.EVT_N_EVENT_REPORT`` | `Handle N-EVENT-REPORT <her_>`_ |\n+----------------+----------------------------+---------------------------------+\n| N-GET | ``evt.EVT_N_GET`` | `Handle N-GET <hn_get_>`_ |\n+----------------+----------------------------+---------------------------------+\n| N-SET | ``evt.EVT_N_SET`` | `Handle N-SET <hset_>`_ |\n+----------------+----------------------------+---------------------------------+\n\n\nWith the exception of the C-ECHO service, a user-defined callable function,\n*handler*, must be bound to the corresponding\n`intervention event <https://pydicom.github.io/pynetdicom/stable/user/events#intervention-events>`_\nin order to complete a DIMSE service request. Events\ncan be imported with ``from pynetdicom import evt`` and a handler can be\nbound to an event prior to starting an association through the *evt_handlers*\nkeyword arguments in\n`AE.start_server() <https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.ae.ApplicationEntity.html#pynetdicom.ae.ApplicationEntity.start_server>`_\nand\n`AE.associate() <https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.ae.ApplicationEntity.html#pynetdicom.ae.ApplicationEntity.associate>`_.\n\nWhen an event occurs the *handler* function is called and passed a single\nparameter, *event*, which is an\n`Event <https://pydicom.github.io/pynetdicom/stable/reference/generated/pynetdicom.events.Event.html>`_\nobject whose specific attributes\nare dependent on the type of event that occurred. Handlers bound to\nintervention events must return or yield certain values. See the\n`handler documentation <https://pydicom.github.io/pynetdicom/stable/reference/events>`_\nfor information on what attributes and properties are available in ``Event``\nfor each event type and the expected returns/yields for the\ncorresponding handlers.\n\nApplications\n------------\n\nSome basic DICOM applications are included with *pynetdicom*:\n\n* `echoscp <https://pydicom.github.io/pynetdicom/stable/apps/echoscp.html>`_\n* `echoscu <https://pydicom.github.io/pynetdicom/stable/apps/echoscu.html>`_\n* `findscu <https://pydicom.github.io/pynetdicom/stable/apps/findscu.html>`_\n* `getscu <https://pydicom.github.io/pynetdicom/stable/apps/getscu.html>`_\n* `qrscp <https://pydicom.github.io/pynetdicom/stable/apps/qrscp.html>`_\n (requires `sqlalchemy <https://www.sqlalchemy.org/>`_)\n* `movescu <https://pydicom.github.io/pynetdicom/stable/apps/movescu.html>`_\n* `storescp <https://pydicom.github.io/pynetdicom/stable/apps/storescp.html>`_\n* `storescu <https://pydicom.github.io/pynetdicom/stable/apps/storescu.html>`_\n\nCode Examples\n-------------\n\nMore\n`code examples <https://pydicom.github.io/pynetdicom/stable/examples/index.html>`_\nare available in the documentation.\n\nEcho SCU\n~~~~~~~~\nSend a C-ECHO request to a Verification SCP (at TCP/IP address\n*addr*, listen port number *port*):\n\n.. code-block:: python\n\n from pynetdicom import AE\n\n ae = AE(ae_title='MY_ECHO_SCU')\n # Verification SOP Class has a UID of 1.2.840.10008.1.1\n # we can use the UID str directly when adding the requested\n # presentation context\n ae.add_requested_context('1.2.840.10008.1.1')\n\n # Associate with a peer AE\n assoc = ae.associate(addr, port)\n\n if assoc.is_established:\n # Send a DIMSE C-ECHO request to the peer\n status = assoc.send_c_echo()\n\n # Print the response from the peer\n if status:\n print('C-ECHO Response: 0x{0:04x}'.format(status.Status))\n\n # Release the association\n assoc.release()\n\nEcho SCP\n~~~~~~~~\nCreate a blocking Echo SCP on port ``11112`` (you may optionally\nbind a handler to the ``evt.EVT_C_ECHO`` event if you want to return something\nother than an ``0x0000`` *Success* status):\n\n.. code-block:: python\n\n from pynetdicom import AE, VerificationPresentationContexts\n\n ae = AE(ae_title='MY_ECHO_SCP')\n # Or we can use the inbuilt VerificationPresentationContexts list,\n # there's one for each of the supported Service Classes\n # In this case, we are supporting any requests to use Verification SOP\n # Class in the association\n ae.supported_contexts = VerificationPresentationContexts\n\n # Start the SCP on (host, port) in blocking mode\n ae.start_server((\"localhost\", 11112), block=True)\n\nAlternatively, you can start the SCP in non-blocking mode, which returns the\nrunning server instance. This can be useful when you want to run a Storage SCP\nand make C-MOVE requests within the same AE.\n\nIn the next example we'll create a non-blocking Verification SCP and bind a\nhandler for the C-ECHO service request event ``evt.EVT_C_ECHO`` that logs the\nrequestor's address and port number and the timestamp for the event.\n\n.. code-block:: python\n\n import logging\n\n from pynetdicom import AE, evt, debug_logger\n from pynetdicom.sop_class import Verification\n\n # Setup logging to use the StreamHandler at the debug level\n debug_logger()\n\n ae = AE(ae_title='MY_ECHO_SCP')\n ae.add_supported_context(Verification)\n\n # Implement the EVT_C_ECHO handler\n def handle_echo(event, logger):\n \"\"\"Handle a C-ECHO service request.\n\n Parameters\n ----------\n event : evt.Event\n The C-ECHO service request event, this parameter is always\n present.\n logger : logging.Logger\n The logger to use, this parameter is only present because we\n bound ``evt.EVT_C_ECHO`` using a 3-tuple.\n\n Returns\n -------\n int or pydicom.dataset.Dataset\n The status returned to the peer AE in the C-ECHO response.\n Must be a valid C-ECHO status value as either an ``int`` or a\n ``Dataset`` object containing an (0000,0900) *Status* element.\n \"\"\"\n # Every *Event* includes `assoc` and `timestamp` attributes\n # which are the *Association* instance the event occurred in\n # and the *datetime.datetime* the event occurred at\n requestor = event.assoc.requestor\n timestamp = event.timestamp.strftime(\"%Y-%m-%d %H:%M:%S\")\n msg = (\n \"Received C-ECHO service request from ({}, {}) at {}\"\n .format(requestor.address, requestor.port, timestamp)\n )\n logger.info(msg)\n\n # Return a *Success* status\n return 0x0000\n\n # By binding using a 3-tuple we can pass extra arguments to\n # the handler\n handlers = [(evt.EVT_C_ECHO, handle_echo, [logging.getLogger('pynetdicom')])]\n\n # Start the SCP in non-blocking mode\n scp = ae.start_server((\"localhost\", 11112), block=False, evt_handlers=handlers)\n\n # Associate and send a C-ECHO request to our own Verification SCP\n ae.add_requested_context(Verification)\n assoc = ae.associate('localhost', 11112)\n if assoc.is_established:\n status = assoc.send_c_echo()\n assoc.release()\n\n # Shutdown the SCP\n scp.shutdown()\n\nStorage SCU\n~~~~~~~~~~~\nSend the DICOM *CT Image Storage* dataset in *file-in.dcm* to a peer Storage\nSCP (at TCP/IP address *addr*, listen port number *port*):\n\n.. code-block:: python\n\n from pydicom import dcmread\n from pydicom.uid import ImplicitVRLittleEndian\n\n from pynetdicom import AE, VerificationPresentationContexts\n from pynetdicom.sop_class import CTImageStorage, MRImageStorage\n\n ae = AE(ae_title='MY_STORAGE_SCU')\n # We can also do the same thing with the requested contexts\n ae.requested_contexts = VerificationPresentationContexts\n # Or we can use inbuilt objects like CTImageStorage.\n # The requested presentation context's transfer syntaxes can also\n # be specified using a str/UID or list of str/UIDs\n ae.add_requested_context(CTImageStorage,\n transfer_syntax=ImplicitVRLittleEndian)\n # Adding a presentation context with multiple transfer syntaxes\n ae.add_requested_context(MRImageStorage,\n transfer_syntax=[ImplicitVRLittleEndian,\n '1.2.840.10008.1.2.1'])\n\n assoc = ae.associate(addr, port)\n if assoc.is_established:\n dataset = dcmread('file-in.dcm')\n # `status` is the response from the peer to the store request\n # but may be an empty pydicom Dataset if the peer timed out or\n # sent an invalid dataset.\n status = assoc.send_c_store(dataset)\n\n assoc.release()\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "A Python implementation of the DICOM networking protocol",
"version": "2.1.1",
"project_urls": {
"Documentation": "https://pydicom.github.io/pynetdicom",
"Homepage": "https://github.com/pydicom/pynetdicom"
},
"split_keywords": [
"dicom",
" networking",
" pydicom"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "be39626a2e5da38dc04d5296e61f083a13f7b055c82843a911a7138424aef285",
"md5": "693a0535833ad8617ed4f5877a7e8aa7",
"sha256": "598910d65712327e478dfd59696703143e8f2531dfb409e60c3b8820d86bae4f"
},
"downloads": -1,
"filename": "pynetdicom-2.1.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "693a0535833ad8617ed4f5877a7e8aa7",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.10",
"size": 1643138,
"upload_time": "2024-07-28T01:36:27",
"upload_time_iso_8601": "2024-07-28T01:36:27.242880Z",
"url": "https://files.pythonhosted.org/packages/be/39/626a2e5da38dc04d5296e61f083a13f7b055c82843a911a7138424aef285/pynetdicom-2.1.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "bf0e6209b1957aad95564a72c998dd42846c75b2073c763ec4bc5964917ba8d3",
"md5": "5f0fff18b88fdffade8c80605f9e7226",
"sha256": "9671fbaeefd7ed6491bb128e056d58862872b4b2335d4bbe44bbda9198cdbfea"
},
"downloads": -1,
"filename": "pynetdicom-2.1.1.tar.gz",
"has_sig": false,
"md5_digest": "5f0fff18b88fdffade8c80605f9e7226",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.10",
"size": 1567394,
"upload_time": "2024-07-28T01:36:29",
"upload_time_iso_8601": "2024-07-28T01:36:29.396371Z",
"url": "https://files.pythonhosted.org/packages/bf/0e/6209b1957aad95564a72c998dd42846c75b2073c763ec4bc5964917ba8d3/pynetdicom-2.1.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-07-28 01:36:29",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "pydicom",
"github_project": "pynetdicom",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"circle": true,
"lcname": "pynetdicom"
}