import importlib
import inspect
import pkgutil
from importlib.metadata import entry_points
from types import ModuleType
from koi_net.core import BaseNode
ENTRY_POINT_GROUP = "koi_net.node"
MODULE_PREFIX = "koi_net_"
MODULE_POSTFIX = "_node"
MODULE_CORE = ".core"
[docs]
class ModuleInterface:
def __init__(self):
self.module_names: set[str] = set()
# alias -> module name
self.alias_module_map: dict[str, str] = {}
self.module_map: dict[str, ModuleType] = {}
self.load_module_names()
[docs]
def resolve_ref(self, module_ref) -> str:
if module_ref in self.module_names:
module_name = module_ref
elif module_ref in self.alias_module_map:
module_name = self.alias_module_map[module_ref]
else:
raise ModuleNotFoundError(f"Couldn't resolve module reference '{module_ref}'")
return module_name
[docs]
def load_class(self, module_name: str, reload_module: bool = False):
if module_name not in self.module_map:
print(f"Loading module {module_name}...")
module = importlib.import_module(module_name + MODULE_CORE)
self.module_map[module_name] = module
elif reload_module:
print(f"Reloading module {module_name}...")
module = importlib.reload(self.module_map[module_name])
self.module_map[module_name] = module
else:
module = self.module_map[module_name]
for _, obj in inspect.getmembers(module):
if (
getattr(obj, "__module__", None) == module.__name__ and
inspect.isclass(obj) and
issubclass(obj, BaseNode)
):
return obj
[docs]
def load_module_names(self):
for ep in entry_points(group=ENTRY_POINT_GROUP):
self.module_names.add(ep.module)
self.alias_module_map[ep.name] = ep.module
for module in pkgutil.iter_modules():
if (module.name.startswith(MODULE_PREFIX) and module.name.endswith(MODULE_POSTFIX)):
self.module_names.add(module.name)
module_alias = module.name[len(MODULE_PREFIX):-len(MODULE_POSTFIX)]
self.alias_module_map.setdefault(module_alias, module.name)
module_interface = ModuleInterface()