Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix crash of the dump tool #75

Merged
merged 1 commit into from
Jan 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ The released versions correspond to PyPi releases.
### Features
* added checking of most enumerated values (see [#54](../../issues/54))

### Fixes
* fixed a regression that causes an exception in the DICOM dump tool

### Infrastructure
* added CI tests for Python 3.12

Expand Down
2 changes: 1 addition & 1 deletion dicom_validator/dump_dcm_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def print_element(self, tag_id, name, vr, prop, value):

def print_dataelement(self, _, dataelement):
tag_id = f"({dataelement.tag.group:04X},{dataelement.tag.element:04X})"
description = self.dict_info.get(tag_id)
description = self.dicom_info.dictionary.get(tag_id)
if description is None:
name = "[Unknown]"
vr = dataelement.VR
Expand Down
24 changes: 16 additions & 8 deletions dicom_validator/spec_reader/enum_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ class EnumParser:
"""Parses enumerated values for a tag."""

docbook_ns = "{http://docbook.org/ns/docbook}"
nr_direct_enums = 0
nr_linked_enums = 0

def __init__(
self, find_section: Callable[[str], Optional[ElementTree.Element]]
Expand All @@ -32,6 +34,10 @@ def parse(self, node: ElementTree.Element, vr: VR) -> ValuesType:
enums = self.parse_linked_variablelist(node)
if enums:
if vr == VR.AT:
# print(
# f"Ignoring enum values: "
# f"{', '.join([str(e) for e in enums])} with VR {vr}"
# )
return [] # this is included in INT_VRs, but won't work
if vr in INT_VR:
int_enums: ValuesType = []
Expand All @@ -41,25 +47,24 @@ def parse(self, node: ElementTree.Element, vr: VR) -> ValuesType:
int_enums.append(int(e[:-1], 16))
else:
int_enums.append(int(e))
self.__class__.nr_direct_enums += 1
return int_enums
if vr in STR_VR:
self.__class__.nr_direct_enums += 1
return enums
# any other VR does not make sense here
print(
f"Ignoring enum values: "
f"{', '.join([str(e) for e in enums])} with VR {vr}"
)
# print(
# f"Ignoring enum values: "
# f"{', '.join([str(e) for e in enums])} with VR {vr}"
# )
return []

def parse_variable_list(self, var_list) -> ValuesType:
# we assume that a variablelist contains enumerated values or defined terms
# we ignore defined terms, as they do not limit the possible values
title = var_list.find(self.docbook_ns + "title")
# TODO: handle cases with conditions
if title is None or title.text.lower() not in (
"enumerated values",
"enumerated values:",
):
if title is None or title.text.lower() not in ("enumerated values:",):
return []
terms = []
for item in var_list.findall(self.docbook_ns + "varlistentry"):
Expand All @@ -79,5 +84,8 @@ def parse_linked_variablelist(self, node) -> ValuesType:
var_list = section.find(f"{self.docbook_ns}variablelist")
if var_list is not None:
self._enum_cache[link] = self.parse_variable_list(var_list)
if self._enum_cache[link]:
self.__class__.nr_linked_enums += 1
# print("LINK:", link, self._enum_cache[link])
return self._enum_cache[link]
return []
4 changes: 2 additions & 2 deletions dicom_validator/spec_reader/part3_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def iod_description(self, chapter):
"""
if chapter not in self._iod_descriptions:
iod_node = self._get_iod_nodes().get(chapter)
if iod_node:
if iod_node is not None and len(iod_node) > 0:
description = self._parse_iod_node(iod_node)
self._iod_descriptions[chapter] = description
try:
Expand Down Expand Up @@ -192,7 +192,7 @@ def _parse_module_description(self, parent_node):
tag_name, columns, current_descriptions
)
else:
# todo: other entries
# not a valid entry, no need to handle
pass
return current_descriptions[0]

Expand Down
3 changes: 3 additions & 0 deletions dicom_validator/tests/test_cmdline_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import pytest

from dicom_validator.spec_reader.enum_parser import EnumParser
from dicom_validator.validate_iods import main

CURRENT_REVISION = "2023c"
Expand Down Expand Up @@ -41,3 +42,5 @@ def test_validate_sr(caplog, standard_path, dicom_fixture_path):
# regression test for #9
assert "Unknown SOPClassUID" not in caplog.text
assert "Tag (0008,1070) (Operators' Name) is missing" in caplog.text

print(f"Direct: {EnumParser.nr_direct_enums}, linked: {EnumParser.nr_linked_enums}")