{"id":10116,"library":"pynetdicom","title":"pynetdicom: DICOM Networking Protocol","description":"pynetdicom is a Python implementation of the DICOM networking protocol, allowing developers to create DICOM Service Class Users (SCUs) and Service Class Providers (SCPs). It handles DICOM association negotiation, message exchange, and event management. The current version is 3.0.4, and it generally follows a release cadence tied to bug fixes and minor feature enhancements, with major versions introducing significant architectural changes.","status":"active","version":"3.0.4","language":"en","source_language":"en","source_url":"https://github.com/pynetdicom/pynetdicom","tags":["DICOM","networking","medical imaging","pydicom","PACS"],"install":[{"cmd":"pip install pynetdicom","lang":"bash","label":"Core installation"},{"cmd":"pip install pynetdicom[scu]","lang":"bash","label":"For SCU applications (includes pydicom)"},{"cmd":"pip install pynetdicom[scp]","lang":"bash","label":"For SCP applications (includes pydicom)"},{"cmd":"pip install pynetdicom[tls]","lang":"bash","label":"For TLS/SSL support (includes cryptography)"}],"dependencies":[{"reason":"Required for working with actual DICOM datasets (e.g., sending/receiving images). While not a strict runtime dependency for the network protocol itself, almost all practical applications of pynetdicom will need it.","package":"pydicom","optional":false},{"reason":"Required for secure communication using TLS/SSL (dicomweb-tls).","package":"cryptography","optional":true},{"reason":"Recommended for efficient handling of pixel data arrays within DICOM datasets.","package":"numpy","optional":true}],"imports":[{"note":"In v3.0+, AE is directly in the top-level package, not in 'apps'.","wrong":"from pynetdicom.apps import AE","symbol":"AE","correct":"from pynetdicom import AE"},{"note":"Event handlers in v3.0+ use `evt` constants and `AE.register_event_handler` instead of directly overriding internal AE methods.","wrong":"ae._handle_association_release","symbol":"evt","correct":"from pynetdicom import evt"},{"note":"While `VerificationSOPClass` exists, `VerificationPresentationContexts` provides a pre-configured list of contexts ready for use.","wrong":"from pynetdicom.sop_class import VerificationSOPClass","symbol":"VerificationPresentationContexts","correct":"from pynetdicom.presentation import VerificationPresentationContexts"},{"note":"Used for pre-configured presentation contexts for common storage SOP classes.","symbol":"StoragePresentationContexts","correct":"from pynetdicom.presentation import StoragePresentationContexts"}],"quickstart":{"code":"from pynetdicom import AE, VerificationPresentationContexts\nimport logging\nimport os\n\n# Configure logging to see association details (optional but recommended)\nlogging.basicConfig(level=logging.INFO)\n\n# Initialise the Application Entity (AE) for the SCU\n# AE Titles must be bytes objects (e.g., b'MY_AE_TITLE')\nscu_ae_title = os.environ.get('PYNETDICOM_AE_TITLE_SCU', 'PYNETDICOM_SCU').encode('utf-8')\nae = AE(ae_title=scu_ae_title)\n\n# Add a supported presentation context for the Verification SOP Class (C-ECHO)\n# This tells the AE what services it can request/provide.\nae.add_supported_context(VerificationPresentationContexts[0])\n\n# Define the target SCP's details (can be read from environment variables for flexibility)\ntarget_ip = os.environ.get('PYNETDICOM_TARGET_IP', '127.0.0.1')\ntarget_port = int(os.environ.get('PYNETDICOM_TARGET_PORT', '11112'))\ntarget_ae_title = os.environ.get('PYNETDICOM_TARGET_AE_TITLE', 'ANY_SCP_AE').encode('utf-8')\n\nprint(f\"\\nAttempting to associate {scu_ae_title.decode()} with {target_ae_title.decode()} at {target_ip}:{target_port}...\")\nprint(\"NOTE: Ensure a DICOM SCP is running at this address and listening on the specified port.\")\n\n# Attempt to establish an association with the remote AE (SCP)\nassoc = ae.associate(target_ip, target_port, ae_title=target_ae_title)\n\nif assoc.is_established:\n    print('\\nAssociation established with peer.')\n    # Send a C-ECHO request to verify connection\n    status = assoc.send_c_echo()\n    print(f'C-ECHO response status: {status}')\n    # Release the association gracefully\n    assoc.release()\n    print('Association released.')\nelse:\n    print('\\nAssociation rejected, aborted or never connected.')\n\n# Clean up any resources (e.g., server threads) associated with the AE\nae.shutdown()\n","lang":"python","description":"This quickstart demonstrates how to create a simple DICOM Service Class User (SCU) that establishes an association with a remote DICOM Service Class Provider (SCP) and sends a C-ECHO request (a DICOM 'ping'). It uses environment variables for configuration, making it runnable without modification."},"warnings":[{"fix":"Install `pydicom` separately: `pip install pydicom` or use the extra `pip install pynetdicom[scu]` or `pip install pynetdicom[scp]`.","message":"pynetdicom v3.0.0 and later no longer bundle pydicom. If you need to work with actual DICOM datasets (e.g., sending/receiving images), you must explicitly install `pydicom`.","severity":"breaking","affected_versions":"3.0.0+"},{"fix":"Migrate your event handler code. Example: `ae.register_event_handler(evt.EVT_C_STORE, my_c_store_handler)`.","message":"The event handling API changed significantly in v3.0.0. Instead of overriding internal `_handle_*` methods, event handlers are now registered using `AE.register_event_handler` with `evt.EVT_*` constants.","severity":"breaking","affected_versions":"3.0.0+"},{"fix":"Always convert your AE titles to bytes: `AE(ae_title=b'MY_AE_TITLE')` or `my_string.encode('utf-8')`.","message":"DICOM AE Titles must be `bytes` objects (e.g., `b'MY_AE'`), not strings. Using a string will result in a `TypeError`.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Ensure you add the correct `PresentationContext` for each SOP Class you intend to use via `ae.add_supported_context()` before associating. Use helper lists like `VerificationPresentationContexts` and `StoragePresentationContexts`.","message":"Incorrect or missing Presentation Contexts are a common cause of 'Association Rejected' errors. Each DICOM service (C-ECHO, C-STORE, etc.) requires a specific Presentation Context to be proposed and accepted.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Always call `ae.shutdown()` at the end of your application's lifecycle for the `AE` instance.","message":"Failure to call `ae.shutdown()` after an `AE` object is no longer needed can lead to lingering server threads, preventing the program from exiting cleanly or consuming resources.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-17T00:00:00.000Z","next_check":"2026-07-16T00:00:00.000Z","problems":[{"fix":"Check that your `ae.add_supported_context()` calls match what the remote AE supports. Ensure AE titles are correct and formatted as `bytes`. Verify TLS/SSL settings if applicable. Check the SCP's logs for a more specific reason for rejection.","cause":"The remote AE rejected the association. Common reasons include unsupported presentation contexts, incorrect AE titles, or security issues (e.g., TLS mismatch).","error":"Association Rejected (0x01)"},{"fix":"Encode your AE titles to bytes: `AE(ae_title=b'MY_AE_TITLE')` or `ae.associate(..., ae_title=my_string.encode('utf-8'))`.","cause":"An AE title (either for the local AE or the remote AE in `ae.associate`) was provided as a Python string instead of a `bytes` object.","error":"TypeError: a bytes-like object is required, not 'str'"},{"fix":"Before associating, add the required presentation context: `ae.add_supported_context(VerificationPresentationContexts[0])` for C-ECHO, or similar for other services.","cause":"You attempted to send a C-ECHO (or similar service) without having an accepted presentation context for the corresponding SOP Class.","error":"ValueError: No Presentation Context for Verification SOP Class"},{"fix":"Always call `ae.shutdown()` when your `AE` instance is no longer needed, typically at the end of your script or within a `finally` block.","cause":"The `AE` object was garbage collected or the program exited without explicitly calling its `shutdown()` method, leaving internal threads or resources open.","error":"RuntimeWarning: You have not called ae.shutdown(). This can lead to uncleaned resources and your program hanging."}]}