diff --git a/astrbot/core/utils/pip_installer.py b/astrbot/core/utils/pip_installer.py index fbc1b5a7ec..49970b6af8 100644 --- a/astrbot/core/utils/pip_installer.py +++ b/astrbot/core/utils/pip_installer.py @@ -619,10 +619,34 @@ def _is_module_loaded_from_site_packages( return False +def _has_loaded_c_extension(module_name: str) -> bool: + """检查 sys.modules 中目标模块的依赖子树是否已包含 C 扩展。 + + 遍历已加载的 key(如 'pikepdf'、'pikepdf._core'), + 检查其 __file__ 后缀是否为 .pyd / .so。 + """ + for key in list(sys.modules.keys()): + if not (key == module_name or key.startswith(f"{module_name}.")): + continue + mod = sys.modules.get(key) + if mod is None: + continue + mod_file = getattr(mod, "__file__", "") or "" + if os.path.splitext(mod_file)[1].lower() in (".pyd", ".so"): + return True + return False + + def _prefer_module_from_site_packages( module_name: str, site_packages_path: str ) -> bool: with _SITE_PACKAGES_IMPORT_LOCK: + if _has_loaded_c_extension(module_name): + logger.debug( + "Skipping prefer for %s: C extension detected in submodules", + module_name, + ) + return False base_path = os.path.join(site_packages_path, *module_name.split(".")) package_init = os.path.join(base_path, "__init__.py") module_file = f"{base_path}.py" @@ -646,6 +670,8 @@ def _prefer_module_from_site_packages( if spec is None or spec.loader is None: return False + # 已在 _has_loaded_c_extension 中扫描过——此处收集 matched_keys + # 仅用于 pop 和异常恢复,不再重复检测 C 扩展 matched_keys = [ key for key in list(sys.modules.keys())