Source code for qudi.tools.config_editor.module_finder
# -*- coding: utf-8 -*-
"""
"""
__all__ = ['ModuleFinder', 'QudiModules']
import importlib
import inspect
import logging
from typing import List, Type, Dict, Iterable
from qudi.core import Connector, ConfigOption, Base, LogicBase, GuiBase
from qudi.util.helpers import iter_modules_recursive
log = logging.getLogger(__package__)
[docs]
class ModuleFinder:
"""
"""
@staticmethod
def is_qudi_module(obj: type) -> bool:
if obj in [Base, LogicBase, GuiBase]:
return False
return inspect.isclass(obj) and issubclass(obj, Base) and not inspect.isabstract(obj)
@staticmethod
def get_module_names_from_ns(namespace: object) -> List[str]:
module_names = [mod_finder.name for mod_finder in
iter_modules_recursive(namespace.__path__, f'{namespace.__name__}.')]
# Remove duplicates
return list(dict.fromkeys(module_names))
@classmethod
def get_qudi_classes_in_module(cls, module: object) -> Dict[str, Type[Base]]:
members = inspect.getmembers(module, cls.is_qudi_module)
return {f'{module.__name__}.{name}': obj for name, obj in members if
obj.__module__ == module.__name__}
@classmethod
def get_qudi_modules_from_ns(cls, namespace: object) -> Dict[str, Type[Base]]:
qudi_modules = dict()
for module_name in cls.get_module_names_from_ns(namespace):
try:
module = importlib.import_module(module_name)
except:
log.warning(f'Error during import of module "{module_name}"')
continue
qudi_modules.update(cls.get_qudi_classes_in_module(module))
return qudi_modules
@classmethod
def get_qudi_modules(cls) -> Dict[str, Dict[str, Type[Base]]]:
try:
import qudi.gui as _gui_ns
except ImportError:
_gui_ns = None
try:
import qudi.logic as _logic_ns
except ImportError:
_logic_ns = None
try:
import qudi.hardware as _hardware_ns
except ImportError:
_hardware_ns = None
modules = dict()
if _gui_ns is not None:
modules.update(cls.get_qudi_modules_from_ns(_gui_ns))
if _logic_ns is not None:
modules.update(cls.get_qudi_modules_from_ns(_logic_ns))
if _hardware_ns is not None:
modules.update(cls.get_qudi_modules_from_ns(_hardware_ns))
return modules
[docs]
class QudiModules:
"""
"""
[docs]
def __init__(self):
# import all qudi module classes if possible (log all errors upon import)
self._qudi_modules = {mod[5:] if mod.startswith('qudi.') else mod: cls for mod, cls in
ModuleFinder.get_qudi_modules().items()}
# Collect all connectors for all modules
self._module_connectors = {
mod: list(cls._meta['connectors'].values()) for mod, cls in self._qudi_modules.items()
}
# Get for each connector in each module compatible modules to connect to
self._module_connectors_compatible_modules = {
mod: self._modules_for_connectors(conn) for mod, conn in self._module_connectors.items()
}
# Get all ConfigOptions for all modules
self._module_config_options = {
mod: list(cls._meta['config_options'].values()) for mod, cls in
self._qudi_modules.items()
}
def _modules_for_connectors(self, connectors: Iterable[Connector]) -> Dict[str, List[str]]:
return {conn.name: self._modules_for_connector(conn) for conn in connectors}
def _modules_for_connector(self, connector: Connector) -> List[str]:
interface = connector.interface
bases = {mod: {c.__name__ for c in cls.mro()} for mod, cls in self._qudi_modules.items()}
return list(mod for mod, base_names in bases.items() if interface in base_names)
@property
def available_modules(self) -> List[str]:
return list(self._qudi_modules)
def module_connectors(self, module: str) -> List[Connector]:
return self._module_connectors[module].copy()
def module_connector_targets(self, module: str) -> Dict[str, List[str]]:
return {k: v.copy() for k, v in self._module_connectors_compatible_modules[module].items()}
def module_config_options(self, module: str) -> List[ConfigOption]:
return self._module_config_options[module].copy()