From 11b54a1ea5208e39a3856af5c1528f1a94b137a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Simonis?= Date: Mon, 11 May 2026 15:48:10 +0200 Subject: [PATCH] Cleanup the import logic and improve errors --- micro_manager/micro_simulation.py | 69 +++++++++++++++++-------------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/micro_manager/micro_simulation.py b/micro_manager/micro_simulation.py index c784e39d..b34c58a6 100644 --- a/micro_manager/micro_simulation.py +++ b/micro_manager/micro_simulation.py @@ -600,39 +600,46 @@ def load_backend_class(path_to_micro_file: str) -> type: A class inheriting from MicroSimulationInterface. """ - def try_load(name): - try: - return getattr(ipl.import_module(path_to_micro_file, name), name) - except ImportError as ie: - return None - except AttributeError as ae: - return None - - def check_cls(cls): - try: - inherits = issubclass(cls, MicroSimulationInterface) - except TypeError: - # pybind11 extension types may not support issubclass — wrap them - inherits = False - - if not inherits: - cls = _wrap_non_interface_class(cls, path_to_micro_file) - return cls + # try to load the module + try: + mod = ipl.import_module(path_to_micro_file) + except ModuleNotFoundError as ie: + if ie.name == path_to_micro_file: + raise RuntimeError( + f"Couldn't load python module '{path_to_micro_file}' containing the micro simulation" + ) + else: + raise RuntimeError( + f"Counldn't load dependency of python module '{path_to_micro_file}' containing the micro simulation: {ie}" + ) + except Exception as e: + raise RuntimeError( + f"Error loading python module '{path_to_micro_file}' containing the micro simulation: {e}" + ) + # try to load the class CLS_NAME = "MicroSimulation" - # attempt to load with base name - result = try_load(CLS_NAME) - if result is not None: - return check_cls(result) - - # attempt to load with appended indices - for i in range(10): - result = try_load(f"{CLS_NAME}{i}") - if result is not None: - return check_cls(result) - - # failed to load any class - raise RuntimeError(f"Could not load micro simulation from {path_to_micro_file}") + suffixes = [""] + [str(i) for i in range(10)] + micro_cls = None + for suffix in suffixes: + if cls := getattr(mod, f"{CLS_NAME}{suffix}", None): + micro_cls = cls + if micro_cls is None: + raise RuntimeError( + f"Loaded module '{path_to_micro_file}' does not contain a MicroSimulation class" + ) + + # check loaded class + try: + inherits = issubclass(micro_cls, MicroSimulationInterface) + except TypeError: + # pybind11 extension types may not support issubclass — wrap them + inherits = False + + if inherits: + return micro_cls + else: + return _wrap_non_interface_class(micro_cls, path_to_micro_file) def create_simulation_class(