Skip to main content

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 — StoreSession is a persistent, association-scoped C-STORE sender: the peer's DIMSE status passes through verbatim as an int (success, warning, and failure alike), and a presentation-context miss raises NoPresentationContextError without 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/related frame 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: StoreSession is a persistent C-STORE SCU session with verbatim DIMSE status pass-through — success, warning, and failure codes all return as an int, never raised. A presentation-context miss raises the new NoPresentationContextError instead; build_storage_scp_contexts() is the new acceptor-side mirror of build_storage_scu_contexts().

0.6.0 (breaking): DicomCache's memory tier is now sized by bytes, not entry count — memory_max_entries (default 50) is replaced by memory_max_size_gb (default 1.0).

0.5.1: StorageSCP accepts all transfer syntaxes by default and the new build_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.start now takes an {AET: port} mapping (was start(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

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)

Source distribution for dimsechord 0.7.0
File Size Uploaded
dimsechord-0.7.0.tar.gz 112.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for dimsechord 0.7.0
File Interpreter ABI Platform
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 log

Release 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

Release history Release notifications | RSS feed

0.8.0

2 release files

This release

0.7.0 This release

2 release files

0.6.0

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page