From 2074628f11fe66cc185a72776e8ab7a009abc52f Mon Sep 17 00:00:00 2001 From: Peter Hessey Date: Tue, 11 Oct 2022 14:07:46 +0100 Subject: [PATCH 1/2] Change timestamp from UTC to local time --- RTConvert/Microsoft.RTConvert.MedIO/RT/DicomRTSeries.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RTConvert/Microsoft.RTConvert.MedIO/RT/DicomRTSeries.cs b/RTConvert/Microsoft.RTConvert.MedIO/RT/DicomRTSeries.cs index f844c67..7478e14 100644 --- a/RTConvert/Microsoft.RTConvert.MedIO/RT/DicomRTSeries.cs +++ b/RTConvert/Microsoft.RTConvert.MedIO/RT/DicomRTSeries.cs @@ -55,7 +55,7 @@ namespace Microsoft.RTConvert.MedIO.RT ds.Add(DicomTag.SeriesNumber, string.Empty); // Type 3 tags - optional but useful - var now = DateTime.UtcNow; + var now = DateTime.Now; var date = now.ToString("yyyyMMdd", CultureInfo.InvariantCulture); var time = now.ToString("HHmmss", CultureInfo.InvariantCulture); ds.Add(DicomTag.SeriesDate, date); From 874d910b6f6eb8fc13b778b5d88149d4e112429f Mon Sep 17 00:00:00 2001 From: Peter Hessey Date: Tue, 11 Oct 2022 14:19:01 +0100 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=9A=A8=20Fix=20flake8=20warnings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build_requirements.txt | 2 +- tests/test_nifti_to_dicom_rt_converter.py | 362 +++++++++++----------- 2 files changed, 180 insertions(+), 184 deletions(-) diff --git a/build_requirements.txt b/build_requirements.txt index 64cd902..a99956f 100644 --- a/build_requirements.txt +++ b/build_requirements.txt @@ -1,5 +1,5 @@ dotnetcore2==2.1.23 -flake8==3.8.4 +flake8==5.0.4 mypy==0.800 pydicom==2.1.2 pytest-cov==2.11.1 diff --git a/tests/test_nifti_to_dicom_rt_converter.py b/tests/test_nifti_to_dicom_rt_converter.py index f1f5721..e48ed18 100644 --- a/tests/test_nifti_to_dicom_rt_converter.py +++ b/tests/test_nifti_to_dicom_rt_converter.py @@ -1,183 +1,179 @@ -# ------------------------------------------------------------------------------------------ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. -# ------------------------------------------------------------------------------------------ - -""" -Tests for nifti_to_dicom_rt_converter. -""" - -import logging -from pathlib import Path -from typing import List -from pydicom import dcmread - -try: - from InnerEye_DICOM_RT.nifti_to_dicom_rt_converter import echo, get_version, rtconvert # type: ignore -except ImportError: - logging.info("using local src") - from src.InnerEye_DICOM_RT.nifti_to_dicom_rt_converter import echo, get_version, rtconvert # type: ignore - -logger = logging.getLogger('test_rtconvert') -logger.setLevel(logging.DEBUG) - - -def test_get_version() -> None: - """ - Test that .dotnet core can be called --info and that it is - running version 2.1. - """ - (stdout, stderr) = get_version() - - logger.debug("stdout: %s", stdout) - logger.debug("stderr: %s", stderr) - - assert stderr == '' - assert 'Microsoft.NETCore.App 2.1.' in stdout - - -def test_echo() -> None: - """ - Test that the test Echo dll can be called and returns the test string and no error. - """ - test_string = "hello world2!" - (stdout, stderr) = echo(test_string) - - logger.debug("stdout: %s", stdout) - logger.debug("stderr: %s", stderr) - - assert stderr == '' - assert stdout == test_string + '\n' - - -def test_echo_err() -> None: - """ - Test that the test Echo dll can be called and returns the test and error strings. - """ - test_string = "hello world2!" - test_error = "Test error." - (stdout, stderr) = echo(test_string, test_error) - - logger.debug("stdout: %s", stdout) - logger.debug("stderr: %s", stderr) - - assert stderr == test_error + '\n' - assert stdout == test_string + '\n' - - -# The directory containing this file. -THIS_DIR: Path = Path(__file__).parent.resolve() -# The TestData directory. -TEST_DATA_DIR: Path = THIS_DIR / "TestData" -# Test Nifti file. -TestNiftiSegmentationLocation: Path = TEST_DATA_DIR / "hnsegmentation.nii.gz" -# Test reference series. -TestDicomVolumeLocation: Path = TEST_DATA_DIR / "HN" -# Target test output file. -TestOutputFile: Path = THIS_DIR / "test.dcm" - -# Test fill holes. -FillHoles: List[bool] = \ - [ - True, True, True, True, - False, False, True, True, - True, True, False, True, - True, True, True, False, - True, False, True, True, - False, True - ] - -# Test ROIInterpretedType. -ROIInterpretedTypes: List[str] = \ - [ - "ORGAN", "None", "CTV", "EXTERNAL", - "ORGAN", "None", "CTV", "EXTERNAL", - "ORGAN", "None", "CTV", "EXTERNAL", - "ORGAN", "None", "CTV", "EXTERNAL", - "ORGAN", "None", "CTV", "EXTERNAL", - "ORGAN", "None" - ] - -# Test structure colors. -StructureColors: List[str] = \ - [ - "FF0001", "FF0002", "FF0003", "FF0004", - "FF0101", "FF0102", "FF0103", "FF0103", - "FF0201", "FF02FF", "FF0203", "FF0204", - "FF0301", "FF0302", "01FF03", "FF0304", - "FF0401", "00FFFF", "FF0403", "FF0404", - "FF0501", "FF0502" - ] - -# Test structure names. -StructureNames: List[str] = \ - [ - "External", "parotid_l", "parotid_r", "smg_l", - "smg_r", "spinal_cord", "brainstem", "globe_l", - "Globe_r", "mandible", "spc_muscle", "mpc_muscle", - "Cochlea_l", "cochlea_r", "lens_l", "lens_r", - "optic_chiasm", "optic_nerve_l", "optic_nerve_r", "pituitary_gland", - "lacrimal_gland_l", "lacrimal_gland_r" - ] - -Manufacturer = "Contosos" -Interpreter = "Ai" -ModelId = "XYZ:12" - -def test_rtconvert() -> None: - """ - Test calling RTConvert for the test data. - """ - (stdout, stderr) = rtconvert( - in_file=TestNiftiSegmentationLocation, - reference_series=TestDicomVolumeLocation, - out_file=TestOutputFile, - struct_names=StructureNames, - struct_colors=StructureColors, - fill_holes=FillHoles, - roi_interpreted_types=ROIInterpretedTypes, - manufacturer=Manufacturer, - interpreter=Interpreter, - modelId=ModelId - ) - - logger.debug("stdout: %s", stdout) - logger.debug("stderr: %s", stderr) - - assert stderr == '' - assert "Successfully written" in stdout - - assert TestOutputFile.is_file() - - with open(TestOutputFile, 'rb') as infile: - ds = dcmread(infile) - - assert ds is not None - - # Check the modality - assert ds.Modality == 'RTSTRUCT' - - assert ds.Manufacturer == Manufacturer - assert ds.SoftwareVersions == ModelId - - assert len(ds.StructureSetROISequence) == len(StructureNames) - - for i, item in enumerate(StructureNames): - assert ds.StructureSetROISequence[i].ROINumber == i + 1 - assert ds.StructureSetROISequence[i].ROIName == item - assert Interpreter in ds.RTROIObservationsSequence[i].ROIInterpreter - assert ds.RTROIObservationsSequence[i].RTROIInterpretedType == ('' if ROIInterpretedTypes[i] == 'None' else ROIInterpretedTypes[i]) - - assert len(ds.ROIContourSequence) == len(StructureNames) - - for i, item in enumerate(StructureNames): - assert ds.ROIContourSequence[i].ReferencedROINumber == i + 1 - assert ds.ROIContourSequence[i].ROIDisplayColor == _parse_rgb(StructureColors[i]) - -def _parse_rgb(rgb: str) -> List[int]: - """ - Convert the string representation of RGB color to an int list - :param rgb: Color string - :return: List of [R, G, B] components. - """ - return [int(rgb[i:i+2], 16) for i in (0, 2, 4)] +# ------------------------------------------------------------------------------------------ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. +# ------------------------------------------------------------------------------------------ + +""" +Tests for nifti_to_dicom_rt_converter. +""" + +import logging +from pathlib import Path +from typing import List +from pydicom import dcmread + +try: + from InnerEye_DICOM_RT.nifti_to_dicom_rt_converter import echo, get_version, rtconvert # type: ignore +except ImportError: + logging.info("using local src") + from src.InnerEye_DICOM_RT.nifti_to_dicom_rt_converter import echo, get_version, rtconvert # type: ignore + +logger = logging.getLogger('test_rtconvert') +logger.setLevel(logging.DEBUG) + + +def test_get_version() -> None: + """ + Test that .dotnet core can be called --info and that it is + running version 2.1. + """ + (stdout, stderr) = get_version() + + logger.debug("stdout: %s", stdout) + logger.debug("stderr: %s", stderr) + + assert stderr == '' + assert 'Microsoft.NETCore.App 2.1.' in stdout + + +def test_echo() -> None: + """ + Test that the test Echo dll can be called and returns the test string and no error. + """ + test_string = "hello world2!" + (stdout, stderr) = echo(test_string) + + logger.debug("stdout: %s", stdout) + logger.debug("stderr: %s", stderr) + + assert stderr == '' + assert stdout == test_string + '\n' + + +def test_echo_err() -> None: + """ + Test that the test Echo dll can be called and returns the test and error strings. + """ + test_string = "hello world2!" + test_error = "Test error." + (stdout, stderr) = echo(test_string, test_error) + + logger.debug("stdout: %s", stdout) + logger.debug("stderr: %s", stderr) + + assert stderr == test_error + '\n' + assert stdout == test_string + '\n' + + +# The directory containing this file. +THIS_DIR: Path = Path(__file__).parent.resolve() +# The TestData directory. +TEST_DATA_DIR: Path = THIS_DIR / "TestData" +# Test Nifti file. +TestNiftiSegmentationLocation: Path = TEST_DATA_DIR / "hnsegmentation.nii.gz" +# Test reference series. +TestDicomVolumeLocation: Path = TEST_DATA_DIR / "HN" +# Target test output file. +TestOutputFile: Path = THIS_DIR / "test.dcm" + +# Test fill holes. +FillHoles: List[bool] = [ + True, True, True, True, + False, False, True, True, + True, True, False, True, + True, True, True, False, + True, False, True, True, + False, True +] + +# Test ROIInterpretedType. +ROIInterpretedTypes: List[str] = [ + "ORGAN", "None", "CTV", "EXTERNAL", + "ORGAN", "None", "CTV", "EXTERNAL", + "ORGAN", "None", "CTV", "EXTERNAL", + "ORGAN", "None", "CTV", "EXTERNAL", + "ORGAN", "None", "CTV", "EXTERNAL", + "ORGAN", "None" +] + +# Test structure colors. +StructureColors: List[str] = [ + "FF0001", "FF0002", "FF0003", "FF0004", + "FF0101", "FF0102", "FF0103", "FF0103", + "FF0201", "FF02FF", "FF0203", "FF0204", + "FF0301", "FF0302", "01FF03", "FF0304", + "FF0401", "00FFFF", "FF0403", "FF0404", + "FF0501", "FF0502" +] + +# Test structure names. +StructureNames: List[str] = [ + "External", "parotid_l", "parotid_r", "smg_l", + "smg_r", "spinal_cord", "brainstem", "globe_l", + "Globe_r", "mandible", "spc_muscle", "mpc_muscle", + "Cochlea_l", "cochlea_r", "lens_l", "lens_r", + "optic_chiasm", "optic_nerve_l", "optic_nerve_r", "pituitary_gland", + "lacrimal_gland_l", "lacrimal_gland_r" +] + +Manufacturer = "Contosos" +Interpreter = "Ai" +ModelId = "XYZ:12" + +def test_rtconvert() -> None: + """ + Test calling RTConvert for the test data. + """ + (stdout, stderr) = rtconvert( + in_file=TestNiftiSegmentationLocation, + reference_series=TestDicomVolumeLocation, + out_file=TestOutputFile, + struct_names=StructureNames, + struct_colors=StructureColors, + fill_holes=FillHoles, + roi_interpreted_types=ROIInterpretedTypes, + manufacturer=Manufacturer, + interpreter=Interpreter, + modelId=ModelId + ) + + logger.debug("stdout: %s", stdout) + logger.debug("stderr: %s", stderr) + + assert stderr == '' + assert "Successfully written" in stdout + + assert TestOutputFile.is_file() + + with open(TestOutputFile, 'rb') as infile: + ds = dcmread(infile) + + assert ds is not None + + # Check the modality + assert ds.Modality == 'RTSTRUCT' + + assert ds.Manufacturer == Manufacturer + assert ds.SoftwareVersions == ModelId + + assert len(ds.StructureSetROISequence) == len(StructureNames) + + for i, item in enumerate(StructureNames): + assert ds.StructureSetROISequence[i].ROINumber == i + 1 + assert ds.StructureSetROISequence[i].ROIName == item + assert Interpreter in ds.RTROIObservationsSequence[i].ROIInterpreter + assert ds.RTROIObservationsSequence[i].RTROIInterpretedType == ('' if ROIInterpretedTypes[i] == 'None' else ROIInterpretedTypes[i]) + + assert len(ds.ROIContourSequence) == len(StructureNames) + + for i, item in enumerate(StructureNames): + assert ds.ROIContourSequence[i].ReferencedROINumber == i + 1 + assert ds.ROIContourSequence[i].ROIDisplayColor == _parse_rgb(StructureColors[i]) + +def _parse_rgb(rgb: str) -> List[int]: + """ + Convert the string representation of RGB color to an int list + :param rgb: Color string + :return: List of [R, G, B] components. + """ + return [int(rgb[i:i+2], 16) for i in (0, 2, 4)]