dimsechord
Pure-Python toolkit of composable building blocks for DICOM and DICOMweb services.
dimsechord wraps pydicom and
pynetdicom behind a small, stable
public API. It gives you the networking, caching, and conversion primitives
needed to build PACS proxies, DICOMweb gateways, and imaging pipelines — and
nothing else: there is no bundled HTTP framework and no opinionated request
handlers, so you bring your own web layer.
Features
- DIMSE SCU — C-FIND, C-STORE, C-MOVE and C-GET, exposed through an async
DicomClient. - C-STORE SCP — receive incoming instances with
StorageSCP, one listener per distinct port; multiple AETs may share a port. All transfer syntaxes are accepted by default, so compressed objects arrive verbatim. - C-STORE SCU session —
StoreSessionis a persistent, association-scoped C-STORE sender: the peer's DIMSE status passes through verbatim as anint(success, warning, and failure alike), and a presentation-context miss raisesNoPresentationContextErrorwithout tearing down the association. - AssociationPool — manage multiple AE-Title identities with per-AET concurrency limits.
- Two-tier cache — in-memory + disk, backed by a SQLite instance index.
- Streaming pull-engine — move-to-self retrieval streamed instance by instance, with per-UID request coalescing.
- Streaming query-engine — raw C-FIND pass-through via
QueryEngine, streamed response by response under independent per-AET find leases. - DICOMweb conversion — DICOM ↔ DICOMweb JSON and
multipart/relatedframe responses.
Runtime dependencies are just pydicom, pynetdicom, and cachetools.
Installation
pip install dimsechord
Requires Python 3.12+.
Quickstart
import asyncio
from dimsechord import (
AssociationPool, DicomCache, DicomClient, DicomNode, PullEngine,
SeriesQuery, StorageSCP, StudyQuery, convert_datasets_to_dicom_json,
)
PACS = DicomNode(aet="PACS", host="127.0.0.1", port=11112)
async def main() -> None:
# 1. Find studies and series (C-FIND, QIDO-style).
client = DicomClient(calling_aet="MYSCU")
studies = await client.find_studies(StudyQuery(patient_id="12345"), PACS)
series = await client.find_series(
SeriesQuery(study_instance_uid=studies[0].study_instance_uid), PACS)
# 2. Pull a series move-to-self and build DICOMweb JSON (WADO-style).
pool = AssociationPool(aets=["MYDEST"])
scp = StorageSCP()
scp.start({"MYDEST": 11113})
# Your PACS must route the AET "MYDEST" back to this SCP's host:port.
cache = DicomCache(base_dir="./cache", index_path="./cache/index.db")
engine = PullEngine(pool=pool, scp=scp, cache=cache, pacs=PACS)
try:
cached = await engine.ensure_series(
studies[0].study_instance_uid, series[0].series_instance_uid)
metadata = convert_datasets_to_dicom_json(
list(cached.instances.values()), base_url="https://example.org/dicom-web")
print(len(metadata), "instances")
finally:
scp.stop()
cache.shutdown()
asyncio.run(main())
0.7.0:
StoreSessionis a persistent C-STORE SCU session with verbatim DIMSE status pass-through — success, warning, and failure codes all return as anint, never raised. A presentation-context miss raises the newNoPresentationContextErrorinstead;build_storage_scp_contexts()is the new acceptor-side mirror ofbuild_storage_scu_contexts().
0.6.0 (breaking):
DicomCache's memory tier is now sized by bytes, not entry count —memory_max_entries(default50) is replaced bymemory_max_size_gb(default1.0).
0.5.1:
StorageSCPaccepts all transfer syntaxes by default and the newbuild_storage_scu_contexts()builds forwarding-SCU contexts, so compressed objects pass through verbatim. C-GET now negotiates a curated storage-class set (see CHANGELOG).
0.5.0: the disk cache now records per-series completeness; series cached by earlier versions re-pull once on first read after upgrade (the SQLite schema migrates automatically).
0.4.0 (breaking):
StorageSCP.startnow takes an{AET: port}mapping (wasstart(aets, port)), binding one listener per port.
Public API
The supported surface is exactly what dimsechord/__init__.py exports
(from dimsechord import …); it is frozen by tests/unit/test_public_api.py.
Everything else lives in underscore-prefixed modules (dimsechord._scu,
dimsechord._cache, …) and is private — importing from those modules is
unsupported and may break without notice. If you need something that is not
exported, extend the public surface rather than reaching into a private module.
Documentation
- Why dimsechord — what problems it solves.
- Typing — how the typed API works with mypy/pyright.
- Cookbook — one recipe per feature.
- Gateway tutorial — an end-to-end DICOMweb gateway.
License
MIT — see LICENSE.
Metadata
Release files for dimsechord 0.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| dimsechord-0.7.0.tar.gz | 112.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| dimsechord-0.7.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 160.9 kB
Release files / dimsechord-0.7.0.tar.gz
| Download URL | dimsechord-0.7.0.tar.gz |
|---|---|
| Size | 112.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ec72df7ad5a68b46e60ba4499fcee82eee3a6f2f2926c20587c093065c1e5974
|
|
BLAKE2b-256 checksum How to use checksums |
dbeeb5aceaf2393ace2f5a6840f67a9ca208935fd55992b7cc8b643983101efc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 24, 2026.
Transparency logRelease files / dimsechord-0.7.0-py3-none-any.whl
| Download URL | dimsechord-0.7.0-py3-none-any.whl |
|---|---|
| Size | 48.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a39cda7b072a9223a149945ebaf320a99c673c071fe4dc4e1e81ccad695534a9
|
|
BLAKE2b-256 checksum How to use checksums |
657d0cf2ab6946bd5ba2a41c6ab9ef516181942806959c9c4286cd727bf5ffe5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 24, 2026.
Transparency log