""" 插件依赖注入模块 提供插件间依赖注入功能: - @inject 装饰器自动注入依赖 - 延迟注入(lazy injection)避免循环依赖 - 类型安全的依赖获取 使用示例: from utils.plugin_inject import inject, require_plugin class MyPlugin(PluginBase): # 方式1: 使用装饰器注入 @inject("AIChat") def get_aichat(self) -> "AIChat": pass # 自动注入,无需实现 # 方式2: 使用 require_plugin async def some_method(self): aichat = require_plugin("AIChat") await aichat.do_something() # 方式3: 使用基类的 get_plugin async def another_method(self): aichat = self.get_plugin("AIChat") if aichat: await aichat.do_something() """ from functools import wraps from typing import Any, Callable, Optional, Type, TypeVar, TYPE_CHECKING from loguru import logger if TYPE_CHECKING: from utils.plugin_base import PluginBase T = TypeVar('T') class PluginNotAvailableError(Exception): """插件不可用错误""" pass def _get_plugin_manager(): """延迟获取 PluginManager 避免循环导入""" from utils.plugin_manager import PluginManager return PluginManager() def require_plugin(plugin_name: str) -> "PluginBase": """ 获取必需的插件(不存在则抛出异常) Args: plugin_name: 插件类名 Returns: 插件实例 Raises: PluginNotAvailableError: 插件不存在或未启用 """ pm = _get_plugin_manager() plugin = pm.plugins.get(plugin_name) if plugin is None: raise PluginNotAvailableError(f"插件 {plugin_name} 不可用") return plugin def get_plugin(plugin_name: str) -> Optional["PluginBase"]: """ 获取插件(不存在返回 None) Args: plugin_name: 插件类名 Returns: 插件实例或 None """ pm = _get_plugin_manager() return pm.plugins.get(plugin_name) def inject(plugin_name: str) -> Callable: """ 插件注入装饰器 将方法转换为属性 getter,自动返回指定插件实例。 Args: plugin_name: 要注入的插件类名 Usage: class MyPlugin(PluginBase): @inject("AIChat") def aichat(self) -> "AIChat": pass # 无需实现 async def handle(self, bot, message): # 直接使用 await self.aichat.process(message) """ def decorator(method: Callable) -> property: @wraps(method) def getter(self) -> Optional["PluginBase"]: # 优先使用插件自身的 _plugin_manager if hasattr(self, '_plugin_manager') and self._plugin_manager: return self._plugin_manager.plugins.get(plugin_name) # 回退到全局 PluginManager return get_plugin(plugin_name) return property(getter) return decorator def inject_required(plugin_name: str) -> Callable: """ 必需插件注入装饰器 与 inject 类似,但如果插件不存在会抛出异常。 Args: plugin_name: 要注入的插件类名 Raises: PluginNotAvailableError: 插件不存在 """ def decorator(method: Callable) -> property: @wraps(method) def getter(self) -> "PluginBase": plugin = None if hasattr(self, '_plugin_manager') and self._plugin_manager: plugin = self._plugin_manager.plugins.get(plugin_name) else: plugin = get_plugin(plugin_name) if plugin is None: raise PluginNotAvailableError( f"插件 {self.__class__.__name__} 依赖的 {plugin_name} 不可用" ) return plugin return property(getter) return decorator class PluginProxy: """ 插件代理 延迟获取插件,避免初始化时的循环依赖问题。 Usage: class MyPlugin(PluginBase): def __init__(self): super().__init__() self._aichat = PluginProxy("AIChat") async def handle(self): # 首次访问时才获取插件 if self._aichat.available: await self._aichat.instance.process() """ def __init__(self, plugin_name: str): self._plugin_name = plugin_name self._cached_instance: Optional["PluginBase"] = None self._checked = False @property def instance(self) -> Optional["PluginBase"]: """获取插件实例(带缓存)""" if not self._checked: self._cached_instance = get_plugin(self._plugin_name) self._checked = True return self._cached_instance @property def available(self) -> bool: """检查插件是否可用""" return self.instance is not None def require(self) -> "PluginBase": """获取插件,不存在则抛出异常""" inst = self.instance if inst is None: raise PluginNotAvailableError(f"插件 {self._plugin_name} 不可用") return inst def invalidate(self): """清除缓存,下次访问重新获取""" self._cached_instance = None self._checked = False def __repr__(self) -> str: status = "available" if self.available else "unavailable" return f"" # ==================== 导出 ==================== __all__ = [ 'PluginNotAvailableError', 'require_plugin', 'get_plugin', 'inject', 'inject_required', 'PluginProxy', ]