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

Add handling of conditional includes #43

Merged
merged 1 commit into from
Aug 22, 2023
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.
### Changes
* removed official support for Python 3.7 which has reached end of life

### Features
* added handling of conditional includes (needed for SR documents)
(see [#39](../.. /issues/39))
### Infrastructure
* use `pyproject.toml` instead of `setup.py`

Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,16 @@ pip install dicom-validator

## Usage
```
validate_iods.py [-h] [--standard-path STANDARD_PATH]
[--revision REVISION] [--force-read] [--recreate-json]
[--verbose]
dicomfiles [dicomfiles ...]

dump_dcm_info.py [-h] [--standard-path STANDARD_PATH]
[--revision REVISION] [--max-value-len MAX_VALUE_LEN]
[--show-tags [SHOW_TAGS [SHOW_TAGS ...]]]
[--show-image-data] [--recreate-json]
dicomfiles [dicomfiles ...]
validate_iods.py [-h] [--standard-path STANDARD_PATH]
[--revision REVISION] [--force-read] [--recreate-json]
[--verbose]
dicomfiles [dicomfiles ...]
```
Use the `--help` option for each script do get usage info.

Expand Down
27 changes: 19 additions & 8 deletions dicom_validator/spec_reader/part3_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,13 +183,15 @@ def _parse_module_description(self, parent_node):
columns, current_descriptions, last_tag_id, tag_name
)
elif tag_name.startswith("Include"):
self._handle_included_attributes(columns, current_descriptions)
self._handle_included_attributes(
tag_name, columns, current_descriptions
)
else:
# todo: other entries
pass
return current_descriptions[0]

def _handle_included_attributes(self, columns, current_descriptions):
def _handle_included_attributes(self, text, columns, current_descriptions):
include_node = self._find(columns[0], ["para", "emphasis", "xref"])
if include_node is None:
description = self._find_text(columns[0])
Expand All @@ -199,7 +201,9 @@ def _handle_included_attributes(self, columns, current_descriptions):
)
if is_func_group:
# add a placeholder - has to be evaluated at validation time
current_descriptions[-1].setdefault("include", []).append("FuncGroup")
current_descriptions[-1].setdefault("include", []).append(
{"ref": "FuncGroup"}
)
return
include_ref = include_node.attrib["linkend"]
if self._current_refs and include_ref == self._current_refs[-1]:
Expand All @@ -216,7 +220,18 @@ def _handle_included_attributes(self, columns, current_descriptions):
# it is allowed to have no attributes (example: Raw Data)
ref_description = self._parse_module_description(ref_node) or {}
self._module_descriptions[label] = ref_description
current_descriptions[-1].setdefault("include", []).append(label)
include_attr = {"ref": label}
# this is currently the only occurring condition for includes
cond_prefix = "if and only if "
cond_index = text.find(cond_prefix)
if cond_index > 0:
# we replace the prefix to avois special handling in the parser
cond_text = text[cond_index:].replace(cond_prefix, "required if ")
condition = self._condition_parser.parse(cond_text)
# the parser will put "MU", which makes no sense for includes
condition.type = "MN"
include_attr["cond"] = condition
current_descriptions[-1].setdefault("include", []).append(include_attr)
self._current_refs.pop()

def _handle_regular_attribute(
Expand All @@ -230,10 +245,6 @@ def _handle_regular_attribute(
"type": tag_type,
}
if tag_type in ("1C", "2C"):
# cond = self._find_all_text(columns[3])
# index = cond.find('Required if ')
# if index >= 0:
# current_descriptions[-1][tag_id]['desc'] = cond[index:]
current_descriptions[-1][tag_id]["cond"] = self._condition_parser.parse(
self._find_all_text(columns[3])
)
Expand Down
3,049 changes: 3,049 additions & 0 deletions dicom_validator/tests/fixtures/2021d/docbook/part03.xml

Large diffs are not rendered by default.

61 changes: 61 additions & 0 deletions dicom_validator/tests/fixtures/2021d/json/iod_info.json
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,67 @@
},
"title": "VL Whole Slide Microscopy Image IOD"
},
"1.2.840.10008.5.1.4.1.1.88.67": {
"group_macros": {},
"modules": {
"Clinical Trial Series": {
"ref": "C.7.3.2",
"use": "U"
},
"Clinical Trial Study": {
"ref": "C.7.2.3",
"use": "U"
},
"Clinical Trial Subject": {
"ref": "C.7.1.3",
"use": "U"
},
"Enhanced General Equipment": {
"ref": "C.7.5.2",
"use": "M"
},
"General Equipment": {
"ref": "C.7.5.1",
"use": "M"
},
"General Study": {
"ref": "C.7.2.1",
"use": "M"
},
"Patient": {
"ref": "C.7.1.1",
"use": "M"
},
"Patient Study": {
"ref": "C.7.2.2",
"use": "U"
},
"SOP Common": {
"ref": "C.12.1",
"use": "M"
},
"SR Document Content": {
"ref": "C.17.3",
"use": "M"
},
"SR Document General": {
"ref": "C.17.2",
"use": "M"
},
"SR Document Series": {
"ref": "C.17.1",
"use": "M"
},
"Synchronization": {
"cond": {
"type": "U"
},
"ref": "C.7.4.2",
"use": "C - shall be present if system time is synchronized to an external reference. May be present otherwise."
}
},
"title": "X-Ray Radiation Dose SR IOD"
},
"1.2.840.10008.5.1.4.1.1.481.2": {
"group_macros": {},
"modules": {
Expand Down
Loading