You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python应用依赖管理规范及pyproject.toml适配问题咨询

问题背景

我有一个Python应用(非库),希望发布为可通过pip安装的包。为确保该应用在当下、一个月后乃至两年后通过pip install都能稳定安装并运行,我计划使用pip-tools等工具固定所有依赖版本。

当前工作流

当前我的包涉及三个文件:

  • requirements.in:列出应用的直接依赖,无版本限制或采用宽松版本锁定,作为pip-compile的源文件。
  • requirements.txt:由pip-compile从requirements.in生成的包含所有依赖(含传递依赖)的完整锁定文件,但该文件不属于Python wheel,因此pip install无法直接使用。
  • setup.py:在install_requires中读取编译后的requirements.txt,以便将完整的固定依赖信息写入wheel元数据供pip install使用(示例如下):
# setup.py
setup(
  ...
  # 伪代码
  "install_requires": pip.parse(Path(".")/"requirements.txt")
  ...
)

技术问询

  1. 该实现方式是否合理?是否存在更优方案?
  2. Python应用依赖管理的最佳实践是什么?是在setup.py中固定所有依赖(含传递依赖),还是仅固定直接依赖(信任其自身的依赖锁定)?
  3. 这种动态读取requirements.txt的方式如何适配现代声明式的pyproject.toml方案?是否无法实现自动化,必须手动将编译后的requirements.txt内容复制到pyproject.toml的依赖部分?

回答

1. 当前实现的合理性与更优方案

当前方案有一定合理性,但存在潜在问题:

  • 动态读取requirements.txt会让setup.py的执行依赖pip和pathlib,打包环境缺失这些工具时会直接报错;
  • pip.parse的输出格式不一定完全符合PEP 508规范,可能触发wheel元数据校验失败。

更优方案:

  • 用pip-compile直接生成符合PEP 508的依赖列表,写入临时文件或直接生成setup.py/pyproject.toml的依赖段;
  • 或者编写简单脚本,将requirements.txt的内容转换为合规格式后,同步到打包配置文件中,避免动态读取的依赖风险。

2. Python应用依赖管理的最佳实践

对于非库类的Python应用,最佳实践是固定所有依赖(包括传递依赖)的精确版本:

  • 应用需要长期稳定运行,传递依赖的版本更新可能引入兼容性问题(比如小版本更新改变核心API);
  • 仅固定直接依赖的话,其依赖的包后续可能出现破坏性变更,导致应用运行失败;
  • 注意:必须使用精确版本号(如requests==2.31.0)而非版本范围,确保每次安装的依赖完全一致。

(注:库类项目则相反,应仅固定直接依赖的版本范围,给下游用户留足依赖适配空间,但你的场景是应用,全量锁定更合适)

3. 适配pyproject.toml的方案

不需要手动复制,完全可以通过自动化脚本实现同步:

  • 编写Python脚本,读取requirements.txt内容,过滤注释和空行,将每一行转换为PEP 508格式(带哈希的行可以去掉哈希,因为wheel元数据不支持哈希校验);
  • 用tomllib(Python 3.11+内置)或tomli-w(低版本兼容)读写pyproject.toml,将转换后的依赖列表写入project.dependencies字段;
  • 将脚本加入打包前的流程(比如pip-compile之后执行),确保pyproject.toml的依赖始终与requirements.txt同步。

简单脚本示例:

import tomllib
import tomli_w

# 读取并处理requirements.txt
with open("requirements.txt", "r") as f:
    dependencies = [
        line.strip() for line in f 
        if line.strip() and not line.startswith("#")
    ]

# 读取pyproject.toml并更新依赖
with open("pyproject.toml", "rb") as f:
    pyproject_data = tomllib.load(f)

pyproject_data["project"]["dependencies"] = dependencies

# 写回pyproject.toml
with open("pyproject.toml", "wb") as f:
    tomli_w.dump(pyproject_data, f)

内容的提问来源于stack exchange,提问作者timmwagener

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 22:20:41