dicom_echo
A lightweight, cross-platform, blazingly fast implementation of the C-ECHO
1 DICOM procedure. 🔥
This package implements a service class user (SCU)2 app which functions like a ping
, testing that the peer service class provider (SCP)3 is accepting associations for the given AE titles4.
Both a simple CLI and a Python API are provided for easy integration with your DICOM projects.
Installation
pipx
is recommended to install dicom-echo
as a standalone CLI utility:
pipx install dicom-echo
# or if integrating with another Python project:
pip3 install dicom-echo
CLI Usage
To send a C-ECHO
request to localhost:11111
:
❯ dicom-echo localhost:11111
✅ Success
❯ dicom-echo --help
Usage: dicom-echo [OPTIONS] HOST
Send a `C-ECHO` request to the given address.
The `C-ECHO` procedure functions like a `ping`, serving to test that the peer SCP is
accepting associations.
This command will fail if the peer SCP is unreachable or rejects the association request
for the given AE titles.
Reference: https://www.dicomstandard.org/standards/view/message-exchange#sect_9.1.5
╭─ Arguments ──────────────────────────────────────────────────────────────────────────────╮
│ * host TEXT The socket address of the peer SCP: {host}:{port} │
│ Optionally, the AE title may be included: {AE title}@{host}:{port} │
│ [required] │
╰──────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────────────────╮
│ --version -V display the version of this program │
│ --install-completion Install completion for the current shell. │
│ --show-completion Show completion for the current shell, to copy it or │
│ customize the installation. │
│ --help -h Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────────╯
╭─ DICOM Options ──────────────────────────────────────────────────────────────────────────╮
│ --called,--called-ae-title -aec TEXT peer AE title of the host SCP │
│ [default: ANY-SCP] │
│ --calling,--calling-ae-title -aet TEXT the AE title of this client │
│ [default: ECHOSCU] │
│ --id,--message-id -id INTEGER the message ID to send [default: 1] │
╰──────────────────────────────────────────────────────────────────────────────────────────╯
API Usage
The dicom_echo
module provides a simple API for sending C-ECHO
requests:
>>> import dicom_echo as echo
>>> echo.send(address)
0
See the API documentation for more details.
Submodules
dicom_echo.backend
This module is built with Rust and provides the core functionality for sending C-ECHO
messages. See
/doc/backend/ for the crate's documentation.
dicom_echo.cli
A simple CLI for sending C-ECHO
messages. Built with typer
.
-
for additional details, see 9.3.5
C-ECHO
protocol | DICOM PS3.7 2024c - Message Exchange ↩ -
6.7 Service Class Specification | DICOM PS3.4 2024c - Service Class Specifications for the definitions of service class user (SCU) and service class provider (SCP):
The SCU or user agent acts as the 'client,' while the SCP or origin server acts as the 'server'. For DIMSE based services the SCU/SCP roles are determined during Association establishment
-
6.7 Service Class Specification | DICOM PS3.4 2024c - Service Class Specifications for the definitions of service class user (SCU) and service class provider (SCP):
The SCU or user agent acts as the 'client,' while the SCP or origin server acts as the 'server'. For DIMSE based services the SCU/SCP roles are determined during Association establishment
-
A DICOM Application Entity Title uniquely identifies a service or application on a specific system in the network.
1""".. include:: ../../README.md 2 :start-line: 2 3 4# Submodules 5 6## `dicom_echo.backend` 7 8This module is built with Rust and provides the core functionality for sending `C-ECHO` messages. See 9[/doc/backend/](./doc/backend/index.html) for the crate's documentation. 10 11## `dicom_echo.cli` 12 13A simple CLI for sending `C-ECHO` messages. Built with `typer`. 14""" # noqa: D205, D415 15 16from __future__ import annotations 17 18import sys 19from typing import Literal 20 21if not sys.argv[0].endswith('pdoc'): 22 from dicom_echo.backend import ( # pylint: disable=no-name-in-module 23 DEFAULT_CALLED_AE_TITLE, 24 DEFAULT_CALLING_AE_TITLE, 25 ) 26 from dicom_echo.backend import send as __send # pylint: disable=no-name-in-module 27else: # pragma: no cover 28 # copy `backend.pyi` contents so the documentation can be built without cargo 29 30 DEFAULT_CALLED_AE_TITLE: Literal['ANY-SCP'] = 'ANY-SCP' # type: ignore[no-redef] 31 """By default, specify this AE title for the target SCP.""" 32 33 DEFAULT_CALLING_AE_TITLE: Literal['ECHOSCU'] = 'ECHOSCU' # type: ignore[no-redef] 34 """By default, specify this AE title for the SCU sending the `C-ECHO` message.""" 35 36 def __send( 37 address: str, 38 /, 39 called_ae_title: str = DEFAULT_CALLED_AE_TITLE, 40 calling_ae_title: str = DEFAULT_CALLING_AE_TITLE, 41 message_id: int = 1, 42 ) -> int: 43 """Send a `C-ECHO` message to the given address. 44 45 Reference: [DICOM Standard Part 7, Section 9.1.5](https://www.dicomstandard.org/standards/view/message-exchange#sect_9.1.5) 46 """ 47 return 0 48 49 50__all__ = ['DEFAULT_CALLED_AE_TITLE', 'DEFAULT_CALLING_AE_TITLE', 'Counter', 'send'] 51 52__version__ = '0.2.3-post.51+fedb856' 53__version_tuple__ = (0, 2, 3, "post", 51, "fedb856") 54 55 56class Counter: 57 """A simple counter.""" 58 59 count = 0 60 61 def increment(self) -> int: 62 """Increment and return the counter.""" 63 self.count += 1 64 return self.count 65 66 67counter = Counter() 68 69 70def send( 71 address: str, 72 /, 73 called_ae_title: str = DEFAULT_CALLED_AE_TITLE, 74 calling_ae_title: str = DEFAULT_CALLING_AE_TITLE, 75 message_id: int | Counter = counter, 76) -> int: 77 """Send a `C-ECHO` message to the given address. 78 79 If `message_id` is not provided, a global counter will be incremented and passed. 80 81 Reference: [DICOM Standard Part 7, Section 9.1.5](https://www.dicomstandard.org/standards/view/message-exchange#sect_9.1.5) 82 """ 83 if isinstance(message_id, Counter): 84 message_id = counter.increment() 85 return __send(address, called_ae_title=called_ae_title, calling_ae_title=calling_ae_title, message_id=message_id)
57class Counter: 58 """A simple counter.""" 59 60 count = 0 61 62 def increment(self) -> int: 63 """Increment and return the counter.""" 64 self.count += 1 65 return self.count
A simple counter.
71def send( 72 address: str, 73 /, 74 called_ae_title: str = DEFAULT_CALLED_AE_TITLE, 75 calling_ae_title: str = DEFAULT_CALLING_AE_TITLE, 76 message_id: int | Counter = counter, 77) -> int: 78 """Send a `C-ECHO` message to the given address. 79 80 If `message_id` is not provided, a global counter will be incremented and passed. 81 82 Reference: [DICOM Standard Part 7, Section 9.1.5](https://www.dicomstandard.org/standards/view/message-exchange#sect_9.1.5) 83 """ 84 if isinstance(message_id, Counter): 85 message_id = counter.increment() 86 return __send(address, called_ae_title=called_ae_title, calling_ae_title=calling_ae_title, message_id=message_id)
Send a C-ECHO
message to the given address.
If message_id
is not provided, a global counter will be incremented and passed.
Reference: DICOM Standard Part 7, Section 9.1.5