FinDataHub
39a28becc7
fix(packaging): 让 .app 的 venv 自包含(内联 Python 运行时 + 修 editable .pth)+ 补打包 common/
缺陷一:bundle 内 venv 依赖用户级 Python
----------------------------------------
三个 bundle venv 的 `python` 都是软链接,指向
`~/.local/share/uv/python/cpython-3.12-macos-aarch64-none/...`,
`pyvenv.cfg` 的 `home` 与 `.venv/bin/*` 的 **shebang 同为绝对外部路径**
(`build-app.sh` 用 `rsync -a`,会原样保留软链接)。
→ 用户执行 `uv python uninstall 3.12`、升级,或清理 `~/.local/share/uv`,
**整个 app 的 Python 侧全部失效**,而这是日常会做的操作。
缺陷二:akshare venv 的 editable .pth 指向源码仓库
---------------------------------------------------
`_editable_impl_akshare_fetcher.pth` → `<repo>/Services/akshare_fetcher/src`。
即**部署的 akshare 采集器依赖源码仓库存在于原路径**(tushare 侧则已指向 bundle 内 src)。
换机器 / 移动仓库即 `ModuleNotFoundError`。
改动
----
1. 新增 `Scripts/bin/relocate_bundle_venvs.py`(`--check` / `--dry-run` / `--apply`)
- 把 Python 运行时整个拷入 `Contents/Frameworks/python312/`(103 MB)
- 重写 `.venv/bin/python*` 软链接、`pyvenv.cfg` 的 home/executable、
`.venv/bin/*` 的 shebang、指向 bundle 外的 editable `.pth`
- `--check` 可作启动自检 / CI 门禁
2. `build-app.sh` 第 5 段补 `common/`:该段此前只 rsync 了 `extend` 与 `app`,
**漏了 `common/` 包**(服务自身入口 `app/main.py` 需要 `from common.config import ...`)。
落实与验证(部署位已执行 --apply)
----------------------------------
- 三个 venv 全部 `--check` 通过「已自包含」;解释器均解析到
`<app>/Contents/Frameworks/python312/bin/python3.12`
- 三个 venv 的关键依赖可导入:pandas 3.0.3 / akshare 1.18.64 / fastapi 0.141.1
- `tushare-fetcher --help`、`akshare-fetcher --help` 均正常
(akshare 侧修复前报 `ModuleNotFoundError: No module named 'akshare_fetcher'`)
- 真实取数:`tushare-fetcher fetch --type daily --dry-run` 正常解析 6 张表
实现过程中被验证抓出的两处自身错误
----------------------------------
1. **shebang 误指向基础解释器**:首版把 `.venv/bin/*` 的 shebang 改成
`<app>/Contents/Frameworks/python312/bin/python3.12`。该路径虽在 bundle 内,
但**执行时不带 venv 上下文** → venv 的 site-packages 不在 sys.path、
editable `.pth` 不生效 → console script 直接 ModuleNotFoundError。
正解:shebang 必须指向 **venv 自己的** `<venv>/bin/python`(它本身是指向
bundle 内解释器的软链接,能正确带出 venv 上下文)。
`--check` 的判据也据此收紧为「shebang 必须恰为本 venv python」。
2. **只看首个 venv 就提前返回**:`--apply` 原先用第一个 venv 的自包含状态决定
是否跳过,导致「tushare 已自包含、akshare 未自包含」时整批跳过、漏修。
关于"缺 common/"的更正(不夸大)
--------------------------------
实测确认:**桌面后端并不导入 `app/main.py`**(它导入 `app.dependencies` /
`app.routers.*`),因此缺 `common/` **并未导致任何当前故障**,后端一直正常工作。
本次补齐属"bundle 相对服务自身入口不完整"的正确性修复与前瞻加固。
另注:`Scripts/bin/common.py`(单文件模块)与 `kuaixun-service/common/`(包)**同名**,
两者同时进入 sys.path 时前者会遮蔽后者 —— 这是既有架构约束,已在 build-app.sh 注明。
对应地,本批另一处真实故障是**采集器被注入了失效的会话代理**(臣上一轮重启时
误带 `HTTP_PROXY=127.0.0.1:50782`),导致所有新闻源 `All connection attempts failed`、
13 小时零写入(`stuck: true`)。已用**不含代理**的环境重启:
`stuck: false`,近 10 分钟写入 346 条 / 去重入库 43 条,采集恢复正常。
境内新闻源应直连,不应走会话代理。
2026-09-19 22:34:08 +08:00
..
2026-09-19 22:34:08 +08:00
2026-09-18 22:37:32 +08:00
2026-09-19 22:34:08 +08:00
2026-09-18 22:37:32 +08:00
2026-09-19 00:27:21 +08:00