Skip to content

Commit 2840c16

Browse files
authored
Merge pull request #95 from erikogabrielsson/bugfix/dicom-rle-mediatype
Bugfix/dicom rle mediatype
2 parents 41f98d1 + 7dd820c commit 2840c16

File tree

3 files changed

+107
-20
lines changed

3 files changed

+107
-20
lines changed
124 Bytes
Binary file not shown.

src/dicomweb_client/web.py

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
Dict,
1515
Iterator,
1616
List,
17+
Mapping,
1718
Optional,
1819
Set,
1920
Sequence,
@@ -865,7 +866,9 @@ def _build_accept_header_field_value(
865866
def _build_multipart_accept_header_field_value(
866867
cls,
867868
media_types: Union[Tuple[Union[str, Tuple[str, str]], ...], None],
868-
supported_media_types: Union[Dict[str, str], Set[str]]
869+
supported_media_types: Union[
870+
Mapping[str, Union[str, Tuple[str, ...]]], Set[str]
871+
]
869872
) -> str:
870873
"""Build an accept header field value for a multipart request message.
871874
@@ -874,7 +877,9 @@ def _build_multipart_accept_header_field_value(
874877
media_types: Union[Tuple[Union[str, Tuple[str, str]], ...], None]
875878
Acceptable media types and optionally the UIDs of the corresponding
876879
transfer syntaxes
877-
supported_media_types: Union[Dict[str, str], Set[str]]
880+
supported_media_types: Union[
881+
Mapping[str, Union[str, Tuple[str, ...]]], Set[str]
882+
]
878883
Set of supported media types or mapping of transfer syntaxes
879884
to their corresponding media types
880885
@@ -902,7 +907,13 @@ def _build_multipart_accept_header_field_value(
902907
cls._assert_media_type_is_valid(media_type)
903908
field_value = f'multipart/related; type="{media_type}"'
904909
if isinstance(supported_media_types, dict):
905-
if media_type not in supported_media_types.values():
910+
media_type_in_supported_media_types = any(
911+
media_type == supported_media_types
912+
if isinstance(supported_media_types, str)
913+
else media_type in supported_media_types
914+
for supported_media_types in supported_media_types.values()
915+
)
916+
if not media_type_in_supported_media_types:
906917
if not (media_type.endswith('/*') or
907918
media_type.endswith('/')):
908919
raise ValueError(
@@ -916,14 +927,23 @@ def _build_multipart_accept_header_field_value(
916927
f'Transfer syntax "{transfer_syntax_uid}" '
917928
'is not supported for requested resource.'
918929
)
919-
expected_media_type = supported_media_types[
930+
expected_media_types = supported_media_types[
920931
transfer_syntax_uid
921932
]
922-
if expected_media_type != media_type:
923-
have_same_type = (
924-
cls._parse_media_type(media_type)[0] ==
925-
cls._parse_media_type(expected_media_type)[0]
933+
if not isinstance(expected_media_types, tuple):
934+
expected_media_types = (expected_media_types, )
935+
if media_type not in expected_media_types:
936+
have_same_type = next(
937+
(
938+
cls._same_media_type(
939+
media_type, expected_media_type
940+
)
941+
for expected_media_type
942+
in expected_media_types
943+
),
944+
False
926945
)
946+
927947
if (have_same_type and
928948
(media_type.endswith('/*') or
929949
media_type.endswith('/'))):
@@ -1065,13 +1085,13 @@ def _http_get_multipart(
10651085
default_media_type = '*/*'
10661086
supported_media_types = {
10671087
'1.2.840.10008.1.2.1': 'application/octet-stream',
1068-
'1.2.840.10008.1.2.5': 'image/x-dicom-rle',
1088+
'1.2.840.10008.1.2.5': ('image/dicom-rle', 'image/x-dicom-rle'),
10691089
'1.2.840.10008.1.2.4.50': 'image/jpeg',
10701090
'1.2.840.10008.1.2.4.51': 'image/jpeg',
10711091
'1.2.840.10008.1.2.4.57': 'image/jpeg',
10721092
'1.2.840.10008.1.2.4.70': 'image/jpeg',
1073-
'1.2.840.10008.1.2.4.80': 'image/jls',
1074-
'1.2.840.10008.1.2.4.81': 'image/jls',
1093+
'1.2.840.10008.1.2.4.80': ('image/jls', 'image/x-jls'),
1094+
'1.2.840.10008.1.2.4.81': ('image/jls', 'image/x-jls'),
10751095
'1.2.840.10008.1.2.4.90': 'image/jp2',
10761096
'1.2.840.10008.1.2.4.91': 'image/jp2',
10771097
'1.2.840.10008.1.2.4.92': 'image/jpx',
@@ -1189,13 +1209,13 @@ def _http_get_multipart_image(
11891209
""" # noqa: E501
11901210
headers = {}
11911211
supported_media_types = {
1192-
'1.2.840.10008.1.2.5': 'image/x-dicom-rle',
1212+
'1.2.840.10008.1.2.5': ('image/dicom-rle', 'image/x-dicom-rle'),
11931213
'1.2.840.10008.1.2.4.50': 'image/jpeg',
11941214
'1.2.840.10008.1.2.4.51': 'image/jpeg',
11951215
'1.2.840.10008.1.2.4.57': 'image/jpeg',
11961216
'1.2.840.10008.1.2.4.70': 'image/jpeg',
1197-
'1.2.840.10008.1.2.4.80': 'image/jls',
1198-
'1.2.840.10008.1.2.4.81': 'image/jls',
1217+
'1.2.840.10008.1.2.4.80': ('image/jls', 'image/x-jls'),
1218+
'1.2.840.10008.1.2.4.81': ('image/jls', 'image/x-jls'),
11991219
'1.2.840.10008.1.2.4.90': 'image/jp2',
12001220
'1.2.840.10008.1.2.4.91': 'image/jp2',
12011221
'1.2.840.10008.1.2.4.92': 'image/jpx',
@@ -1661,6 +1681,27 @@ def search_for_studies(
16611681
get_remaining=get_remaining
16621682
)
16631683

1684+
@classmethod
1685+
def _same_media_type(cls, first: str, second: str) -> bool:
1686+
"""Check if two media types have the same type.
1687+
1688+
Parameters
1689+
----------
1690+
first: str
1691+
First media type
1692+
second: str
1693+
Second media type
1694+
1695+
Returns
1696+
-------
1697+
bool
1698+
Whether media types have the same type
1699+
1700+
"""
1701+
return (
1702+
cls._parse_media_type(first)[0] == cls._parse_media_type(second)[0]
1703+
)
1704+
16641705
@classmethod
16651706
def _parse_media_type(cls, media_type: str) -> Tuple[str, str]:
16661707
"""Parse media type and extract its type and subtype.

tests/test_web.py

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -880,22 +880,31 @@ def test_retrieve_instance_frames_jp2(httpserver, client, cache_dir):
880880
assert request.accept_mimetypes[0][0][:35] == headers['content-type'][:35]
881881

882882

883-
def test_retrieve_instance_frames_jls(httpserver, client, cache_dir):
883+
@pytest.mark.parametrize(
884+
"media_type", ["image/dicom-rle", "image/x-dicom-rle"]
885+
)
886+
def test_retrieve_instance_frames_jls(
887+
httpserver,
888+
client,
889+
cache_dir,
890+
media_type
891+
):
884892
cache_filename = str(cache_dir.joinpath('retrieve_instance_pixeldata.jls'))
885893
with open(cache_filename, 'rb') as f:
886894
content = f.read()
887-
headers = {
888-
'content-type': 'multipart/related; type="image/jls"',
889-
}
895+
headers = {'content-type': f'multipart/related; type="{media_type}"',}
890896
httpserver.serve_content(content=content, code=200, headers=headers)
891897
study_instance_uid = '1.2.3'
892898
series_instance_uid = '1.2.4'
893899
sop_instance_uid = '1.2.5'
894900
frame_numbers = [114]
895901
frame_list = ','.join([str(n) for n in frame_numbers])
896902
result = client.retrieve_instance_frames(
897-
study_instance_uid, series_instance_uid, sop_instance_uid,
898-
frame_numbers, media_types=('image/jls', )
903+
study_instance_uid,
904+
series_instance_uid,
905+
sop_instance_uid,
906+
frame_numbers,
907+
media_types=(media_type, )
899908
)
900909
assert list(result) == [content]
901910
request = httpserver.requests[0]
@@ -908,6 +917,43 @@ def test_retrieve_instance_frames_jls(httpserver, client, cache_dir):
908917
assert request.path == expected_path
909918
assert request.accept_mimetypes[0][0][:35] == headers['content-type'][:35]
910919

920+
@pytest.mark.parametrize(
921+
"media_type", ["image/dicom-rle", "image/x-dicom-rle"]
922+
)
923+
def test_retrieve_instance_frames_rle(
924+
httpserver,
925+
client,
926+
cache_dir,
927+
media_type
928+
):
929+
cache_filename = str(cache_dir.joinpath('retrieve_instance_pixeldata.rle'))
930+
with open(cache_filename, 'rb') as f:
931+
content = f.read()
932+
headers = {'content-type': f'multipart/related; type="{media_type}"',}
933+
httpserver.serve_content(content=content, code=200, headers=headers)
934+
study_instance_uid = '1.2.3'
935+
series_instance_uid = '1.2.4'
936+
sop_instance_uid = '1.2.5'
937+
frame_numbers = [114]
938+
frame_list = ','.join([str(n) for n in frame_numbers])
939+
result = client.retrieve_instance_frames(
940+
study_instance_uid,
941+
series_instance_uid,
942+
sop_instance_uid,
943+
frame_numbers,
944+
media_types=(media_type, )
945+
)
946+
assert list(result) == [content]
947+
request = httpserver.requests[0]
948+
expected_path = (
949+
f'/studies/{study_instance_uid}'
950+
f'/series/{series_instance_uid}'
951+
f'/instances/{sop_instance_uid}'
952+
f'/frames/{frame_list}'
953+
)
954+
assert request.path == expected_path
955+
assert request.accept_mimetypes[0][0][:36] == headers['content-type'][:36]
956+
911957

912958
def test_retrieve_instance_frames_rendered_jpeg(httpserver, client, cache_dir):
913959
cache_filename = str(cache_dir.joinpath('retrieve_instance_pixeldata.jpg'))

0 commit comments

Comments
 (0)