"""厂商集成包自动发现。 扫描 ``integrations/`` 目录下所有子包(厂商集成包),通过 ``importlib.import_module`` 触发子包 ``__init__.py`` 顶层副作用完成自注册。本函数不调用任何注册函数。 约定: - 使用 ``pkgutil.iter_modules`` 扫描 integrations 包路径下所有子包(ispkg=True), 与 framework/auth_plugins/discovery.py 模式一致 - 跳过框架自身模块黑名单:registry / schemas / discovery / operation_registry - 仅 ``importlib.import_module(name)``,不调用任何注册函数 - 注册逻辑由子包 ``__init__.py`` 顶层副作用完成 容错策略(与 framework/registry/discovery.py::discover_adapters 对齐): - ImportError(可选依赖缺失)→ logger.warning,不中断启动 - 其他异常(如 metadata 校验失败、register 键冲突)→ 向上抛出,快速失败 """ from __future__ import annotations import importlib import logging import pkgutil from pathlib import Path logger = logging.getLogger(__name__) # 框架自身模块黑名单:非厂商集成包,跳过 _BLACKLIST = {"registry", "schemas", "discovery", "operation_registry"} def discover_integration_packages() -> list[str]: """自动发现并导入 integrations/ 目录下所有厂商集成子包。 Returns: 成功导入的子包完整模块名列表(如 ``["yuxi.external_systems.integrations.dynamics365"]``)。 返回 list[str] 而非 None,便于启动日志记录与单元测试断言已加载的集成包。 """ package_path = Path(__file__).parent package = "yuxi.external_systems.integrations" imported: list[str] = [] for _, name, ispkg in pkgutil.iter_modules([str(package_path)]): if not ispkg or name in _BLACKLIST or name.startswith("_"): continue module_name = f"{package}.{name}" try: importlib.import_module(module_name) imported.append(module_name) except ImportError as exc: logger.warning("集成包 %s 加载失败(缺少可选依赖): %s", name, exc) return imported