如何从setup.py读取顶层依赖并将固定版本依赖写入install_requires?
使用pip-tools固定Python包依赖版本并同步至setup.py
核心思路
先维护无版本限制的顶层依赖列表,用pip-tools锁定所有依赖(直接+间接)的版本,再将顶层依赖的固定版本同步回setup.py的install_requires字段——既保证生产环境依赖稳定,又能方便跟踪和更新顶层依赖。
具体操作步骤
1. 调整setup.py结构,分离顶层依赖
把无版本限制的顶层依赖单独定义,方便后续维护和跟踪:
#!/usr/bin/env python import pathlib from setuptools import setup, find_packages # 定义顶层依赖(无版本限制,作为依赖管理的基准) TOP_LEVEL_DEPS = ["package1", "package2"] setup( author="Foo", description="My package", install_requires=[], # 后续将填充锁定后的版本 extras_require={ "top_level": TOP_LEVEL_DEPS, }, version="0.1.0", )
2. 用pip-compile生成锁定的依赖文件
基于setup.py里的top_level extras,生成包含所有依赖(直接+间接)固定版本的requirements.txt:
pip-compile --extra=top_level setup.py
运行后会生成类似这样的requirements.txt:
# # This file is autogenerated by pip-compile with Python 3.10 # by the following command: # # pip-compile --extra=top_level setup.py # package1==1.0.0 package2==2.1.0 dependency-of-package1==3.0.0 # via package1
3. 提取顶层依赖的固定版本,同步至setup.py
requirements.txt包含间接依赖,而install_requires只需要你的包直接依赖的顶层包版本,所以要筛选对应行:
- 手动筛选:从
requirements.txt中找到package1和package2的版本行,替换setup.py里的install_requires:install_requires=["package1==1.0.0", "package2==2.1.0"], - 自动化处理(推荐):写个小脚本自动完成筛选和替换,避免手动出错:
运行脚本后,import re from pathlib import Path # 要和setup.py里的TOP_LEVEL_DEPS保持一致 TOP_LEVEL_DEPS = {"package1", "package2"} # 读取requirements.txt reqs_path = Path("requirements.txt") req_lines = [line.strip() for line in reqs_path.read_text().splitlines()] # 筛选顶层依赖的固定版本行 locked_reqs = [] for line in req_lines: if not line or line.startswith("#"): continue pkg_match = re.match(r"^([a-zA-Z0-9_-]+)", line) if pkg_match and pkg_match.group(1) in TOP_LEVEL_DEPS: locked_reqs.append(line) # 更新setup.py的install_requires字段 setup_path = Path("setup.py") setup_content = setup_path.read_text() setup_content = re.sub( r"install_requires=\[.*?\],", f"install_requires={locked_reqs},", setup_content, flags=re.DOTALL ) setup_path.write_text(setup_content)setup.py的install_requires会自动更新为锁定的版本。
疑问解答
你问的「直接把requirements.txt内容读入install_requires」不可行——因为requirements.txt包含了你的包不需要直接声明的间接依赖,把这些写入install_requires会导致依赖冗余,甚至引发版本冲突。正确的做法是只提取顶层依赖的固定版本同步至install_requires。
注意事项
- 每次更新顶层依赖(比如新增/移除包),都要重新运行
pip-compile生成新的requirements.txt,再同步至setup.py。 - 生产环境安装时,既可以用
pip install .(基于setup.py的固定依赖),也可以用pip install -r requirements.txt(安装所有锁定的依赖,包括间接的)。 - 要保证
TOP_LEVEL_DEPS在setup.py和自动化脚本中完全一致,避免遗漏或错误匹配。
内容的提问来源于stack exchange,提问作者Cord Kaldemeyer
相关产品推荐
相关产品推荐

