From b1ce7809cc451f308f6e3337b3e16abd8a8efb4d Mon Sep 17 00:00:00 2001 From: Kamayani Rai Date: Sun, 12 Apr 2026 12:56:49 -0700 Subject: [PATCH 1/3] fix(LoadImage): raise OptionalImportError when user-specified reader package is not installed Previously, if a user explicitly passed a reader name (e.g. reader="ITKReader") and the required package was not installed, LoadImage would only emit a warning and silently continue with fallback readers. This masked real configuration errors. Now an OptionalImportError is raised immediately, making the failure explicit. The auto-select path (reader=None) is unchanged and still skips missing readers silently. Fixes #7437 Signed-off-by: Kamayani Rai --- monai/transforms/io/array.py | 6 +++--- tests/transforms/test_load_image.py | 13 +++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/monai/transforms/io/array.py b/monai/transforms/io/array.py index f0c1d1949d..b30a29c3c1 100644 --- a/monai/transforms/io/array.py +++ b/monai/transforms/io/array.py @@ -210,10 +210,10 @@ def __init__( the_reader = look_up_option(_r.lower(), SUPPORTED_READERS) try: self.register(the_reader(*args, **kwargs)) - except OptionalImportError: - warnings.warn( + except OptionalImportError as e: + raise OptionalImportError( f"required package for reader {_r} is not installed, or the version doesn't match requirement." - ) + ) from e except TypeError: # the reader doesn't have the corresponding args/kwargs warnings.warn(f"{_r} is not supported with the given parameters {args} {kwargs}.") self.register(the_reader()) diff --git a/tests/transforms/test_load_image.py b/tests/transforms/test_load_image.py index 031e38272e..54677d914a 100644 --- a/tests/transforms/test_load_image.py +++ b/tests/transforms/test_load_image.py @@ -498,5 +498,18 @@ def test_correct(self, input_param, expected_shape, track_meta): self.assertFalse(hasattr(r, "affine")) +class TestLoadImageReaderNotInstalled(unittest.TestCase): + def test_raises_when_user_specified_reader_not_installed(self): + """LoadImage must raise OptionalImportError when a user-specified reader's package is missing.""" + from unittest.mock import patch + + from monai.utils import OptionalImportError + + # Patch ITKReader.__init__ to simulate the package not being installed + with patch("monai.data.image_reader.ITKReader.__init__", side_effect=OptionalImportError("itk not installed")): + with self.assertRaises(OptionalImportError): + LoadImage(reader="ITKReader") + + if __name__ == "__main__": unittest.main() From 3194a78c7ede6b34e18d34ad724a3ca3f97f7203 Mon Sep 17 00:00:00 2001 From: Kamayani Rai Date: Sun, 12 Apr 2026 13:17:18 -0700 Subject: [PATCH 2/3] fix: update tests to handle OptionalImportError from user-specified readers - tests/data/test_init_reader.py: wrap LoadImaged init in try/except OptionalImportError since packages may not be installed in min-dep envs - tests/transforms/test_load_image.py: tighten assertion using assertRaisesRegex, add Google-style class and method docstrings Signed-off-by: Kamayani Rai --- tests/data/test_init_reader.py | 8 ++++++-- tests/transforms/test_load_image.py | 10 ++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/tests/data/test_init_reader.py b/tests/data/test_init_reader.py index 4170412207..fe4416129f 100644 --- a/tests/data/test_init_reader.py +++ b/tests/data/test_init_reader.py @@ -15,6 +15,7 @@ from monai.data import ITKReader, NibabelReader, NrrdReader, NumpyReader, PILReader, PydicomReader from monai.transforms import LoadImage, LoadImaged +from monai.utils import OptionalImportError from tests.test_utils import SkipIfNoModule @@ -26,8 +27,11 @@ def test_load_image(self): self.assertIsInstance(instance2, LoadImage) for r in ["NibabelReader", "PILReader", "ITKReader", "NumpyReader", "NrrdReader", "PydicomReader", None]: - inst = LoadImaged("image", reader=r) - self.assertIsInstance(inst, LoadImaged) + try: + inst = LoadImaged("image", reader=r) + self.assertIsInstance(inst, LoadImaged) + except OptionalImportError: + pass # expected when the reader's package is not installed @SkipIfNoModule("nibabel") @SkipIfNoModule("cupy") diff --git a/tests/transforms/test_load_image.py b/tests/transforms/test_load_image.py index 54677d914a..8b0b137c43 100644 --- a/tests/transforms/test_load_image.py +++ b/tests/transforms/test_load_image.py @@ -499,15 +499,21 @@ def test_correct(self, input_param, expected_shape, track_meta): class TestLoadImageReaderNotInstalled(unittest.TestCase): + """Tests that LoadImage raises when a user-specified reader's package is not installed.""" + def test_raises_when_user_specified_reader_not_installed(self): - """LoadImage must raise OptionalImportError when a user-specified reader's package is missing.""" + """Test LoadImage raises OptionalImportError for a missing user-specified reader. + + Raises: + OptionalImportError: when the package required by the specified reader is not installed. + """ from unittest.mock import patch from monai.utils import OptionalImportError # Patch ITKReader.__init__ to simulate the package not being installed with patch("monai.data.image_reader.ITKReader.__init__", side_effect=OptionalImportError("itk not installed")): - with self.assertRaises(OptionalImportError): + with self.assertRaisesRegex(OptionalImportError, "itk not installed|required package for reader ITKReader"): LoadImage(reader="ITKReader") From 78d9a93be2a8b132acdb1e0c171485734f4b56fb Mon Sep 17 00:00:00 2001 From: Kamayani Rai Date: Sun, 12 Apr 2026 13:51:41 -0700 Subject: [PATCH 3/3] fix(test): tighten OptionalImportError handling in test_init_reader Use subTest per reader and explicitly fail if reader=None raises OptionalImportError, preventing silent swallowing of real logic bugs. Signed-off-by: Kamayani Rai --- tests/data/test_init_reader.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/data/test_init_reader.py b/tests/data/test_init_reader.py index fe4416129f..47421f72b0 100644 --- a/tests/data/test_init_reader.py +++ b/tests/data/test_init_reader.py @@ -27,11 +27,13 @@ def test_load_image(self): self.assertIsInstance(instance2, LoadImage) for r in ["NibabelReader", "PILReader", "ITKReader", "NumpyReader", "NrrdReader", "PydicomReader", None]: - try: - inst = LoadImaged("image", reader=r) - self.assertIsInstance(inst, LoadImaged) - except OptionalImportError: - pass # expected when the reader's package is not installed + with self.subTest(reader=r): + try: + inst = LoadImaged("image", reader=r) + self.assertIsInstance(inst, LoadImaged) + except OptionalImportError: + if r is None: + self.fail("LoadImaged(reader=None) should not raise OptionalImportError.") @SkipIfNoModule("nibabel") @SkipIfNoModule("cupy")