Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions monai/data/image_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,16 +107,32 @@ def resolve_writer(ext_name, error_if_not_found=True) -> Sequence:
fmt = fmt[1:]
avail_writers = []
default_writers = SUPPORTED_WRITERS.get(EXT_WILDCARD, ())
import re
errors = []
for _writer in look_up_option(fmt, SUPPORTED_WRITERS, default=default_writers):
try:
_writer() # this triggers `monai.utils.module.require_pkg` to check the system availability
avail_writers.append(_writer)
except OptionalImportError:
except OptionalImportError as e:
errors.append(str(e))
continue
except Exception: # other writer init errors indicating it exists
avail_writers.append(_writer)
if not avail_writers and error_if_not_found:
raise OptionalImportError(f"No ImageWriter backend found for {fmt}.")
required_pkgs = []
for err in errors:
match = re.search(r"required package `([^`]+)`", err)
if match:
pkg = match.group(1)
pkg = "pillow" if pkg == "PIL" else pkg
pkg = "pynrrd" if pkg == "nrrd" else pkg
if pkg not in required_pkgs:
required_pkgs.append(pkg)

msg = f"No ImageWriter backend found for {fmt}."
if required_pkgs:
msg += f" Please install: {' or '.join(required_pkgs)}."
raise OptionalImportError(msg)
writer_tuple = ensure_tuple(avail_writers)
SUPPORTED_WRITERS[fmt] = writer_tuple
return writer_tuple
Expand Down
13 changes: 9 additions & 4 deletions monai/transforms/io/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,13 +209,18 @@ 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())
try:
self.register(the_reader())
except OptionalImportError as e:
raise OptionalImportError(
f"required package for reader {_r} is not installed, or the version doesn't match requirement."
) from e
elif inspect.isclass(_r):
self.register(_r(*args, **kwargs))
else:
Expand Down
14 changes: 12 additions & 2 deletions tests/data/test_image_rw.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,18 @@ def test_rgb(self, reader, writer):
class TestRegRes(unittest.TestCase):
def test_0_default(self):
self.assertTrue(len(resolve_writer(".png")) > 0, "has png writer")
self.assertTrue(len(resolve_writer(".nrrd")) > 0, "has nrrd writer")
self.assertTrue(len(resolve_writer("unknown")) > 0, "has writer")
_, has_nibabel = optional_import("nibabel")
_, has_itk = optional_import("itk", allow_namespace_pkg=True)
if has_nibabel or has_itk:
self.assertTrue(len(resolve_writer(".nrrd")) > 0, "has nrrd writer")
self.assertTrue(len(resolve_writer("unknown")) > 0, "has writer")
else:
with self.assertRaises(OptionalImportError) as ctx:
resolve_writer(".nrrd")
self.assertIn("Please install: itk or nibabel.", str(ctx.exception))
with self.assertRaises(OptionalImportError) as ctx:
resolve_writer("unknown")
self.assertIn("Please install: itk or nibabel.", str(ctx.exception))
register_writer("unknown1", lambda: (_ for _ in ()).throw(OptionalImportError))
with self.assertRaises(OptionalImportError):
resolve_writer("unknown1")
Expand Down
23 changes: 21 additions & 2 deletions tests/data/test_init_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,28 @@ def test_load_image(self):
self.assertIsInstance(instance1, LoadImage)
self.assertIsInstance(instance2, LoadImage)

from monai.utils import optional_import, OptionalImportError
pkg_map = {
"NibabelReader": "nibabel",
"PILReader": "PIL",
"ITKReader": "itk",
"NrrdReader": "nrrd",
"NumpyReader": "numpy",
"PydicomReader": "pydicom",
}
for r in ["NibabelReader", "PILReader", "ITKReader", "NumpyReader", "NrrdReader", "PydicomReader", None]:
inst = LoadImaged("image", reader=r)
self.assertIsInstance(inst, LoadImaged)
if r is None:
inst = LoadImaged("image", reader=r)
self.assertIsInstance(inst, LoadImaged)
continue

_, has_pkg = optional_import(pkg_map[r])
if has_pkg:
inst = LoadImaged("image", reader=r)
self.assertIsInstance(inst, LoadImaged)
else:
with self.assertRaises(OptionalImportError):
LoadImaged("image", reader=r)

@SkipIfNoModule("nibabel")
@SkipIfNoModule("cupy")
Expand Down
Loading