Merge pull request #2047 from InfinityPacer/main

fix 热加载不同平台路径及插件实例化
This commit is contained in:
jxxghp 2024-05-10 19:57:48 +08:00 committed by GitHub
commit 3d5761157a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 47 additions and 7 deletions

View File

@ -1,7 +1,9 @@
import concurrent
import concurrent.futures
import os
import time
import traceback
from pathlib import Path
from typing import List, Any, Dict, Tuple, Optional
from watchdog.events import FileSystemEventHandler
@ -39,8 +41,9 @@ class PluginMonitorHandler(FileSystemEventHandler):
self.__last_modified = current_time
# 读取插件根目录下的__init__.py文件读取class XXXX(_PluginBase)的类名
try:
plugin_dir = event.src_path.split("plugins/")[1].split("/")[0]
init_file = settings.ROOT_PATH / "app" / "plugins" / plugin_dir / "__init__.py"
# 使用os.path和pathlib处理跨平台的路径问题
plugin_dir = event.src_path.split("plugins" + os.sep)[1].split(os.sep)[0]
init_file = Path(settings.ROOT_PATH) / "app" / "plugins" / plugin_dir / "__init__.py"
with open(init_file, "r", encoding="utf-8") as f:
lines = f.readlines()
pid = None
@ -91,11 +94,16 @@ class PluginManager(metaclass=Singleton):
# 扫描插件目录
plugin_package = "app.plugins"
if pid:
plugin_package = f"{plugin_package}.{pid.lower()}"
plugins = ModuleHelper.load(
plugin_package,
filter_func=lambda _, obj: hasattr(obj, 'init_plugin') and hasattr(obj, "plugin_name")
)
plugins = ModuleHelper.load_with_pre_filter(
"app.plugins",
filter_func=lambda name, obj:
hasattr(obj, 'init_plugin') and hasattr(obj, "plugin_name") and name == pid
)
else:
plugins = ModuleHelper.load(
"app.plugins",
filter_func=lambda _, obj: hasattr(obj, 'init_plugin') and hasattr(obj, "plugin_name")
)
# 已安装插件
installed_plugins = self.systemconfig.get(SystemConfigKey.UserInstalledPlugins) or []
# 排序

View File

@ -40,6 +40,38 @@ class ModuleHelper:
return submodules
@classmethod
def load_with_pre_filter(cls, package_path, filter_func=lambda name, obj: True):
"""
导入子模块
:param package_path: 父包名
:param filter_func: 子模块过滤函数入参为模块名和模块对象返回True则导入否则不导入
:return:
"""
submodules: list = []
packages = importlib.import_module(package_path)
for importer, package_name, _ in pkgutil.iter_modules(packages.__path__):
try:
if package_name.startswith('_'):
continue
full_package_name = f'{package_path}.{package_name}'
module = importlib.import_module(full_package_name)
# 预检查模块中的对象
candidates = [(name, obj) for name, obj in module.__dict__.items() if
not name.startswith('_') and isinstance(obj, type)]
# 确定是否需要重新加载
if any(filter_func(name, obj) for name, obj in candidates):
importlib.reload(module)
# reload后对象已经发生变更重新过滤已经重新加载后的模块中的对象
for name, obj in module.__dict__.items():
if not name.startswith('_') and isinstance(obj, type) and filter_func(name, obj):
submodules.append(obj)
except Exception as err:
logger.debug(f'加载模块 {package_name} 失败:{str(err)} - {traceback.format_exc()}')
return submodules
@staticmethod
def dynamic_import_all_modules(base_path: Path, package_name: str):
"""