EngineModuleLoader
What it is
EngineModuleLoader discovers module dependencies, computes a safe load order, and imports/instantiates enabled ABI modules (implementations of BaseModule) using an EngineProxy.
Public API
class EngineModuleLoader(configuration: EngineConfiguration)- Loads and initializes configured modules for a given engine.
Properties
modules -> Dict[str, BaseModule]- Loaded module instances keyed by module name.
module_load_order -> List[str]- Module names in computed load order (topological order).
ordered_modules -> List[BaseModule]- Loaded module instances in load order.
Methods
-
get_module_dependencies(module_name: str, scanned_modules: List[str] = []) -> Dict[str, ModuleDependencies]- Imports a single module, calls
ABIModule.get_dependencies(), and recursively resolves its module dependencies. - Detects circular dependencies during recursion using
scanned_modules. - Supports soft dependencies by allowing
module_nameto end with#soft(missing soft modules return{}).
- Imports a single module, calls
-
get_modules_dependencies(module_names: List[str] = []) -> Dict[str, ModuleDependencies]- Builds the dependency map for all enabled modules in
EngineConfiguration.modules. - If
module_namesis provided, only includes those modules; raises if a requested module is not enabled.
- Builds the dependency map for all enabled modules in
-
load_modules(engine: IEngine, module_names: List[str] = []) -> Dict[str, BaseModule]- Resolves dependencies (if not already resolved), computes load order, imports modules, validates their configuration models, instantiates them, and calls
on_load(). - Creates an
EngineProxyper module; the proxy is created withunlocked=Trueonly whenmodule_name == "naas_abi".
- Resolves dependencies (if not already resolved), computes load order, imports modules, validates their configuration models, instantiates them, and calls
Configuration/Dependencies
-
Requires an
EngineConfigurationcontaining:global_config(passed into each module’s configuration model asglobal_config=...)modules: list of module configs with at least:module(import path string used byimportlib.import_module)enabled(bool)config(dict passed to the module configuration model)
-
Each importable module must expose:
ABIModuleclassABIModule.get_dependencies() -> ModuleDependenciesABIModule.Configurationwhich must be a subclass ofModuleConfigurationABIModule(...)must produce an instance ofBaseModuleand supporton_load()
-
Uses:
importlibfor dynamic importspydantic_corefor catching configuration validation errorsEngineProxy,IEngine,BaseModule,ModuleDependencies,ModuleConfiguration
Usage
from naas_abi_core.engine.engine_loaders.EngineModuleLoader import EngineModuleLoader
# Provided by your application/runtime
from naas_abi_core.engine.engine_configuration.EngineConfiguration import EngineConfiguration
from naas_abi_core.engine.IEngine import IEngine
engine: IEngine = ... # your engine implementation
config: EngineConfiguration = ... # populated EngineConfiguration
loader = EngineModuleLoader(config)
modules = loader.load_modules(engine) # loads all enabled modules
print(loader.module_load_order)
print(list(modules.keys()))
To load a subset (must be enabled in configuration):
modules = loader.load_modules(engine, module_names=["my_module_path"])
Caveats
- Dependency load order is computed via topological sort; circular dependencies raise
ValueError. - Missing required dependencies (non-
#soft) raiseValueErrorduring sorting. module_dependencies_recursive()is explicitly not protected against circular dependencies and should only be used after a safe load order is established.get_module_dependencies()has a default argumentscanned_modules=[](mutable default); the method uses it read-only per call chain, but it is still a shared default object.