Skip to content

Commit 534efa9

Browse files
Fixes for pydicom 3 (#301)
* Import related fixes; remove fix_meta_info, now unnecessary * Drop support for python<3.10 * Fixes to codes and RLE encoding * Remove fix for resolved pydicom bug in decode_frame * Fix frame encoding and decoding, add further transfer syntaxes * Various fixes * Enforce repo-review rules (#296) * Enforce repo-review rule PP302 PP302: Sets a minimum pytest to at least 6 Must have a `minversion=`, and must be at least 6 (first version to support `pyproject.toml` configuration). * Enforce repo-review rule PP305 PP305: Specifies xfail_strict `xfail_strict` should be set. You can manually specify if a check should be strict when setting each xfail. * Enforce repo-review rule PP306 PP306: Specifies strict config `--strict-config` should be in `addopts = [...]`. This forces an error if a config setting is misspelled. * Enforce repo-review rule PP307 PP307: Specifies strict markers `--strict-markers` should be in `addopts = [...]`. This forces all markers to be specified in config, avoiding misspellings. * Enforce repo-review rule PP308 PP308: Specifies useful pytest summary An explicit summary flag like `-ra` should be in `addopts = [...]` (print summary of all fails/errors). * Enforce pytest ≥ 7.3.2 This is the first version to support Python 3.12: https://docs.pytest.org/en/stable/changelog.html#pytest-7-3-2-2023-06-10 * Enforce repo-review rule MY104 MY104: MyPy enables ignore-without-code Must have `"ignore-without-code"` in `enable_error_code = [...]`. This will force all skips in your project to include the error code, which makes them more readable, and avoids skipping something unintended. * Enforce repo-review rule MY105 MY105: MyPy enables redundant-expr Must have `"redundant-expr"` in `enable_error_code = [...]`. This helps catch useless lines of code, like checking the same condition twice. * Enforce repo-review rule MY106 MY106: MyPy enables truthy-bool Must have `"truthy-bool"` in `enable_error_code = []`. This catches mistakes in using a value as truthy if it cannot be falsy. * Remove pillow-jpls dependency as functionality now comes from pylibjpeg * Add details of single bit JPEG2000 to the docs * Better workaround for floating point pixel decoding * Adjust dependencies * Deprecate row_stack for vstack * Bump pydicom version to 3.0.1 * Error message typo --------- Co-authored-by: Dimitri Papadopoulos Orfanos <3234522+DimitriPapadopoulos@users.noreply.github.com>
1 parent d7bfe7c commit 534efa9

19 files changed

Lines changed: 534 additions & 259 deletions

File tree

.github/workflows/run_unit_tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
runs-on: ubuntu-latest
1616
strategy:
1717
matrix:
18-
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
18+
python-version: ["3.10", "3.11", "3.12"]
1919
dependencies: [".", "'.[libjpeg]'"]
2020

2121
steps:

docs/seg.rst

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -807,39 +807,38 @@ We recommend that if you do this, you specify ``max_fractional_value=1`` to
807807
clearly communicate that the segmentation is inherently binary in nature.
808808

809809
Why would you want to make this seemingly rather strange choice? Well,
810-
``"FRACTIONAL"`` SEGs tend to compress *much* better than ``"BINARY"`` ones
811-
(see next section). Note however, that this is arguably an misuse of the intent
812-
of the standard, so *caveat emptor*.
810+
``"FRACTIONAL"`` SEGs tend to compress better than ``"BINARY"`` ones (see next
811+
section). Note however, that this is arguably an misuse of the intent of the
812+
standard, so *caveat emptor*. Also note that while this used to be a more
813+
serious issue it is less serious now that ``"JPEG2000Lossless"`` compression is
814+
now supported for ``"BINARY"`` segmentations as of highdicom v0.23.0.
813815

814816
Compression
815817
-----------
816818

817819
The types of pixel compression available in segmentation images depends on the
818-
segmentation type. Pixels in a ``"BINARY"`` segmentation image are "bit-packed"
819-
such that 8 pixels are grouped into 1 byte in the stored array. If a given frame
820-
contains a number of pixels that is not divisible by 8 exactly, a single byte
820+
segmentation type.
821+
822+
Pixels in an uncompressed ``"BINARY"`` segmentation image are "bit-packed" such
823+
that 8 pixels are grouped into 1 byte in the stored array. If a given frame
824+
contains a number of pixels that is not divisible by 8 exactly, a single byte
821825
will straddle a frame boundary into the next frame if there is one, or the byte
822826
will be padded with zeroes of there are no further frames. This means that
823-
retrieving individual frames from segmentation images in which each frame
824-
size is not divisible by 8 becomes problematic. No further compression may be
825-
applied to frames of ``"BINARY"`` segmentation images.
827+
retrieving individual frames from segmentation images in which each frame size
828+
is not divisible by 8 becomes problematic. For this reason, as well as for
829+
space efficiency (sparse segmentations tend to compress very well), we
830+
therefore strongly recommend using ``"JPEG2000Lossless"`` compression with
831+
``"BINRARY"`` segmentations. This is the only compression method currently
832+
supported for ``"BINARY"`` segmentations. However, beware that reading these
833+
single-bit JPEG 2000 images may not be supported by all other tools and
834+
viewers.
826835

827836
Pixels in ``"FRACTIONAL"`` segmentation images may be compressed using one of
828837
the lossless compression methods available within DICOM. Currently *highdicom*
829838
supports the following compressed transfer syntaxes when creating
830839
``"FRACTIONAL"`` segmentation images: ``"RLELossless"``,
831840
``"JPEG2000Lossless"``, and ``"JPEGLSLossless"``.
832841

833-
Note that there may be advantages to using ``"FRACTIONAL"`` segmentations to
834-
store segmentation images that are binary in nature (i.e. only taking values 0
835-
and 1):
836-
837-
- If the segmentation is very simple or sparse, the lossless compression methods
838-
available in ``"FRACTIONAL"`` images may be more effective than the
839-
"bit-packing" method required by ``"BINARY"`` segmentations.
840-
- The clear frame boundaries make retrieving individual frames from
841-
``"FRACTIONAL"`` image files possible.
842-
843842
Multiprocessing
844843
---------------
845844

pyproject.toml

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ name = "highdicom"
77
dynamic = ["version"]
88
description = "High-level DICOM abstractions."
99
readme = "README.md"
10-
requires-python = ">=3.6"
10+
requires-python = ">=3.10"
1111
authors = [
1212
{ name = "Markus D. Herrmann" },
1313
]
@@ -24,10 +24,6 @@ classifiers = [
2424
"Operating System :: Microsoft :: Windows",
2525
"Operating System :: POSIX :: Linux",
2626
"Programming Language :: Python :: 3",
27-
"Programming Language :: Python :: 3.6",
28-
"Programming Language :: Python :: 3.7",
29-
"Programming Language :: Python :: 3.8",
30-
"Programming Language :: Python :: 3.9",
3127
"Programming Language :: Python :: 3.10",
3228
"Programming Language :: Python :: 3.11",
3329
"Programming Language :: Python :: 3.12",
@@ -36,21 +32,21 @@ classifiers = [
3632
]
3733
dependencies = [
3834
"numpy>=1.19",
39-
"pillow-jpls>=1.0",
4035
"pillow>=8.3",
41-
"pydicom>=2.3.0,!=2.4.0",
36+
"pydicom>=3.0.1",
37+
"pyjpegls>=1.0.0",
4238
]
4339

4440
[project.optional-dependencies]
4541
libjpeg = [
46-
"pylibjpeg-libjpeg>=1.3",
47-
"pylibjpeg-openjpeg>=1.2",
48-
"pylibjpeg>=1.4",
42+
"pylibjpeg-libjpeg>=2.1",
43+
"pylibjpeg-openjpeg>=2.0.0",
44+
"pylibjpeg>=2.0",
4945
]
5046
test = [
5147
"mypy==0.971",
52-
"pytest==7.1.2",
53-
"pytest-cov==3.0.0",
48+
"pytest==7.4.4",
49+
"pytest-cov==4.1.0",
5450
"pytest-flake8==1.1.1",
5551
"numpy-stubs @ git+https://github.com/numpy/numpy-stubs@201115370a0c011d879d69068b60509accc7f750",
5652
]
@@ -68,12 +64,15 @@ documentation = "https://highdicom.readthedocs.io/"
6864
repository = "https://github.com/ImagingDataCommons/highdicom.git"
6965

7066
[tool.pytest.ini_options]
71-
addopts = "--doctest-modules"
67+
minversion = "7"
68+
addopts = ["--doctest-modules", "-ra", "--strict-config", "--strict-markers"]
7269
testpaths = ["tests"]
7370
log_cli_level = "INFO"
71+
xfail_strict = true
7472

7573
[tool.mypy]
7674
warn_unreachable = true
75+
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
7776

7877
[[tool.mypy.overrides]]
7978
module = "mypy-pydicom.*"

src/highdicom/base.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,6 @@ def __init__(
139139
"Big Endian transfer syntaxes are retired and no longer "
140140
"supported by highdicom."
141141
)
142-
self.is_little_endian = True # backwards compatibility
143-
self.is_implicit_VR = transfer_syntax_uid.is_implicit_VR
144142

145143
# Include all File Meta Information required for writing SOP instance
146144
# to a file in PS3.10 format.
@@ -154,7 +152,6 @@ def __init__(
154152
'1.2.826.0.1.3680043.9.7433.1.1'
155153
)
156154
self.file_meta.ImplementationVersionName = f'highdicom{__version__}'
157-
self.fix_meta_info(enforce_standard=True)
158155
with BytesIO() as fp:
159156
write_file_meta_info(fp, self.file_meta, enforce_standard=True)
160157
self.file_meta.FileMetaInformationGroupLength = len(fp.getvalue())

src/highdicom/content.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from pydicom.sr.coding import Code
1212
from pydicom.sr.codedict import codes
1313
from pydicom.valuerep import DS, format_number_as_ds
14-
from pydicom._storage_sopclass_uids import SegmentationStorage
14+
from pydicom.uid import SegmentationStorage
1515

1616
from highdicom.enum import (
1717
CoordinateSystemNames,

0 commit comments

Comments
 (0)