From 83fac4b7b9a4d21807796e901973aead78992f82 Mon Sep 17 00:00:00 2001 From: lyt2011 <3757973483@qq.com> Date: Wed, 16 Sep 2026 05:04:26 +0000 Subject: [PATCH] =?UTF-8?q?fix(core):=20=E6=83=B0=E6=80=A7=E5=AF=BC?= =?UTF-8?q?=E5=87=BA=20Session=20=E7=B1=BB=E5=9E=8B=E4=BB=A5=E6=89=93?= =?UTF-8?q?=E7=A0=B4=20plugin=20=E2=86=94=20core=20=E5=BE=AA=E7=8E=AF?= =?UTF-8?q?=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `ncatbot/core/__init__.py` 在模块顶层直接 `from ncatbot.plugin import SessionCancelled, SessionResult`,而 `ncatbot/plugin/loader/core.py` 又会 `from ncatbot.core import ...`,从而形成 plugin ↔ core 的循环导入。 当用户(或任何入口)先 `import ncatbot.plugin` 时,plugin 包尚未初始化完 成就会触发 core 的顶层导入,导致: ImportError: cannot import name 'SessionCancelled' from partially initialized module 'ncatbot.plugin' (most likely due to a circular import) 修复方式:把这两个 Session 便利类型的 re-export 改为 PEP 562 模块级 `__getattr__` 惰性导入,仅在真正访问 `ncatbot.core.SessionCancelled` / `ncatbot.core.SessionResult` 时才导入 plugin,从而消除模块初始化期的循环。 兼容性: - `from ncatbot.core import SessionCancelled, SessionResult` 仍然可用(首次 访问触发惰性导入)。 - `dir()` 语义不变,`__all__` 保持不变。 - 任意导入顺序(core-first / plugin-first)均可正常初始化。 验证: python -c "import ncatbot.plugin; import ncatbot.core as c; print(c.SessionCancelled)" # 修复前: ImportError (circular import) # 修复后: --- ncatbot/core/__init__.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ncatbot/core/__init__.py b/ncatbot/core/__init__.py index 4f5f7b56..c3736a89 100644 --- a/ncatbot/core/__init__.py +++ b/ncatbot/core/__init__.py @@ -71,7 +71,12 @@ ) # Session 便利类型(从 plugin 层 re-export,方便用户导入) -from ncatbot.plugin import SessionCancelled, SessionResult +# 延迟到 __getattr__ 惰性导入,打破 plugin ↔ core 初始化时的循环导入 +def __getattr__(name: str): + if name in ("SessionCancelled", "SessionResult"): + from ncatbot.plugin import SessionCancelled, SessionResult + return SessionCancelled if name == "SessionCancelled" else SessionResult + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") __all__ = [ "AsyncEventDispatcher",