dicomforge 0.6.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. dicomforge-0.6.0/.claude/settings.local.json +11 -0
  2. dicomforge-0.6.0/.github/workflows/ci.yml +26 -0
  3. dicomforge-0.6.0/.gitignore +17 -0
  4. dicomforge-0.6.0/CHANGELOG.md +115 -0
  5. dicomforge-0.6.0/CITATION.cff +38 -0
  6. dicomforge-0.6.0/CONTRIBUTING.md +31 -0
  7. dicomforge-0.6.0/LICENSE +21 -0
  8. dicomforge-0.6.0/PKG-INFO +273 -0
  9. dicomforge-0.6.0/README.md +208 -0
  10. dicomforge-0.6.0/SECURITY.md +33 -0
  11. dicomforge-0.6.0/docs/architecture.md +84 -0
  12. dicomforge-0.6.0/docs/compatibility.md +80 -0
  13. dicomforge-0.6.0/docs/conformance.md +194 -0
  14. dicomforge-0.6.0/docs/roadmap.md +166 -0
  15. dicomforge-0.6.0/docs/safety.md +28 -0
  16. dicomforge-0.6.0/examples/async_networking.py +17 -0
  17. dicomforge-0.6.0/examples/deidentify_with_report.py +19 -0
  18. dicomforge-0.6.0/examples/dicomweb_client.py +11 -0
  19. dicomforge-0.6.0/examples/end_to_end_workflow.py +113 -0
  20. dicomforge-0.6.0/examples/pixel_safety.py +22 -0
  21. dicomforge-0.6.0/examples/pydicom_io.py +6 -0
  22. dicomforge-0.6.0/pyproject.toml +52 -0
  23. dicomforge-0.6.0/src/dicomforge/__init__.py +143 -0
  24. dicomforge-0.6.0/src/dicomforge/adapt.py +514 -0
  25. dicomforge-0.6.0/src/dicomforge/anonymize.py +363 -0
  26. dicomforge-0.6.0/src/dicomforge/api.py +451 -0
  27. dicomforge-0.6.0/src/dicomforge/codecs.py +83 -0
  28. dicomforge-0.6.0/src/dicomforge/dataset.py +113 -0
  29. dicomforge-0.6.0/src/dicomforge/dicomweb.py +577 -0
  30. dicomforge-0.6.0/src/dicomforge/errors.py +21 -0
  31. dicomforge-0.6.0/src/dicomforge/io.py +192 -0
  32. dicomforge-0.6.0/src/dicomforge/network.py +597 -0
  33. dicomforge-0.6.0/src/dicomforge/pixels.py +420 -0
  34. dicomforge-0.6.0/src/dicomforge/tags.py +305 -0
  35. dicomforge-0.6.0/src/dicomforge/transfer_syntax.py +148 -0
  36. dicomforge-0.6.0/src/dicomforge/uids.py +108 -0
  37. dicomforge-0.6.0/tests/__init__.py +1 -0
  38. dicomforge-0.6.0/tests/test_adapt.py +333 -0
  39. dicomforge-0.6.0/tests/test_anonymize.py +169 -0
  40. dicomforge-0.6.0/tests/test_api.py +358 -0
  41. dicomforge-0.6.0/tests/test_core.py +139 -0
  42. dicomforge-0.6.0/tests/test_dicomweb.py +258 -0
  43. dicomforge-0.6.0/tests/test_io.py +113 -0
  44. dicomforge-0.6.0/tests/test_network.py +286 -0
  45. dicomforge-0.6.0/tests/test_pixels.py +264 -0
@@ -0,0 +1,11 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(grep -E \"\\\\.\\(py|toml|txt|cfg|ini|md|yml|yaml\\)$|Makefile|^.*\\\\.github.*$\")",
5
+ "Bash(PYTHONPATH=src python3 -m unittest discover -v)",
6
+ "Bash(python3 -m compileall -q src tests)",
7
+ "Bash(PYTHONPATH=src python3 -W error::DeprecationWarning -m unittest)",
8
+ "Bash(PYTHONPATH=src python3 -m unittest)"
9
+ ]
10
+ }
11
+ }
@@ -0,0 +1,26 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ test:
9
+ name: Python ${{ matrix.python-version }}
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
15
+
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: ${{ matrix.python-version }}
21
+ - name: Install package
22
+ run: python -m pip install -e ".[dev]"
23
+ - name: Unit tests
24
+ run: PYTHONPATH=src python -m unittest
25
+ - name: Compile check
26
+ run: PYTHONPATH=src python -m compileall -q src tests
@@ -0,0 +1,17 @@
1
+ .DS_Store
2
+ .pycache/
3
+ __pycache__/
4
+ *.py[cod]
5
+ .pytest_cache/
6
+ .mypy_cache/
7
+ .ruff_cache/
8
+ .venv/
9
+ dist/
10
+ build/
11
+ *.egg-info/
12
+
13
+ #documentation
14
+ paper.md
15
+ paper.bib
16
+ citation.cff
17
+
@@ -0,0 +1,115 @@
1
+ # Changelog
2
+
3
+ All notable changes to DicomForge are documented here.
4
+ Versions follow [Semantic Versioning](https://semver.org/).
5
+
6
+ ## [0.6.0] — 2026-05-05
7
+
8
+ ### Added
9
+ - `dicomforge.adapt` — adoption-layer integration adapters:
10
+ - `from_pydicom` / `to_pydicom` — bidirectional pydicom Dataset conversion
11
+ - `pixel_array` — numpy array from uncompressed PixelData with correct dtype
12
+ - `to_pil_image` — PIL Image with automatic VOI windowing and MONOCHROME1 inversion
13
+ - `to_json` / `from_json` — DICOM JSON Model round-trip
14
+ - `from_pynetdicom_event` — extract DicomDataset from a pynetdicom event
15
+ - `dicomforge.api` — high-level convenience API:
16
+ - `DicomFile` — lazy-loading file wrapper with named property access for 30+ tags
17
+ - `quick_anonymize` — read → de-identify → write in one call
18
+ - `validate_dataset` — structural validation with human-readable issue list
19
+ - `batch_anonymize` — anonymize a file list; partial failures are isolated
20
+ - 55 additional `Tag` keywords (SeriesNumber, BodyPartExamined, PixelSpacing,
21
+ ImagePositionPatient, Manufacturer, AttendingPhysicianName, and more)
22
+ - 20+ additional `SopClassUID` constants (PET, NM, US, RT, SR, WSI, enhanced CT/MR)
23
+ - 6 additional `TransferSyntaxUID` constants (JPEG 2000 lossy, JPEG-LS near-lossless,
24
+ HT-JPEG 2000 lossless and lossy)
25
+ - 6 additional registered `TransferSyntax` entries
26
+ - `network` and `all` optional dependency extras in `pyproject.toml`
27
+ - `DicomDataset.copy()` and `DicomDataset.__repr__`
28
+ - `Tag.__repr__` returns keyword name when available (e.g. `Tag.PatientName`)
29
+
30
+ ### Changed
31
+ - `AnonymizationPlan.starter_profile` expanded from 27 to 48 de-identification rules,
32
+ adding patient weight/size/comments, ethnic group, smoking/pregnancy status,
33
+ attending/requesting physician, device serial number, and department name
34
+ - `UidRemapper` is now thread-safe (internal cache protected by `threading.Lock`)
35
+ - `UidRemapper` now also remaps `MediaStorageSOPInstanceUID` and `ReferencedSOPInstanceUID`
36
+ - `default_registry()` now returns a cached singleton instead of a new instance per call
37
+ - `io.write` prefers `pydicom.dcmwrite()` on pydicom ≥ 3.0 (avoids deprecation warning)
38
+ - Network `_read_message` and `_write_message` now enforce a 30-second timeout and a
39
+ 64 MiB maximum message size
40
+ - All public pixel helper functions (`rescale_values`, `is_monochrome`, `voi_window_bounds`,
41
+ `apply_voi_window_from_dataset`, etc.) are now exported from `dicomforge` top level
42
+ - `pyproject.toml` version bumped to 0.6.0; development status promoted to Beta
43
+
44
+ ### Fixed
45
+ - `assert_pixel_data_length` incorrectly validated the last byte of even-length
46
+ pixel data as a padding byte, causing `PixelMetadataError` for any dataset
47
+ whose last pixel value was non-zero
48
+
49
+ ---
50
+
51
+ ## [0.5.0] — 2025-01-01
52
+
53
+ ### Added
54
+ - `dicomforge.dicomweb` — dependency-free DICOMweb client:
55
+ - QIDO-RS query builder (`QidoQuery`)
56
+ - WADO-RS study/series/instance retrieval
57
+ - STOW-RS multipart upload
58
+ - DICOM JSON Model conversion (`dataset_from_dicom_json`, `dataset_to_dicom_json`)
59
+ - `parse_multipart_related` / `build_multipart_related`
60
+ - Injectable `DicomwebTransport` protocol with stdlib `UrllibDicomwebTransport`
61
+ - `dicomforge.network` — async DIMSE-style services:
62
+ - `Association` client with C-ECHO, C-FIND, C-MOVE, C-STORE
63
+ - `DimseServer` SCP with backpressure-aware C-STORE queue
64
+ - `open_association` / `start_dimse_server` convenience helpers
65
+ - `AssociationRejectedError`, `AssociationClosedError`
66
+ - DICOMweb integration: `dataset_to_message` / `dataset_from_message` with
67
+ base64-encoded binary and nested dataset support
68
+
69
+ ---
70
+
71
+ ## [0.4.0] — 2024-10-01
72
+
73
+ ### Added
74
+ - `dicomforge.network` initial implementation (async association lifecycle,
75
+ C-ECHO, JSON framing)
76
+ - `DimseStatus` with class-level constants (SUCCESS, PENDING, CANCEL, UNABLE_TO_PROCESS)
77
+ - `AssociationRequest` frozen dataclass
78
+
79
+ ---
80
+
81
+ ## [0.3.0] — 2024-07-01
82
+
83
+ ### Added
84
+ - `dicomforge.anonymize` — de-identification engine:
85
+ - `AnonymizationPlan` with `starter_profile()` and `basic_profile()` factory methods
86
+ - `UidRemapper` with SHA-256 deterministic remapping
87
+ - `AnonymizationReport` / `AnonymizationEvent` audit trail
88
+ - `PrivateTagAction` (REMOVE / KEEP)
89
+ - Recursive sequence processing
90
+
91
+ ---
92
+
93
+ ## [0.2.0] — 2024-04-01
94
+
95
+ ### Added
96
+ - `dicomforge.pixels` — pixel metadata and safety layer:
97
+ - `FrameMetadata` with `from_dataset` and eager validation
98
+ - `check_pixel_capability` — metadata + codec pre-flight check
99
+ - `PixelCapability`, `VoiLut`
100
+ - `rescale_value`, `apply_voi_window`, photometric interpretation helpers
101
+ - `dicomforge.io` — optional pydicom read/write backend
102
+
103
+ ---
104
+
105
+ ## [0.1.0] — 2024-01-01
106
+
107
+ ### Added
108
+ - `dicomforge.tags` — `Tag` frozen dataclass with keyword registry and multi-format parser
109
+ - `dicomforge.dataset` — `DicomDataset` (MutableMapping with tag normalization)
110
+ - `dicomforge.transfer_syntax` — `TransferSyntax` registry with safe unknown defaults
111
+ - `dicomforge.codecs` — `CodecRegistry` and `Codec` capability model
112
+ - `dicomforge.errors` — `DicomForgeError` hierarchy
113
+ - `dicomforge.uids` — `SopClassUID`, `TransferSyntaxUID`, `ImplementationUID`, `DimseStatusCode`
114
+ - CI matrix: Python 3.9–3.13 on GitHub Actions
115
+ - MIT license, CONTRIBUTING.md, SECURITY.md, architecture and conformance docs
@@ -0,0 +1,38 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use DicomForge in your research, please cite it as below."
3
+ type: software
4
+ title: "DicomForge: A Lightweight Python Toolkit for Typed DICOM Processing and Medical Imaging Workflows"
5
+ version: 0.6.0
6
+ date-released: "2026-05-05"
7
+ license: MIT
8
+ repository-code: "https://github.com/dicomforge/dicomforge"
9
+ url: "https://github.com/dicomforge/dicomforge"
10
+ abstract: >-
11
+ DicomForge is a typed, dependency-free Python library for DICOM processing.
12
+ It provides tag normalization, transfer syntax classification, pixel metadata
13
+ validation, auditable de-identification with deterministic UID remapping,
14
+ DICOMweb client helpers, and an adoption layer for pydicom, NumPy, and Pillow
15
+ integration — designed for both hobby medical imaging projects and commercial
16
+ production software.
17
+ keywords:
18
+ - DICOM
19
+ - medical imaging
20
+ - radiology
21
+ - de-identification
22
+ - DICOMweb
23
+ - healthcare
24
+ - Python
25
+ authors:
26
+ - family-names: Merchant
27
+ given-names: Mustufa
28
+ affiliation: "Kub Technologies Inc."
29
+ preferred-citation:
30
+ type: article
31
+ title: "DicomForge: A Lightweight Python Toolkit for Typed DICOM Processing and Medical Imaging Workflows"
32
+ authors:
33
+ - family-names: Merchant
34
+ given-names: Mustufa
35
+ affiliation: "Kub Technologies Inc."
36
+ journal: "Journal of Open Source Software"
37
+ year: 2026
38
+ url: "https://github.com/dicomforge/dicomforge"
@@ -0,0 +1,31 @@
1
+ # Contributing
2
+
3
+ Thank you for helping make DICOMForge safer and more useful.
4
+
5
+ ## Development Setup
6
+
7
+ ```bash
8
+ python3 -m venv .venv
9
+ . .venv/bin/activate
10
+ python -m pip install -e ".[dev]"
11
+ PYTHONPATH=src python -m unittest
12
+ ```
13
+
14
+ ## Project Rules
15
+
16
+ - Keep the core package dependency-light.
17
+ - Prefer explicit DICOM boundaries over claiming unsupported conformance.
18
+ - Add tests for every user-visible behavior change.
19
+ - Do not commit real patient data or DICOM files containing PHI.
20
+ - Prefer small, focused modules over broad abstractions.
21
+
22
+ ## DICOM Changes
23
+
24
+ When adding DICOM behavior, include one of:
25
+
26
+ - a reference to the DICOM part/table used
27
+ - a test that captures the expected behavior
28
+ - documentation in `docs/conformance.md` explaining the current boundary
29
+
30
+ Full clinical conformance work should also update the compatibility matrix and
31
+ conformance notes.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DICOMForge contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,273 @@
1
+ Metadata-Version: 2.4
2
+ Name: dicomforge
3
+ Version: 0.6.0
4
+ Summary: A lightweight, typed Python DICOM processing toolkit for medical imaging.
5
+ Project-URL: Homepage, https://github.com/dicomforge/dicomforge
6
+ Project-URL: Repository, https://github.com/dicomforge/dicomforge
7
+ Project-URL: Documentation, https://github.com/dicomforge/dicomforge/tree/main/docs
8
+ Project-URL: Issues, https://github.com/dicomforge/dicomforge/issues
9
+ Author: DICOMForge contributors
10
+ License: MIT License
11
+
12
+ Copyright (c) 2026 DICOMForge contributors
13
+
14
+ Permission is hereby granted, free of charge, to any person obtaining a copy
15
+ of this software and associated documentation files (the "Software"), to deal
16
+ in the Software without restriction, including without limitation the rights
17
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18
+ copies of the Software, and to permit persons to whom the Software is
19
+ furnished to do so, subject to the following conditions:
20
+
21
+ The above copyright notice and this permission notice shall be included in all
22
+ copies or substantial portions of the Software.
23
+
24
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
+ SOFTWARE.
31
+ License-File: LICENSE
32
+ Keywords: dicom,healthcare,medical-imaging,pacs,radiology
33
+ Classifier: Development Status :: 4 - Beta
34
+ Classifier: Intended Audience :: Developers
35
+ Classifier: Intended Audience :: Healthcare Industry
36
+ Classifier: License :: OSI Approved :: MIT License
37
+ Classifier: Programming Language :: Python :: 3
38
+ Classifier: Programming Language :: Python :: 3.9
39
+ Classifier: Programming Language :: Python :: 3.10
40
+ Classifier: Programming Language :: Python :: 3.11
41
+ Classifier: Programming Language :: Python :: 3.12
42
+ Classifier: Programming Language :: Python :: 3.13
43
+ Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
44
+ Requires-Python: >=3.9
45
+ Provides-Extra: all
46
+ Requires-Dist: numpy>=1.23; extra == 'all'
47
+ Requires-Dist: pillow>=10; extra == 'all'
48
+ Requires-Dist: pydicom>=2.4; extra == 'all'
49
+ Requires-Dist: pynetdicom>=2.0; extra == 'all'
50
+ Provides-Extra: dev
51
+ Requires-Dist: mypy>=1.8; extra == 'dev'
52
+ Requires-Dist: numpy>=1.23; extra == 'dev'
53
+ Requires-Dist: pillow>=10; extra == 'dev'
54
+ Requires-Dist: pydicom>=2.4; extra == 'dev'
55
+ Requires-Dist: pytest>=7; extra == 'dev'
56
+ Requires-Dist: ruff>=0.4; extra == 'dev'
57
+ Provides-Extra: network
58
+ Requires-Dist: pynetdicom>=2.0; extra == 'network'
59
+ Provides-Extra: pixels
60
+ Requires-Dist: numpy>=1.23; extra == 'pixels'
61
+ Requires-Dist: pillow>=10; extra == 'pixels'
62
+ Provides-Extra: pydicom
63
+ Requires-Dist: pydicom>=2.4; extra == 'pydicom'
64
+ Description-Content-Type: text/markdown
65
+
66
+ # DICOMForge
67
+
68
+ DICOMForge is a Python DICOM processing library for medical imaging
69
+ applications. The goal is a lightweight core with typed, predictable APIs,
70
+ explicit safety boundaries, and optional integrations for heavier work such as
71
+ pixel codecs, wire-compatible networking, and DICOMweb.
72
+
73
+ This repository is intentionally starting with a small, solid core:
74
+
75
+ - typed tags and value access
76
+ - transfer syntax classification
77
+ - pluggable codec registry
78
+ - de-identification profiles, deterministic UID remapping, and audit reports
79
+ - pixel metadata and safety checks
80
+ - VOI window, rescale, and photometric interpretation helpers
81
+ - async networking primitives for association lifecycle and DIMSE-style commands
82
+ - DICOMweb query, retrieval, upload, and multipart helpers
83
+ - optional `pydicom` IO backend
84
+ - standard-library tests
85
+
86
+ ## Why another DICOM library?
87
+
88
+ The adoption target is not just feature count. The library should feel safe for
89
+ production teams and approachable for new medical-imaging developers.
90
+
91
+ Design priorities:
92
+
93
+ - **Small import surface:** core imports should not pull in NumPy, Pillow, codec
94
+ wheels, or networking stacks.
95
+ - **Typed access:** avoid stringly-typed dataset code where common attributes can
96
+ be accessed predictably.
97
+ - **Explicit codec model:** make unsupported transfer syntaxes visible before a
98
+ transcoding job fails halfway through.
99
+ - **Lazy IO:** support large studies and multi-frame objects without forcing
100
+ full pixel loading.
101
+ - **Character-set correctness:** treat text encoding as a first-class concern.
102
+ - **Concurrency-safe services:** design networking and DICOMweb APIs around
103
+ explicit lifecycle and backpressure.
104
+ - **Good errors:** explain the DICOM concept, the offending tag, and the next
105
+ action where possible.
106
+
107
+ See [docs/architecture.md](docs/architecture.md) and
108
+ [docs/roadmap.md](docs/roadmap.md). Current implementation boundaries are
109
+ tracked in [docs/conformance.md](docs/conformance.md). For repository naming
110
+ and discoverability notes, see [docs/branding.md](docs/branding.md).
111
+
112
+ ## Commercial Readiness
113
+
114
+ DICOMForge is MIT licensed and designed for commercial use as a developer
115
+ library. It is not a medical device, diagnostic application, complete PS3.15
116
+ de-identification engine, or wire-compatible DIMSE implementation. See
117
+ [docs/safety.md](docs/safety.md), [docs/conformance.md](docs/conformance.md),
118
+ and [docs/compatibility.md](docs/compatibility.md) before using it in regulated
119
+ clinical workflows.
120
+
121
+ ## When To Use It
122
+
123
+ Use DICOMForge when you need:
124
+
125
+ - typed, dependency-light DICOM metadata handling
126
+ - pixel metadata validation before decoding or processing
127
+ - de-identification planning with deterministic UID remapping and audit reports
128
+ - pydicom-backed file IO behind a smaller application API
129
+ - DICOMweb URL/query, DICOM JSON, STOW multipart, and response parsing helpers
130
+ - async lifecycle and backpressure primitives for DICOM-like service design
131
+
132
+ Do not use DICOMForge as the only component for:
133
+
134
+ - diagnostic interpretation or medical-device behavior
135
+ - legal de-identification approval without site policy and human review
136
+ - direct DIMSE/PACS interoperability over the DICOM Upper Layer
137
+ - full-fidelity DICOM editing that requires every VR, character set, and IOD rule
138
+ - replacing pydicom, pynetdicom, or integration-tested PACS/VNA validation
139
+
140
+ ## Architecture At A Glance
141
+
142
+ ```text
143
+ dicomforge.tags typed tag parsing and common keyword constants
144
+ dicomforge.dataset lightweight mutable dataset wrapper
145
+ dicomforge.transfer_syntax transfer syntax classification
146
+ dicomforge.codecs codec capability registry
147
+ dicomforge.pixels pixel metadata safety checks and small value helpers
148
+ dicomforge.anonymize starter de-identification plans and audit reports
149
+ dicomforge.io optional pydicom read/write adapter
150
+ dicomforge.network async command lifecycle primitives, not DICOM UL PDUs
151
+ dicomforge.dicomweb QIDO/WADO/STOW helpers with injectable HTTP transport
152
+ ```
153
+
154
+ ## API Stability
155
+
156
+ DICOMForge is pre-1.0. Public APIs are intended to be small and stable, but
157
+ breaking changes may happen while the library moves toward a 1.0 adoption bar.
158
+ Breaking changes should be documented in release notes and paired with migration
159
+ guidance.
160
+
161
+ ## Quick Start
162
+
163
+ ```python
164
+ from dicomforge import DicomDataset, Tag, TransferSyntax
165
+
166
+ ds = DicomDataset()
167
+ ds.set(Tag.PatientName, "Anonymous")
168
+ ds.set(Tag.Modality, "CT")
169
+
170
+ syntax = TransferSyntax.from_uid("1.2.840.10008.1.2.1")
171
+ assert syntax.is_little_endian
172
+ assert syntax.is_explicit_vr
173
+ ```
174
+
175
+ Optional pydicom-backed reading:
176
+
177
+ ```python
178
+ from dicomforge.io import read
179
+
180
+ dataset = read("image.dcm", stop_before_pixels=True)
181
+ print(dataset.get("PatientName"))
182
+ ```
183
+
184
+ Basic de-identification:
185
+
186
+ ```python
187
+ from dicomforge import AnonymizationPlan, DicomDataset, PrivateTagAction
188
+
189
+ dataset = DicomDataset(
190
+ {
191
+ "PatientName": "Ada Lovelace",
192
+ "PatientID": "MRN-123",
193
+ "StudyInstanceUID": "1.2.826.0.1.3680043.8.498.1",
194
+ (0x0011, 0x1001): "private vendor value",
195
+ }
196
+ )
197
+
198
+ plan = AnonymizationPlan.starter_profile(
199
+ uid_salt="project-specific-secret",
200
+ private_tag_action=PrivateTagAction.REMOVE,
201
+ )
202
+ report = plan.apply_with_report(dataset)
203
+
204
+ assert dataset.get("PatientName") == "Anonymous"
205
+ assert dataset.get("PatientIdentityRemoved") == "YES"
206
+ assert report.private_tags_removed == 1
207
+ ```
208
+
209
+ Async networking:
210
+
211
+ ```python
212
+ from dicomforge.network import DimseServer, open_association
213
+
214
+ async with DimseServer(ae_title="LOCAL-SCP") as server:
215
+ async with await open_association(
216
+ "127.0.0.1",
217
+ server.bound_port,
218
+ called_ae_title="LOCAL-SCP",
219
+ ) as association:
220
+ status = await association.c_echo()
221
+ assert status.is_success
222
+ ```
223
+
224
+ DICOMweb query building:
225
+
226
+ ```python
227
+ from dicomforge.dicomweb import DicomwebClient, QidoQuery, UrllibDicomwebTransport
228
+
229
+ client = DicomwebClient(
230
+ "https://pacs.example/dicomweb",
231
+ UrllibDicomwebTransport(timeout=10),
232
+ )
233
+ studies = client.search_studies(QidoQuery().patient_id("MRN-123").modality("CT"))
234
+ ```
235
+
236
+ ## De-identification Scope
237
+
238
+ DICOMForge implements a practical, conservative subset of the DICOM PS3.15
239
+ Basic Application Level Confidentiality Profile for non-pixel attributes:
240
+ common patient, accession, date/time, institution, operator, and UID fields are
241
+ removed, emptied, replaced, or deterministically remapped. Private tag handling
242
+ is explicit and defaults to removal. `remove_private_tags` on `apply` and
243
+ `apply_with_report` remains available as a per-call override for older callers.
244
+
245
+ This is a software library, not a compliance certificate. Production use should
246
+ pair it with site-specific policy, legal review, image pixel review, and a risk
247
+ assessment for the data release context.
248
+
249
+ ## Development
250
+
251
+ Run the standard-library test suite:
252
+
253
+ ```bash
254
+ PYTHONPATH=src python3 -m unittest
255
+ ```
256
+
257
+ Optional checks used by maintainers when development dependencies are installed:
258
+
259
+ ```bash
260
+ python -m ruff check src tests
261
+ python -m mypy src/dicomforge
262
+ python -m compileall -q src tests
263
+ ```
264
+
265
+ Examples live in [examples](examples).
266
+
267
+ For a fuller commercial workflow, see
268
+ [examples/end_to_end_workflow.py](examples/end_to_end_workflow.py).
269
+
270
+ ## License
271
+
272
+ DICOMForge is distributed under the MIT License for personal and commercial
273
+ use. See [LICENSE](LICENSE).