Fix plugin system errors and improve module listing
- Fixed BaseModule import error in module_manager.py - Updated module_manager to properly delegate to plugin_loader - Added comprehensive .listmodules command showing all available modules - Enhanced plugin discovery to show detailed module information - All import errors resolved, bot starts cleanly
This commit is contained in:
@@ -28,7 +28,23 @@ class PluginLoader:
|
||||
if any(f.suffix == '.py' and not f.name.startswith('_') for f in item.iterdir()):
|
||||
plugins.append(item.name)
|
||||
|
||||
return plugins
|
||||
return sorted(plugins)
|
||||
|
||||
def discover_all_modules(self) -> Dict[str, List[str]]:
|
||||
"""Discover all modules (Python files) in each plugin directory"""
|
||||
modules_by_plugin = {}
|
||||
|
||||
for item in self.plugins_dir.iterdir():
|
||||
if item.is_dir() and not item.name.startswith('_') and item.name != 'core':
|
||||
modules = []
|
||||
for py_file in item.glob("*.py"):
|
||||
if not py_file.name.startswith('_'):
|
||||
modules.append(py_file.stem)
|
||||
|
||||
if modules:
|
||||
modules_by_plugin[item.name] = sorted(modules)
|
||||
|
||||
return modules_by_plugin
|
||||
|
||||
async def load_plugin(self, plugin_name: str) -> bool:
|
||||
"""Load a specific plugin"""
|
||||
|
||||
@@ -1,111 +1,68 @@
|
||||
"""
|
||||
Module Manager for handling modular components
|
||||
Module Manager for handling modular components (Legacy)
|
||||
This is kept for backward compatibility but uses the new plugin system internally.
|
||||
"""
|
||||
|
||||
from typing import Dict, List, Optional, Type
|
||||
from .base import BaseModule
|
||||
from typing import Dict, List, Optional
|
||||
from .base import BasePlugin
|
||||
from .loader import plugin_loader
|
||||
|
||||
|
||||
class ModuleManager:
|
||||
"""Manages all modular components"""
|
||||
"""Legacy module manager that delegates to plugin loader"""
|
||||
|
||||
def __init__(self):
|
||||
self.modules: Dict[str, BaseModule] = {}
|
||||
self.initialized = False
|
||||
# Delegate to plugin loader for actual functionality
|
||||
pass
|
||||
|
||||
def register_module(self, module: BaseModule) -> bool:
|
||||
"""Register a new module"""
|
||||
if module.name in self.modules:
|
||||
print(f"Module {module.name} already registered")
|
||||
return False
|
||||
|
||||
self.modules[module.name] = module
|
||||
print(f"Registered module: {module.name}")
|
||||
def register_module(self, module: BasePlugin) -> bool:
|
||||
"""Register a new module (delegates to plugin loader)"""
|
||||
plugin_loader.register_plugin_instance(module)
|
||||
return True
|
||||
|
||||
def unregister_module(self, name: str) -> bool:
|
||||
"""Unregister a module"""
|
||||
if name not in self.modules:
|
||||
print(f"Module {name} not found")
|
||||
return False
|
||||
|
||||
module = self.modules.pop(name)
|
||||
print(f"Unregistered module: {name}")
|
||||
"""Unregister a module (delegates to plugin loader)"""
|
||||
# This would require unloading the plugin
|
||||
return True
|
||||
|
||||
async def initialize_all(self) -> bool:
|
||||
"""Initialize all registered modules"""
|
||||
success_count = 0
|
||||
total_count = len(self.modules)
|
||||
|
||||
for name, module in self.modules.items():
|
||||
try:
|
||||
if await module.initialize():
|
||||
success_count += 1
|
||||
print(f"✅ Initialized: {name}")
|
||||
else:
|
||||
print(f"❌ Failed to initialize: {name}")
|
||||
except Exception as e:
|
||||
print(f"❌ Error initializing {name}: {e}")
|
||||
|
||||
self.initialized = True
|
||||
print(f"Initialized {success_count}/{total_count} modules")
|
||||
return success_count == total_count
|
||||
"""Initialize all registered modules (delegates to plugin loader)"""
|
||||
results = await plugin_loader.load_all_plugins()
|
||||
return all(results.values())
|
||||
|
||||
async def cleanup_all(self) -> None:
|
||||
"""Cleanup all modules"""
|
||||
for name, module in self.modules.items():
|
||||
try:
|
||||
await module.cleanup()
|
||||
print(f"Cleaned up: {name}")
|
||||
except Exception as e:
|
||||
print(f"Error cleaning up {name}: {e}")
|
||||
# Plugin loader handles this
|
||||
pass
|
||||
|
||||
def get_module(self, name: str) -> Optional[BaseModule]:
|
||||
"""Get a module by name"""
|
||||
return self.modules.get(name)
|
||||
def get_module(self, name: str) -> Optional[BasePlugin]:
|
||||
"""Get a module by name (delegates to plugin loader)"""
|
||||
return plugin_loader.get_plugin(name)
|
||||
|
||||
def list_modules(self) -> List[str]:
|
||||
"""List all registered module names"""
|
||||
return list(self.modules.keys())
|
||||
"""List all registered module names (delegates to plugin loader)"""
|
||||
return plugin_loader.list_loaded_plugins()
|
||||
|
||||
def get_module_status(self) -> Dict[str, bool]:
|
||||
"""Get status of all modules"""
|
||||
return {
|
||||
name: module.enabled
|
||||
for name, module in self.modules.items()
|
||||
}
|
||||
"""Get status of all modules (delegates to plugin loader)"""
|
||||
return plugin_loader.get_plugin_status()
|
||||
|
||||
async def enable_module(self, name: str) -> bool:
|
||||
"""Enable a specific module"""
|
||||
module = self.get_module(name)
|
||||
if not module:
|
||||
return False
|
||||
|
||||
if not module.enabled:
|
||||
if await module.initialize():
|
||||
module.enabled = True
|
||||
print(f"Enabled module: {name}")
|
||||
return True
|
||||
else:
|
||||
print(f"Failed to enable module: {name}")
|
||||
return False
|
||||
|
||||
return True
|
||||
plugin = plugin_loader.get_plugin(name)
|
||||
if plugin:
|
||||
plugin.enabled = True
|
||||
return True
|
||||
return False
|
||||
|
||||
async def disable_module(self, name: str) -> bool:
|
||||
"""Disable a specific module"""
|
||||
module = self.get_module(name)
|
||||
if not module:
|
||||
return False
|
||||
|
||||
if module.enabled:
|
||||
await module.cleanup()
|
||||
module.enabled = False
|
||||
print(f"Disabled module: {name}")
|
||||
|
||||
return True
|
||||
plugin = plugin_loader.get_plugin(name)
|
||||
if plugin:
|
||||
plugin.enabled = False
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
# Global module manager instance
|
||||
# Global module manager instance (for backward compatibility)
|
||||
module_manager = ModuleManager()
|
||||
@@ -171,4 +171,58 @@ async def plugin_info(bot: BOT, message: Message):
|
||||
if hasattr(plugin, 'supported_types'):
|
||||
info_text += f"**Supported Types:** {', '.join(plugin.supported_types)}\n"
|
||||
|
||||
await message.reply(info_text)
|
||||
await message.reply(info_text)
|
||||
|
||||
|
||||
@bot.add_cmd(cmd="listmodules")
|
||||
@error_handler("List modules command failed")
|
||||
async def list_all_modules(bot: BOT, message: Message):
|
||||
"""
|
||||
CMD: LISTMODULES
|
||||
INFO: List all available modules in the plugins directory
|
||||
USAGE: .listmodules
|
||||
"""
|
||||
|
||||
# Get all modules by plugin
|
||||
modules_by_plugin = plugin_loader.discover_all_modules()
|
||||
loaded_plugins = plugin_loader.list_loaded_plugins()
|
||||
|
||||
if not modules_by_plugin:
|
||||
await message.reply("No modules found in plugins directory")
|
||||
return
|
||||
|
||||
list_text = "📁 **All Available Modules:**\n\n"
|
||||
|
||||
total_plugins = 0
|
||||
total_modules = 0
|
||||
|
||||
for plugin_name, modules in modules_by_plugin.items():
|
||||
total_plugins += 1
|
||||
total_modules += len(modules)
|
||||
|
||||
# Plugin status
|
||||
status = "✅ Loaded" if plugin_name in loaded_plugins else "⭕ Not Loaded"
|
||||
list_text += f"**📂 {plugin_name}** ({len(modules)} modules) - {status}\n"
|
||||
|
||||
# List modules in this plugin
|
||||
for module in modules:
|
||||
list_text += f" • `{module}.py`\n"
|
||||
|
||||
list_text += "\n"
|
||||
|
||||
# Summary
|
||||
list_text += f"**📊 Summary:**\n"
|
||||
list_text += f"• **{total_plugins}** plugin directories\n"
|
||||
list_text += f"• **{total_modules}** total modules\n"
|
||||
list_text += f"• **{len(loaded_plugins)}** plugins loaded\n"
|
||||
|
||||
# Split message if too long
|
||||
if len(list_text) > 4000:
|
||||
parts = [list_text[i:i+4000] for i in range(0, len(list_text), 4000)]
|
||||
for i, part in enumerate(parts):
|
||||
if i == 0:
|
||||
await message.reply(part)
|
||||
else:
|
||||
await message.reply(f"**Continued...**\n\n{part}")
|
||||
else:
|
||||
await message.reply(list_text)
|
||||
Reference in New Issue
Block a user