From 0929253620ef6ffe62bcdd35bb3a261da144ff74 Mon Sep 17 00:00:00 2001 From: shy3130 <415333856@qq.com> Date: Thu, 8 Oct 2026 10:36:26 +0800 Subject: [PATCH] =?UTF-8?q?fix(packaging):=20app/custom=20=E6=89=A9?= =?UTF-8?q?=E5=B1=95=E5=8F=8C=E5=A3=B0=E6=98=8E=E9=9A=8F=E6=A1=8C=E9=9D=A2?= =?UTF-8?q?=E5=8C=85=E5=8F=91=E5=B8=83,=20=E4=BF=AE=E5=A4=8D=20AI=20?= =?UTF-8?q?=E5=AF=B9=E8=AF=9D=E5=8A=A9=E6=89=8B=20405=20(#459)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit loader 运行时 importlib+pkgutil 发现 app/custom/*, 静态分析不可见; 未声明时冻结包里扩展静默消失, 助手路由未注册 → SPA 兜底返回 405。 datas 落盘 _internal/app/custom + hiddenimports 进 PYZ, 仿 fuyao 双声明; 新增 test_packaging_spec.py 锁定打包不变量。 --- backend/tests/test_packaging_spec.py | 31 ++++++++++++++++++++++++++++ packaging/tsp.spec | 11 ++++++++++ 2 files changed, 42 insertions(+) create mode 100644 backend/tests/test_packaging_spec.py diff --git a/backend/tests/test_packaging_spec.py b/backend/tests/test_packaging_spec.py new file mode 100644 index 00000000..2f867135 --- /dev/null +++ b/backend/tests/test_packaging_spec.py @@ -0,0 +1,31 @@ +"""tsp.spec 打包不变量 — 运行时动态发现的模块必须随冻结产物发布 (issue #459)。 + +app/extensions/loader.py 用 importlib.import_module + pkgutil.iter_modules 在 +运行时发现 app/custom/*, 两条链路对 PyInstaller 静态分析都不可见; tsp.spec +未声明时冻结产物里扩展静默消失(桌面版 AI 对话助手 405, 且无任何日志)。 +锁定双声明契约: + - hiddenimports(collect_submodules) 进 PYZ —— 保 import_module 可导入; + - datas 落盘到 app/custom —— frozen 下 app.__path__ 解析到 _internal/app, + 保 pkgutil.iter_modules 可枚举(与 fuyao 插件同一处理方式)。 +""" + +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[2] +SPEC_TEXT = (REPO_ROOT / "packaging" / "tsp.spec").read_text(encoding="utf-8") +# 只断言代码行, 避免被注释里的字样误判为已声明 +SPEC_CODE = "\n".join( + line for line in SPEC_TEXT.splitlines() if not line.lstrip().startswith("#") +) + + +def test_spec_declares_custom_extensions(): + """app/custom/* 双声明: PYZ 可导入 + 磁盘可枚举, 缺一冻结后扩展静默消失。""" + assert 'collect_submodules("app.custom")' in SPEC_CODE + assert '"app/custom"' in SPEC_CODE + + +def test_spec_declares_builtin_plugin_fuyao(): + """fuyao 插件双声明不被回归 (同类动态发现问题, 见 spec 内注释)。""" + assert "app.plugins.fuyao.provider" in SPEC_CODE + assert "app/plugins/fuyao" in SPEC_CODE diff --git a/packaging/tsp.spec b/packaging/tsp.spec index a2b5e317..072776ad 100644 --- a/packaging/tsp.spec +++ b/packaging/tsp.spec @@ -76,6 +76,17 @@ hiddenimports += [ "app.plugins.fuyao.client", ] +# ── 后端源码扩展 (app/custom/*) ────────────────────────────────────── +# extensions/loader.py 运行时用 importlib.import_module + pkgutil.iter_modules +# 发现 app/custom/* — 与插件同样对静态分析不可见, 必须双声明 (issue #459: +# 未声明时冻结包里扩展静默消失, 助手路由未注册 → 请求落到 GET-only SPA 兜底 +# 返回 405): +# datas 落盘到 _internal/app/custom — frozen 下 app.__path__ 解析到 +# _internal/app, 保 pkgutil 枚举与磁盘可见性; +# hiddenimports 进 PYZ — 保 importlib.import_module 可导入。 +datas += [(str(ROOT / "backend" / "app" / "custom"), "app/custom")] +hiddenimports += collect_submodules("app.custom") + # ── pywebview 平台后端 (动态导入, PyInstaller 默认抓不到) ──────────── hiddenimports += collect_submodules("webview") hiddenimports += collect_submodules("webview.platforms")