From 1d3703b0e529df27ebc5a86a768d67d5c4266220 Mon Sep 17 00:00:00 2001 From: JOJO <1498581755@qq.com> Date: Mon, 1 Jun 2026 17:10:28 +0800 Subject: [PATCH] =?UTF-8?q?build(deps):=20=E5=9B=BA=E5=8C=96=20Python=20?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=E7=89=88=E6=9C=AC=EF=BC=8C=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=20lock=20=E4=B8=8E=E7=94=9F=E6=88=90=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 为便携 release 打包与可复现安装做准备(P3 依赖固化)。 - 新增 requirements.lock.txt:锁定 9 个运行时直接依赖的精确版本 - requirements.txt 顶部加注释,说明与 lock 文件的分工(宽松 vs 精确) - 新增 scripts/gen_requirements_lock.py:从已验证环境一键重生 lock, 避免手工对照版本出错 调查结论(已核实): - 项目源码真实第三方依赖与 requirements.txt 完全一致,无遗漏 - tiktoken 已不再使用(token 统计改用 API usage 字段),无需纳入 - 三个 node 项目的 package-lock.json 均已存在并被 git 追踪,npm ci 可直接用,node 端无需改动 Co-Authored-By: Claude Opus 4.8 (1M context) --- requirements.lock.txt | 20 ++++++++ requirements.txt | 2 + scripts/gen_requirements_lock.py | 83 ++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 requirements.lock.txt create mode 100644 scripts/gen_requirements_lock.py diff --git a/requirements.lock.txt b/requirements.lock.txt new file mode 100644 index 0000000..13e2dce --- /dev/null +++ b/requirements.lock.txt @@ -0,0 +1,20 @@ +# 锁定版本依赖(构建 / release 打包用)。由 scripts/gen_requirements_lock.py 生成。 +# +# 与 requirements.txt 的关系: +# - requirements.txt 人读、宽松,列出运行时直接依赖(不锁版本) +# - requirements.lock.txt(本文件) 精确版本,供便携 release 打包与可复现安装 +# +# 安装:pip install -r requirements.lock.txt +# 更新:在已验证可用的环境执行 python -m scripts.gen_requirements_lock +# +# 注:这里只锁项目运行时直接依赖;其传递依赖由 pip 在安装时解析。 + +flask==2.3.3 +flask-socketio==5.3.6 +flask-cors==3.0.10 +werkzeug==2.3.7 +httpx==0.28.1 +openai==2.8.1 +cryptography==43.0.3 +pillow==9.3.0 +websockets==10.4 diff --git a/requirements.txt b/requirements.txt index d1bfdf4..fef2642 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,5 @@ +# 运行时直接依赖(人读、宽松,不锁版本,便于开发期升级)。 +# 可复现安装 / release 打包请用 requirements.lock.txt(精确版本)。 flask flask-socketio flask-cors diff --git a/scripts/gen_requirements_lock.py b/scripts/gen_requirements_lock.py new file mode 100644 index 0000000..ba0bad7 --- /dev/null +++ b/scripts/gen_requirements_lock.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +"""根据 requirements.txt 生成 requirements.lock.txt(精确版本)。 + +读取 requirements.txt 列出的直接依赖名,从当前已安装环境查出精确版本, +写出 requirements.lock.txt。在「已验证可用」的环境中运行,确保锁定的是 +一组实测能跑起来的版本。 + +用法: + python -m scripts.gen_requirements_lock + python scripts/gen_requirements_lock.py +""" + +from __future__ import annotations + +import importlib.metadata as md +import re +import sys +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[1] +REQ_PATH = REPO_ROOT / "requirements.txt" +LOCK_PATH = REPO_ROOT / "requirements.lock.txt" + +_LOCK_HEADER = """\ +# 锁定版本依赖(构建 / release 打包用)。由 scripts/gen_requirements_lock.py 生成。 +# +# 与 requirements.txt 的关系: +# - requirements.txt 人读、宽松,列出运行时直接依赖(不锁版本) +# - requirements.lock.txt(本文件) 精确版本,供便携 release 打包与可复现安装 +# +# 安装:pip install -r requirements.lock.txt +# 更新:在已验证可用的环境执行 python -m scripts.gen_requirements_lock +# +# 注:这里只锁项目运行时直接依赖;其传递依赖由 pip 在安装时解析。 +""" + + +def _parse_requirement_names(text: str) -> list[str]: + """从 requirements.txt 提取包名(忽略注释、空行、已带版本约束的尾巴)。""" + names: list[str] = [] + for raw in text.splitlines(): + line = raw.strip() + if not line or line.startswith("#"): + continue + # 去掉版本约束/extras,仅留包名: flask[async]>=2 -> flask + name = re.split(r"[<>=!~\[ ;]", line, 1)[0].strip() + if name: + names.append(name) + return names + + +def main() -> int: + if not REQ_PATH.exists(): + print(f"找不到 {REQ_PATH}", file=sys.stderr) + return 1 + names = _parse_requirement_names(REQ_PATH.read_text(encoding="utf-8")) + if not names: + print("requirements.txt 中没有可锁定的依赖。", file=sys.stderr) + return 1 + + lines: list[str] = [] + missing: list[str] = [] + for name in names: + try: + version = md.version(name) + lines.append(f"{name}=={version}") + except md.PackageNotFoundError: + missing.append(name) + lines.append(f"# {name} (未安装,无法锁定版本)") + + LOCK_PATH.write_text(_LOCK_HEADER + "\n" + "\n".join(lines) + "\n", encoding="utf-8") + print(f"已写出 {LOCK_PATH}({len(names)} 项依赖)") + for line in lines: + print(" " + line) + if missing: + print(f"\n警告:以下依赖未安装,未能锁定版本:{', '.join(missing)}", file=sys.stderr) + print("请在已安装全部依赖的环境中重新运行。", file=sys.stderr) + return 2 + return 0 + + +if __name__ == "__main__": + sys.exit(main())