Skip to content

Commit

Permalink
Metadata fixes (#160)
Browse files Browse the repository at this point in the history
* Truncate dicom long dicom strings

* Remove FlattenOnLoadNestedDicomField

* Staining substance is either a single string or list of codes

* Fix missing 'allow_none' for json fields

* Do not add empty `CodingSchemeVersion` to concept code name
  • Loading branch information
erikogabrielsson authored Mar 18, 2024
1 parent 28f9b2f commit ec4fd2b
Show file tree
Hide file tree
Showing 26 changed files with 458 additions and 315 deletions.
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.20.2] - 2024-02-22

### Fixed

- Fixed handling of string values longer than allowed by value representation.
- Corrected staining substances to be either a single string or a list of codes instead of a list of strings or codes.
- Added `allow_none` for json metadata fields where it was missing.
- Do not add empty `CodingSchemeVersion` to concept code name.

## [0.20.1] - 2024-02-22

### Fixed
Expand Down Expand Up @@ -344,7 +353,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Initial release of wsidicom

[Unreleased]: https://github.com/imi-bigpicture/wsidicom/compare/0.20.1..HEAD
[Unreleased]: https://github.com/imi-bigpicture/wsidicom/compare/0.20.2..HEAD
[0.20.2]: https://github.com/imi-bigpicture/wsidicom/compare/v0.20.1..v0.20.2
[0.20.1]: https://github.com/imi-bigpicture/wsidicom/compare/v0.20.0..v0.20.1
[0.20.0]: https://github.com/imi-bigpicture/wsidicom/compare/v0.19.1..v0.20.0
[0.19.1]: https://github.com/imi-bigpicture/wsidicom/compare/v0.19.0..v0.19.1
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "wsidicom"
version = "0.20.1"
version = "0.20.2"
description = "Tools for handling DICOM based whole scan images"
authors = ["Erik O Gabrielsson <[email protected]>"]
license = "Apache-2.0"
Expand Down
33 changes: 16 additions & 17 deletions tests/metadata/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,12 +345,21 @@ def processing(


@pytest.fixture()
def staining(date_time: datetime.datetime, description: str):
def substances():
yield [
SpecimenStainsCode("hematoxylin stain"),
SpecimenStainsCode("water soluble eosin stain"),
]


@pytest.fixture()
def staining(
substances: Union[str, Sequence[SpecimenStainsCode]],
date_time: datetime.datetime,
description: str,
):
yield Staining(
[
SpecimenStainsCode("hematoxylin stain"),
SpecimenStainsCode("water soluble eosin stain"),
],
substances,
date_time=date_time,
description=description,
)
Expand Down Expand Up @@ -421,7 +430,7 @@ def slide_sample(sample: Sample):


@pytest.fixture()
def slide(slide_identifier: Union[str, SpecimenIdentifier]):
def slide(slide_identifier: Union[str, SpecimenIdentifier], staining: Staining):
part_1 = Specimen(
"part 1",
Collection(
Expand Down Expand Up @@ -503,18 +512,8 @@ def slide(slide_identifier: Union[str, SpecimenIdentifier]):
SampleLocalization(description="right"),
)

stainings = [
Staining(
[
SpecimenStainsCode("hematoxylin stain"),
SpecimenStainsCode("water soluble eosin stain"),
],
date_time=datetime.datetime(2023, 8, 5),
),
]

yield Slide(
identifier=slide_identifier, stainings=stainings, samples=[sample_1, sample_2]
identifier=slide_identifier, stainings=[staining], samples=[sample_1, sample_2]
)


Expand Down
25 changes: 14 additions & 11 deletions tests/metadata/dicom_schema/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,7 @@ def assert_dicom_code_dataset_equals_code(
if expected_code.scheme_version is not None:
assert code_dataset.CodingSchemeVersion == expected_code.scheme_version
else:
assert (
"CodingSchemeVersion" not in code_dataset
or code_dataset.CodingSchemeVersion is None
)
assert "CodingSchemeVersion" not in code_dataset


def assert_dicom_code_sequence_equals_codes(
Expand Down Expand Up @@ -602,12 +599,17 @@ def create_staining_dataset(
):
dataset = Dataset()
items = create_initial_common_preparation_step_items(staining_dicom, identifier)
for substance in staining_dicom.substances:
if isinstance(staining_dicom.substances, str):
items.append(
create_code_item(SampleCodes.using_substance, substance)
if isinstance(substance, SpecimenStainsCode)
else create_string_item(SampleCodes.using_substance, substance)
create_string_item(SampleCodes.using_substance, staining_dicom.substances)
)
else:
for substance in staining_dicom.substances:
items.append(
create_code_item(SampleCodes.using_substance, substance)
if isinstance(substance, SpecimenStainsCode)
else create_string_item(SampleCodes.using_substance, substance)
)
items.extend(create_final_common_preparation_step_items(staining_dicom))
dataset.SpecimenPreparationStepContentItemSequence = items
return dataset
Expand Down Expand Up @@ -647,7 +649,7 @@ def create_specimen_preparation_sequence(
block_sampling_method: SpecimenSamplingProcedureCode,
block_type: AnatomicPathologySpecimenTypesCode,
sampling_location: SamplingLocation,
stains: Sequence[SpecimenStainsCode],
stains: Union[str, Sequence[SpecimenStainsCode]],
specimen_container: Optional[ContainerTypeCode] = None,
block_container: Optional[ContainerTypeCode] = None,
):
Expand Down Expand Up @@ -706,7 +708,7 @@ def create_specimen_preparation_sequence(
staining = create_staining_dataset(
StainingDicomModel(
identifier=slide_sample_id,
substances=list(stains),
substances=stains,
),
identifier=slide_sample_id,
)
Expand Down Expand Up @@ -831,7 +833,8 @@ def create_code_dataset(code: Union[Code, ConceptCode]):
dataset.CodeValue = code.value
dataset.CodingSchemeDesignator = code.scheme_designator
dataset.CodeMeaning = code.meaning
dataset.CodingSchemeVersion = code.scheme_version
if code.scheme_version is not None and code.scheme_version != "":
dataset.CodingSchemeVersion = code.scheme_version
return dataset


Expand Down
44 changes: 36 additions & 8 deletions tests/metadata/dicom_schema/sample/test_dicom_sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import List, Optional, Sequence
from typing import List, Optional, Sequence, Union

import pytest
from pydicom import Dataset
Expand Down Expand Up @@ -105,6 +105,16 @@ class TestSampleDicom:
@pytest.mark.parametrize(
"block_container", [None, ContainerTypeCode("Tissue cassette")]
)
@pytest.mark.parametrize(
"substances",
[
"HE",
[
SpecimenStainsCode("hematoxylin stain"),
SpecimenStainsCode("water soluble eosin stain"),
],
],
)
def test_slide_sample_from_dataset(
self,
slide_sample_ids: Sequence[str],
Expand All @@ -121,7 +131,7 @@ def test_slide_sample_from_dataset(
sample_localization: SampleLocalization,
sampling_location: SamplingLocation,
primary_anatomic_structures: Sequence[Code],
stains: Sequence[SpecimenStainsCode],
substances: Union[str, Sequence[SpecimenStainsCode]],
short_description: Optional[str],
detailed_description: Optional[str],
specimen_container: Optional[ContainerTypeCode],
Expand All @@ -145,7 +155,7 @@ def test_slide_sample_from_dataset(
block_sampling_method,
block_type,
sampling_location,
stains,
substances,
specimen_container,
block_container,
)
Expand Down Expand Up @@ -173,6 +183,9 @@ def test_slide_sample_from_dataset(
# Assert
assert slide_samples is not None
assert stainings is not None
for staining in stainings:
assert isinstance(staining, Staining)
assert staining.substances == substances
assert len(slide_samples) == len(slide_sample_ids)
for slide_sample_index, slide_sample in enumerate(slide_samples):
assert isinstance(slide_sample, SlideSample)
Expand Down Expand Up @@ -246,6 +259,16 @@ def test_slide_sample_from_dataset(
@pytest.mark.parametrize(
"block_container", [None, ContainerTypeCode("Tissue cassette")]
)
@pytest.mark.parametrize(
"substances",
[
"HE",
[
SpecimenStainsCode("hematoxylin stain"),
SpecimenStainsCode("water soluble eosin stain"),
],
],
)
def test_slide_sample_to_dataset(
self,
slide_sample_ids: Sequence[str],
Expand All @@ -262,7 +285,7 @@ def test_slide_sample_to_dataset(
sample_localization: SampleLocalization,
sampling_location: SamplingLocation,
primary_anatomic_structures: Sequence[Code],
stains: Sequence[SpecimenStainsCode],
substances: Union[str, Sequence[SpecimenStainsCode]],
short_description: Optional[str],
detailed_description: Optional[str],
specimen_container: Optional[ContainerTypeCode],
Expand Down Expand Up @@ -308,7 +331,7 @@ def test_slide_sample_to_dataset(
detailed_description=detailed_description,
)
slide_samples.append(slide_sample)
staining = Staining(stains)
staining = Staining(substances)

schema = SpecimenDescriptionDicomSchema()

Expand Down Expand Up @@ -545,10 +568,15 @@ def test_slide_sample_to_dataset(
SampleCodes.processing_type,
SampleCodes.staining,
)
for stain in stains:
assert_next_item_equals_code(
step_item_iterator, SampleCodes.using_substance, stain
if isinstance(substances, str):
assert_next_item_equals_string(
step_item_iterator, SampleCodes.using_substance, substances
)
else:
for substance in substances:
assert_next_item_equals_code(
step_item_iterator, SampleCodes.using_substance, substance
)
assert next(step_item_iterator, None) is None

def test_sampling_from_not_defined_specimen(
Expand Down
Loading

0 comments on commit ec4fd2b

Please sign in to comment.