diff --git a/presidio-image-redactor/presidio_image_redactor/dicom_image_redactor_engine.py b/presidio-image-redactor/presidio_image_redactor/dicom_image_redactor_engine.py index d99f339fa..552297cdc 100644 --- a/presidio-image-redactor/presidio_image_redactor/dicom_image_redactor_engine.py +++ b/presidio-image-redactor/presidio_image_redactor/dicom_image_redactor_engine.py @@ -16,7 +16,9 @@ from presidio_image_redactor import ImageRedactorEngine from presidio_image_redactor import ImageAnalyzerEngine # noqa: F401 +import presidio_analyzer # required for isinstance check which throws an error when trying to specify PatternRecognizer # noqa: E501 from presidio_analyzer import PatternRecognizer +from presidio_image_redactor.entities import ImageRecognizerResult class DicomImageRedactorEngine(ImageRedactorEngine): @@ -31,7 +33,9 @@ def redact_and_return_bbox( fill: str = "contrast", padding_width: int = 25, crop_ratio: float = 0.75, + use_metadata: bool = True, ocr_kwargs: Optional[dict] = None, + ad_hoc_recognizers: Optional[List[PatternRecognizer]] = None, **text_analyzer_kwargs, ) -> Tuple[pydicom.dataset.FileDataset, List[Dict[str, int]]]: """Redact method to redact the given DICOM image and return redacted bboxes. @@ -44,7 +48,11 @@ def redact_and_return_bbox( :param padding_width: Padding width to use when running OCR. :param crop_ratio: Portion of image to consider when selecting most common pixel value as the background color value. + :param use_metadata: Whether to redact text in the image that + are present in the metadata. :param ocr_kwargs: Additional params for OCR methods. + :param ad_hoc_recognizers: List of PatternRecognizer objects to use + for ad-hoc recognizer. :param text_analyzer_kwargs: Additional values for the analyze method in AnalyzerEngine. @@ -76,17 +84,10 @@ def redact_and_return_bbox( loaded_image = Image.open(png_filepath) image = self._add_padding(loaded_image, is_greyscale, padding_width) - # Create custom recognizer using DICOM metadata - original_metadata, is_name, is_patient = self._get_text_metadata(instance) - phi_list = self._make_phi_list(original_metadata, is_name, is_patient) - deny_list_recognizer = PatternRecognizer( - supported_entity="PERSON", deny_list=phi_list - ) - analyzer_results = self.image_analyzer_engine.analyze( - image, - ocr_kwargs=ocr_kwargs, - ad_hoc_recognizers=[deny_list_recognizer], - **text_analyzer_kwargs, + # Detect PII + analyzer_results = self._get_analyzer_results( + image, instance, use_metadata, ocr_kwargs, ad_hoc_recognizers, + **text_analyzer_kwargs ) # Redact all bounding boxes from DICOM file @@ -107,6 +108,7 @@ def redact( padding_width: int = 25, crop_ratio: float = 0.75, ocr_kwargs: Optional[dict] = None, + ad_hoc_recognizers: Optional[List[PatternRecognizer]] = None, **text_analyzer_kwargs, ) -> pydicom.dataset.FileDataset: """Redact method to redact the given DICOM image. @@ -120,6 +122,8 @@ def redact( :param crop_ratio: Portion of image to consider when selecting most common pixel value as the background color value. :param ocr_kwargs: Additional params for OCR methods. + :param ad_hoc_recognizers: List of PatternRecognizer objects to use + for ad-hoc recognizer. :param text_analyzer_kwargs: Additional values for the analyze method in AnalyzerEngine. @@ -131,6 +135,7 @@ def redact( padding_width=padding_width, crop_ratio=crop_ratio, ocr_kwargs=ocr_kwargs, + ad_hoc_recognizers=ad_hoc_recognizers, **text_analyzer_kwargs ) @@ -143,8 +148,10 @@ def redact_from_file( padding_width: int = 25, crop_ratio: float = 0.75, fill: str = "contrast", + use_metadata: bool = True, save_bboxes: bool = False, ocr_kwargs: Optional[dict] = None, + ad_hoc_recognizers: Optional[List[PatternRecognizer]] = None, **text_analyzer_kwargs, ) -> None: """Redact method to redact from a given file. @@ -157,8 +164,12 @@ def redact_from_file( :param padding_width : Padding width to use when running OCR. :param fill: Color setting to use for redaction box ("contrast" or "background"). + :param use_metadata: Whether to redact text in the image that + are present in the metadata. :param save_bboxes: True if we want to save boundings boxes. :param ocr_kwargs: Additional params for OCR methods. + :param ad_hoc_recognizers: List of PatternRecognizer objects to use + for ad-hoc recognizer. :param text_analyzer_kwargs: Additional values for the analyze method in AnalyzerEngine. """ @@ -181,10 +192,12 @@ def redact_from_file( crop_ratio=crop_ratio, fill=fill, padding_width=padding_width, + use_metadata=use_metadata, overwrite=True, dst_parent_dir=".", save_bboxes=save_bboxes, ocr_kwargs=ocr_kwargs, + ad_hoc_recognizers=ad_hoc_recognizers, **text_analyzer_kwargs, ) @@ -199,8 +212,10 @@ def redact_from_directory( padding_width: int = 25, crop_ratio: float = 0.75, fill: str = "contrast", + use_metadata: bool = True, save_bboxes: bool = False, ocr_kwargs: Optional[dict] = None, + ad_hoc_recognizers: Optional[List[PatternRecognizer]] = None, **text_analyzer_kwargs, ) -> None: """Redact method to redact from a directory of files. @@ -215,8 +230,12 @@ def redact_from_directory( most common pixel value as the background color value. :param fill: Color setting to use for redaction box ("contrast" or "background"). + :param use_metadata: Whether to redact text in the image that + are present in the metadata. :param save_bboxes: True if we want to save boundings boxes. :param ocr_kwargs: Additional params for OCR methods. + :param ad_hoc_recognizers: List of PatternRecognizer objects to use + for ad-hoc recognizer. :param text_analyzer_kwargs: Additional values for the analyze method in AnalyzerEngine. """ @@ -239,6 +258,8 @@ def redact_from_directory( crop_ratio=crop_ratio, fill=fill, padding_width=padding_width, + use_metadata=use_metadata, + ad_hoc_recognizers=ad_hoc_recognizers, overwrite=True, dst_parent_dir=".", save_bboxes=save_bboxes, @@ -858,6 +879,75 @@ def _add_redact_box( return redacted_instance + def _get_analyzer_results( + self, + image: PIL.PngImagePlugin.PngImageFile, + instance: pydicom.dataset.FileDataset, + use_metadata: bool, + ocr_kwargs: Optional[dict], + ad_hoc_recognizers: Optional[List[PatternRecognizer]], + **text_analyzer_kwargs + ) -> List[ImageRecognizerResult]: + """Analyze image with selected redaction approach. + + :param image: DICOM pixel data as PIL image. + :param instance: DICOM instance (with metadata). + :param use_metadata: Whether to redact text in the image that + are present in the metadata. + :param ocr_kwargs: Additional params for OCR methods. + :param ad_hoc_recognizers: List of PatternRecognizer objects to use + for ad-hoc recognizer. + :param text_analyzer_kwargs: Additional values for the analyze method + in AnalyzerEngine (e.g., allow_list). + + :return: Analyzer results. + """ + # Check the ad-hoc recognizers list + if isinstance(ad_hoc_recognizers, (list, type(None))): + if isinstance(ad_hoc_recognizers, list): + if len(ad_hoc_recognizers) >= 1: + are_recognizers = all(isinstance(x, presidio_analyzer.pattern_recognizer.PatternRecognizer) for x in ad_hoc_recognizers) # noqa: E501 + if are_recognizers is False: + raise TypeError("All items in ad_hoc_recognizers list must be PatternRecognizer objects") # noqa: E501 + else: + raise TypeError("ad_hoc_recognizers must be None or list of PatternRecognizer") # noqa: E501 + else: + raise TypeError("ad_hoc_recognizers must be None or list of PatternRecognizer") # noqa: E501 + + # Create custom recognizer using DICOM metadata + if use_metadata: + original_metadata, is_name, is_patient = self._get_text_metadata( + instance + ) + phi_list = self._make_phi_list( + original_metadata, is_name, is_patient + ) + deny_list_recognizer = PatternRecognizer( + supported_entity="PERSON", deny_list=phi_list + ) + + if type(ad_hoc_recognizers) is None: + ad_hoc_recognizers = [deny_list_recognizer] + elif type(ad_hoc_recognizers) is list: + ad_hoc_recognizers.append(deny_list_recognizer) + + # Detect PII + if ad_hoc_recognizers is None: + analyzer_results = self.image_analyzer_engine.analyze( + image, + ocr_kwargs=ocr_kwargs, + **text_analyzer_kwargs, + ) + else: + analyzer_results = self.image_analyzer_engine.analyze( + image, + ocr_kwargs=ocr_kwargs, + ad_hoc_recognizers=ad_hoc_recognizers, + **text_analyzer_kwargs, + ) + + return analyzer_results + @staticmethod def _save_bbox_json(output_dcm_path: str, bboxes: List[Dict[str, int]]) -> None: """Save the redacted bounding box info as a json file. @@ -877,10 +967,12 @@ def _redact_single_dicom_image( crop_ratio: float, fill: str, padding_width: int, + use_metadata: bool, overwrite: bool, dst_parent_dir: str, save_bboxes: bool, ocr_kwargs: Optional[dict] = None, + ad_hoc_recognizers: Optional[List[PatternRecognizer]] = None, **text_analyzer_kwargs, ) -> str: """Redact text PHI present on a DICOM image. @@ -891,11 +983,15 @@ def _redact_single_dicom_image( :param fill: Color setting to use for bounding boxes ("contrast" or "background"). :param padding_width: Pixel width of padding (uniform). + :param use_metadata: Whether to redact text in the image that + are present in the metadata. :param overwrite: Only set to True if you are providing the duplicated DICOM path in dcm_path. :param dst_parent_dir: String path to parent directory of where to store copies. :param save_bboxes: True if we want to save boundings boxes. :param ocr_kwargs: Additional params for OCR methods. + :param ad_hoc_recognizers: List of PatternRecognizer objects to use + for ad-hoc recognizer. :param text_analyzer_kwargs: Additional values for the analyze method in AnalyzerEngine. @@ -929,17 +1025,10 @@ def _redact_single_dicom_image( loaded_image = Image.open(png_filepath) image = self._add_padding(loaded_image, is_greyscale, padding_width) - # Create custom recognizer using DICOM metadata - original_metadata, is_name, is_patient = self._get_text_metadata(instance) - phi_list = self._make_phi_list(original_metadata, is_name, is_patient) - deny_list_recognizer = PatternRecognizer( - supported_entity="PERSON", deny_list=phi_list - ) - analyzer_results = self.image_analyzer_engine.analyze( - image, - ocr_kwargs=ocr_kwargs, - ad_hoc_recognizers=[deny_list_recognizer], - **text_analyzer_kwargs, + # Detect PII + analyzer_results = self._get_analyzer_results( + image, instance, use_metadata, ocr_kwargs, ad_hoc_recognizers, + **text_analyzer_kwargs ) # Redact all bounding boxes from DICOM file @@ -966,10 +1055,12 @@ def _redact_multiple_dicom_images( crop_ratio: float, fill: str, padding_width: int, + use_metadata: bool, overwrite: bool, dst_parent_dir: str, save_bboxes: bool, ocr_kwargs: Optional[dict] = None, + ad_hoc_recognizers: Optional[List[PatternRecognizer]] = None, **text_analyzer_kwargs, ) -> str: """Redact text PHI present on all DICOM images in a directory. @@ -980,11 +1071,15 @@ def _redact_multiple_dicom_images( :param fill: Color setting to use for bounding boxes ("contrast" or "background"). :param padding_width: Pixel width of padding (uniform). + :param use_metadata: Whether to redact text in the image that + are present in the metadata. :param overwrite: Only set to True if you are providing the duplicated DICOM dir in dcm_dir. :param dst_parent_dir: String path to parent directory of where to store copies. :param save_bboxes: True if we want to save boundings boxes. :param ocr_kwargs: Additional params for OCR methods. + :param ad_hoc_recognizers: List of PatternRecognizer objects to use + for ad-hoc recognizer. :param text_analyzer_kwargs: Additional values for the analyze method in AnalyzerEngine. @@ -1011,10 +1106,12 @@ def _redact_multiple_dicom_images( crop_ratio, fill, padding_width, + use_metadata, overwrite, dst_parent_dir, save_bboxes, ocr_kwargs=ocr_kwargs, + ad_hoc_recognizers=ad_hoc_recognizers, **text_analyzer_kwargs, ) diff --git a/presidio-image-redactor/tests/integration/test_dicom_image_redactor_engine_integration.py b/presidio-image-redactor/tests/integration/test_dicom_image_redactor_engine_integration.py index eae298a7c..3d2aabb60 100644 --- a/presidio-image-redactor/tests/integration/test_dicom_image_redactor_engine_integration.py +++ b/presidio-image-redactor/tests/integration/test_dicom_image_redactor_engine_integration.py @@ -43,7 +43,7 @@ def test_redact_image_correctly( dcm_filepath (Path): Path to DICOM file to load. """ test_image = pydicom.dcmread(dcm_filepath) - test_redacted_image = mock_engine.redact(test_image) + test_redacted_image = mock_engine.redact(test_image, use_metadata=True) assert ( np.array_equal(test_image.pixel_array, test_redacted_image.pixel_array) is False @@ -63,6 +63,7 @@ def test_redact_from_single_file_correctly(mock_engine: DicomImageRedactorEngine input_dicom_path=str(input_path), output_dir=tmpdirname, fill="contrast", + use_metadata=True ) output_path = Path(tmpdirname, f"{input_path.stem}.dcm") @@ -105,6 +106,7 @@ def test_redact_from_directory_correctly(mock_engine: DicomImageRedactorEngine): input_dicom_path=str(input_path), output_dir=tmpdirname, fill="contrast", + use_metadata=True ) # Get list of all DICOM files diff --git a/presidio-image-redactor/tests/test_dicom_image_redactor_engine.py b/presidio-image-redactor/tests/test_dicom_image_redactor_engine.py index e256e8234..5b432b366 100644 --- a/presidio-image-redactor/tests/test_dicom_image_redactor_engine.py +++ b/presidio-image-redactor/tests/test_dicom_image_redactor_engine.py @@ -7,7 +7,8 @@ from PIL import Image import pydicom from presidio_image_redactor.dicom_image_redactor_engine import DicomImageRedactorEngine -from typing import Union, List, Tuple, Dict, TypeVar +from presidio_analyzer import PatternRecognizer +from typing import Union, List, Tuple, Dict, TypeVar, Optional import pytest T = TypeVar('T') @@ -1157,6 +1158,126 @@ def test_add_redact_box_happy_path( assert box_color_pixels_redacted > box_color_pixels_original +# ------------------------------------------------------ +# DicomImageRedactorEngine._get_analyzer_results() +# ------------------------------------------------------ +@pytest.mark.parametrize( + "image, dcm_path, use_metadata, ad_hoc_recognizers", + [ + ( + Image.fromarray(np.random.randint(255, size=(400, 400),dtype=np.uint8)), + Path(TEST_DICOM_PARENT_DIR, "0_ORIGINAL.dcm"), + False, + None + ), + ( + Image.fromarray(np.random.randint(255, size=(400, 400),dtype=np.uint8)), + Path(TEST_DICOM_PARENT_DIR, "0_ORIGINAL.dcm"), + False, + [PatternRecognizer(supported_entity="PERSON", deny_list=["1"])] + ), + ( + Image.fromarray(np.random.randint(255, size=(400, 400),dtype=np.uint8)), + Path(TEST_DICOM_PARENT_DIR, "0_ORIGINAL.dcm"), + True, + None + ), + ( + Image.fromarray(np.random.randint(255, size=(400, 400),dtype=np.uint8)), + Path(TEST_DICOM_PARENT_DIR, "0_ORIGINAL.dcm"), + True, + [PatternRecognizer(supported_entity="PERSON", deny_list=["2"])] + ), + ], +) +def test_get_analyzer_results_happy_path( + mocker, + mock_engine: DicomImageRedactorEngine, + image: Image, + dcm_path: str, + use_metadata: bool, + ad_hoc_recognizers: Optional[List[PatternRecognizer]] +): + """Test happy path for DicomImageRedactorEngine._get_analyzer_results + + Args: + mock_engine (DicomImageRedactorEngine): DicomImageRedactorEngine object. + image (PIL.Image): A PIL image. + dcm_path (pathlib.Path): Path to DICOM file. + use_metadata (bool): Whether to consider metadata when running analysis. + ad_hoc_recognizers(None or list): Ad-hoc recognizers to use. + """ + # Arrange + mock_analyze = mocker.patch( + "presidio_image_redactor.dicom_image_redactor_engine.ImageAnalyzerEngine.analyze", + return_value=None, + ) + mock_get_text_metadata = mocker.patch( + "presidio_image_redactor.dicom_image_redactor_engine.DicomImageRedactorEngine._get_text_metadata", + return_value=[None, None, None], + ) + mock_make_phi_list = mocker.patch( + "presidio_image_redactor.dicom_image_redactor_engine.DicomImageRedactorEngine._make_phi_list", + return_value=None, + ) + mock_pattern_recognizer = mocker.patch( + "presidio_image_redactor.dicom_image_redactor_engine.PatternRecognizer", + return_value=None, + ) + test_instance = pydicom.dcmread(dcm_path) + + # Act + _ = mock_engine._get_analyzer_results( + image=image, + instance=test_instance, + use_metadata=use_metadata, + ocr_kwargs=None, + ad_hoc_recognizers=ad_hoc_recognizers + ) + + # Assert + if use_metadata is False: + mock_analyze.assert_called_once() + mock_get_text_metadata.assert_not_called() + mock_make_phi_list.assert_not_called() + mock_pattern_recognizer.assert_not_called() + elif use_metadata is True: + mock_analyze.assert_called_once() + mock_get_text_metadata.assert_called_once() + mock_make_phi_list.assert_called_once() + mock_pattern_recognizer.assert_called_once() + +@pytest.mark.parametrize( + "ad_hoc_recognizers", + [ + ("invalidType"), + ([]), + ([PatternRecognizer(supported_entity="TITLE", deny_list=["Mr", "Ms"]), 2]) + ], +) +def test_get_analyzer_results_exceptions( + mock_engine: DicomImageRedactorEngine, + ad_hoc_recognizers: Optional[List[PatternRecognizer]], +): + """Test error handling of DicomImageRedactorEngine _get_analyzer_results() + + Args: + mock_engine (DicomImageRedactorEngine): DicomImageRedactorEngine object. + ad_hoc_recognizers(None or list): Ad-hoc recognizers to use. + """ + with pytest.raises(Exception): + # Arrange + image = Image.fromarray(np.random.randint(255, size=(400, 400),dtype=np.uint8)) + test_instance = pydicom.dcmread(Path(TEST_DICOM_PARENT_DIR, "0_ORIGINAL.dcm")) + + # Act + _ = mock_engine._get_analyzer_results( + image=image, + instance=test_instance, + use_metadata=True, + ocr_kwargs=None, + ad_hoc_recognizers=ad_hoc_recognizers + ) # ------------------------------------------------------ # DicomImageRedactorEngine redact_and_return_bbox() @@ -1204,23 +1325,8 @@ def test_DicomImageRedactorEngine_redact_and_return_bbox( "presidio_image_redactor.dicom_image_redactor_engine.DicomImageRedactorEngine._add_padding", return_value=None, ) - - mock_get_text_metadata = mocker.patch( - "presidio_image_redactor.dicom_image_redactor_engine.DicomImageRedactorEngine._get_text_metadata", - return_value=[None, None, None], - ) - mock_make_phi_list = mocker.patch( - "presidio_image_redactor.dicom_image_redactor_engine.DicomImageRedactorEngine._make_phi_list", - return_value=None, - ) - - mock_pattern_recognizer = mocker.patch( - "presidio_image_redactor.dicom_image_redactor_engine.PatternRecognizer", - return_value=None, - ) - mock_analyze = mocker.patch( - "presidio_image_redactor.dicom_image_redactor_engine.ImageAnalyzerEngine.analyze", + "presidio_image_redactor.dicom_image_redactor_engine.DicomImageRedactorEngine._get_analyzer_results", return_value=None, ) @@ -1240,7 +1346,7 @@ def test_DicomImageRedactorEngine_redact_and_return_bbox( ) # Act - test_redacted_image, test_bboxes = mock_engine.redact_and_return_bbox(test_image) + test_redacted_image, _ = mock_engine.redact_and_return_bbox(test_image, use_metadata=True) # Assert assert type(test_redacted_image) in [pydicom.dataset.FileDataset, pydicom.dataset.Dataset] @@ -1250,9 +1356,6 @@ def test_DicomImageRedactorEngine_redact_and_return_bbox( mock_save_pixel_array.assert_called_once() mock_image_open.assert_called_once() mock_add_padding.assert_called_once() - mock_get_text_metadata.assert_called_once() - mock_make_phi_list.assert_called_once() - mock_pattern_recognizer.assert_called_once() mock_analyze.assert_called_once() mock_get_analyze_bbox.assert_called_once() mock_remove_bbox_padding.assert_called_once() @@ -1290,7 +1393,8 @@ def test_DicomImageRedactorEngine_redact_and_return_bbox_exceptions( else: test_image = image # Act - mock_engine.redact_and_return_bbox(test_image) + mock_engine.redact(test_image, fill="contrast", padding_width=25, use_metadata=True + ) # Assert assert exc_info.typename in expected_error_type @@ -1300,25 +1404,24 @@ def test_DicomImageRedactorEngine_redact_and_return_bbox_exceptions( # ------------------------------------------------------ def test_DicomImageRedactorEngine_redact_happy_path( mocker, + mock_engine: DicomImageRedactorEngine, ): """Test happy path for DicomImageRedactorEngine redact() """ # Arrange test_image = pydicom.dcmread(Path(TEST_DICOM_PARENT_DIR, "0_ORIGINAL.dcm")) - mock_redact_return_bbox = mocker.patch.object( - DicomImageRedactorEngine, - "redact_and_return_bbox", + mock_redact_return_bbox = mocker.patch( + "presidio_image_redactor.dicom_image_redactor_engine.DicomImageRedactorEngine.redact_and_return_bbox", return_value=[test_image, [{}, {}, {}]] ) - test_mock_redact_engine = DicomImageRedactorEngine() # Act - test_redacted_image = test_mock_redact_engine.redact(test_image) + test_redacted_image = mock_engine.redact(test_image) # Assert assert type(test_redacted_image) in [pydicom.dataset.FileDataset, pydicom.dataset.Dataset] - assert mock_redact_return_bbox.call_count == 1 + mock_redact_return_bbox.assert_called_once() # ------------------------------------------------------ # DicomImageRedactorEngine _save_bbox_json() @@ -1451,22 +1554,9 @@ def test_DicomImageRedactorEngine_redact_single_dicom_image_happy_path( "presidio_image_redactor.dicom_image_redactor_engine.DicomImageRedactorEngine._add_padding", return_value=None, ) - mock_get_text_metadata = mocker.patch( - "presidio_image_redactor.dicom_image_redactor_engine.DicomImageRedactorEngine._get_text_metadata", - return_value=[None, None, None], - ) - mock_make_phi_list = mocker.patch( - "presidio_image_redactor.dicom_image_redactor_engine.DicomImageRedactorEngine._make_phi_list", - return_value=None, - ) - - mock_pattern_recognizer = mocker.patch( - "presidio_image_redactor.dicom_image_redactor_engine.PatternRecognizer", - return_value=None, - ) mock_analyze = mocker.patch( - "presidio_image_redactor.dicom_image_redactor_engine.ImageAnalyzerEngine.analyze", + "presidio_image_redactor.dicom_image_redactor_engine.DicomImageRedactorEngine._get_analyzer_results", return_value=None, ) @@ -1491,7 +1581,14 @@ def save_as(self, dst_path: str): # Act mock_engine._redact_single_dicom_image( - dcm_path, crop_ratio, "contrast", 25, overwrite, output_dir, False + dcm_path=dcm_path, + crop_ratio=crop_ratio, + fill="contrast", + padding_width=25, + use_metadata=True, + overwrite=overwrite, + dst_parent_dir=output_dir, + save_bboxes=False ) # Assert @@ -1502,9 +1599,6 @@ def save_as(self, dst_path: str): assert mock_convert_dcm_to_png.call_count == 1 assert mock_image_open.call_count == 1 assert mock_add_padding.call_count == 1 - assert mock_get_text_metadata.call_count == 1 - assert mock_make_phi_list.call_count == 1 - assert mock_pattern_recognizer.call_count == 1 assert mock_analyze.call_count == 1 assert mock_get_analyze_bbox.call_count == 1 assert mock_remove_bbox_padding.call_count == 1 @@ -1533,7 +1627,14 @@ def test_DicomImageRedactorEngine_redact_single_dicom_image_exceptions( with pytest.raises(Exception) as exc_info: # Act mock_engine._redact_single_dicom_image( - dcm_path, 0.75, "contrast", 25, False, ".", False + dcm_path=dcm_path, + crop_ratio=0.75, + fill="contrast", + padding_width=25, + use_metadata=True, + overwrite=False, + dst_parent_dir=".", + save_bboxes=False ) # Assert @@ -1590,7 +1691,14 @@ def test_DicomImageRedactorEngine_redact_multiple_dicom_images_happy_path( # Act mock_engine._redact_multiple_dicom_images( - dcm_path, crop_ratio, "contrast", 25, overwrite, output_dir, False + dcm_dir=dcm_path, + crop_ratio=crop_ratio, + fill="contrast", + padding_width=25, + use_metadata=True, + overwrite=overwrite, + dst_parent_dir=output_dir, + save_bboxes=False ) # Assert @@ -1624,7 +1732,14 @@ def test_DicomImageRedactorEngine_redact_multiple_dicom_images_exceptions( with pytest.raises(Exception) as exc_info: # Act mock_engine._redact_multiple_dicom_images( - dcm_path, 0.75, "contrast", 25, False, ".", False + dcm_dir=dcm_path, + crop_ratio=0.75, + fill="contrast", + padding_width=25, + use_metadata=True, + overwrite=False, + dst_parent_dir=".", + save_bboxes=False ) # Assert @@ -1679,7 +1794,7 @@ def test_DicomImageRedactorEngine_redact_from_file_happy_path( ) # Act - mock_engine.redact_from_file(dcm_path, "output", 25, "contrast") + mock_engine.redact_from_file(dcm_path, "output", padding_width=25, fill="contrast", use_metadata=True) # Assert assert mock_copy_files.call_count == 1 @@ -1721,7 +1836,7 @@ def test_DicomImageRedactorEngine_redact_from_file_exceptions( """ with pytest.raises(Exception) as exc_info: # Act - mock_engine.redact_from_file(input_path, output_path, 25, "contrast") + mock_engine.redact_from_file(input_path, output_path, padding_width=25, fill="contrast", use_metadata=True) # Assert assert expected_error_type == exc_info.typename @@ -1763,7 +1878,7 @@ def test_DicomImageRedactorEngine_redact_from_directory_happy_path( ) # Act - mock_engine.redact_from_directory(dcm_path, "output", 25, "contrast") + mock_engine.redact_from_directory(dcm_path, "output", padding_width=25, fill="contrast", use_metadata=True) # Assert assert mock_copy_files.call_count == 1 @@ -1794,7 +1909,7 @@ def test_DicomImageRedactorEngine_redact_from_directory_exceptions( """ with pytest.raises(Exception) as exc_info: # Act - mock_engine.redact_from_directory(input_path, output_path, 25, "contrast") + mock_engine.redact_from_directory(input_path, output_path, padding_width=25, fill="contrast", use_metadata=True) # Assert assert expected_error_type == exc_info.typename