Source code for genericroboticarm.robo_APIs.dynamic_loader
"""
Utility module for loading RobotInterface implementations.
"""
import importlib
import inspect
import logging
import pkgutil
from types import ModuleType
from .robo_interface import RoboInterface
[docs]
def collect_robo_implementations(package: str = __package__) -> set[type[RoboInterface]]:
"""
Recursively find all subclasses of RoboInterface in a package.
Args:
package: Dotted path of the package
Returns:
list of RoboInterface subclasses
"""
classes: set[type[RoboInterface]] = set()
pkg = importlib.import_module(package)
def walk_modules(module: ModuleType):
for _, mod_name, is_pkg in pkgutil.iter_modules(module.__path__):
full_name = f"{module.__name__}.{mod_name}"
try:
mod = importlib.import_module(full_name)
for _, obj in inspect.getmembers(mod, inspect.isclass):
if (
issubclass(obj, RoboInterface)
and obj is not RoboInterface
and not inspect.isabstract(obj)
):
classes.add(obj)
if is_pkg:
walk_modules(mod)
except ModuleNotFoundError as error:
logging.warning(f"Could not import {module.__name__} because of missing module: {error}")
walk_modules(pkg)
return classes
[docs]
def get_arm_impl(impl_str: str) -> RoboInterface | None:
"""Dynamically imports the specified robotic arm implementation class.
Args:
impl_str (str): The robotic arm implementation class to use, formatted as <module>:<class>
"""
try:
module_name, class_name = impl_str.split(":")
module = importlib.import_module(module_name)
implementation = getattr(module, class_name)
if not issubclass(implementation, RoboInterface):
logging.error(f"{implementation} is no subclass of RoboInterface")
logging.info(f"Successfully imported {class_name} from {module_name}")
return implementation
except (ValueError, ImportError, AttributeError) as e:
logging.error(f"Failed to import {impl_str}: {e}")
return None