Skip to content

Commit 1e6dd49

Browse files
committed
Raise exception when user-specified reader package is not installed
When a user explicitly specifies a reader (e.g., reader="ITKReader") but the required package is not installed, LoadImage now raises an OptionalImportError instead of silently falling back to another reader with only a warning. This makes the behavior explicit: if the user specifically requested a reader, they should be informed immediately that it cannot be used, rather than having the system silently use a different reader which may produce unexpected results. Default behavior (reader=None) remains unchanged — missing optional packages are still handled gracefully with debug logging. Fixes #7437 Signed-off-by: haoyu-haoyu <haoyu-haoyu@users.noreply.github.com> Signed-off-by: SexyERIC0723 <haoyuwang144@gmail.com>
1 parent daaedaa commit 1e6dd49

File tree

3 files changed

+53
-6
lines changed

3 files changed

+53
-6
lines changed

monai/transforms/io/array.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,11 @@ def __init__(
209209
the_reader = look_up_option(_r.lower(), SUPPORTED_READERS)
210210
try:
211211
self.register(the_reader(*args, **kwargs))
212-
except OptionalImportError:
213-
warnings.warn(
214-
f"required package for reader {_r} is not installed, or the version doesn't match requirement."
215-
)
212+
except OptionalImportError as e:
213+
raise OptionalImportError(
214+
f"Required package for reader {_r} is not installed, or the version doesn't match requirement. "
215+
f"Please install the required package to use {_r}."
216+
) from e
216217
except TypeError: # the reader doesn't have the corresponding args/kwargs
217218
warnings.warn(f"{_r} is not supported with the given parameters {args} {kwargs}.")
218219
self.register(the_reader())

tests/data/test_init_reader.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
from monai.data import ITKReader, NibabelReader, NrrdReader, NumpyReader, PILReader, PydicomReader
1717
from monai.transforms import LoadImage, LoadImaged
18+
from monai.utils import OptionalImportError
1819
from tests.test_utils import SkipIfNoModule
1920

2021

@@ -26,8 +27,13 @@ def test_load_image(self):
2627
self.assertIsInstance(instance2, LoadImage)
2728

2829
for r in ["NibabelReader", "PILReader", "ITKReader", "NumpyReader", "NrrdReader", "PydicomReader", None]:
29-
inst = LoadImaged("image", reader=r)
30-
self.assertIsInstance(inst, LoadImaged)
30+
try:
31+
inst = LoadImaged("image", reader=r)
32+
self.assertIsInstance(inst, LoadImaged)
33+
except OptionalImportError:
34+
# Reader's backend package is not installed — expected in
35+
# minimal-dependency environments after the fix for #7437.
36+
pass
3137

3238
@SkipIfNoModule("nibabel")
3339
@SkipIfNoModule("cupy")

tests/transforms/test_load_image.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,5 +498,45 @@ def test_correct(self, input_param, expected_shape, track_meta):
498498
self.assertFalse(hasattr(r, "affine"))
499499

500500

501+
class TestLoadImageReaderNotInstalled(unittest.TestCase):
502+
"""Test that specifying a reader whose required package is not installed raises an error.
503+
504+
Addresses https://github.com/Project-MONAI/MONAI/issues/7437
505+
"""
506+
507+
@unittest.skipIf(has_itk, "test requires itk to NOT be installed")
508+
def test_specified_reader_not_installed_raises(self):
509+
"""When a user explicitly specifies a reader that is not installed, LoadImage should raise
510+
an OptionalImportError instead of silently falling back to another reader."""
511+
from monai.utils import OptionalImportError
512+
513+
with self.assertRaises(OptionalImportError):
514+
LoadImage(reader="ITKReader")
515+
516+
def test_specified_reader_not_installed_raises_mocked(self):
517+
"""Mock test to verify OptionalImportError is raised (not just warned) when a user-specified
518+
reader's required package is not installed."""
519+
from unittest.mock import patch
520+
521+
from monai.utils import OptionalImportError
522+
523+
_original = __import__("monai.transforms.io.array", fromlist=["optional_import"]).optional_import
524+
525+
def _mock_optional_import(module, name="", *args, **kwargs):
526+
if name == "MockMissingReader":
527+
# Return a class that raises OptionalImportError on instantiation,
528+
# simulating a reader whose backend package is not installed
529+
class _Unavailable:
530+
def __init__(self, *a, **kw):
531+
raise OptionalImportError("mock package is not installed")
532+
533+
return _Unavailable, True
534+
return _original(module, *args, name=name, **kwargs)
535+
536+
with patch("monai.transforms.io.array.optional_import", side_effect=_mock_optional_import):
537+
with self.assertRaises(OptionalImportError):
538+
LoadImage(reader="MockMissingReader")
539+
540+
501541
if __name__ == "__main__":
502542
unittest.main()

0 commit comments

Comments
 (0)