Python包如何声明开发专用依赖?requirements-dev方案是否最优
Python项目开发依赖隔离方案选型说明
你提到的拆分独立开发依赖文件的方式,是Python生态长期验证的成熟通用方案,但并非当前所有场景下的唯一行业优选,需要结合项目的维护规模、打包发布需求匹配对应方案:
1. 独立拆分多requirements文件的方案定位
- 这套方案是很多经典开源项目(包括你提到的eo-learn)在Python打包标准尚未完全统一阶段落地的通用实践,核心逻辑是通过文件隔离运行时、开发、文档等不同场景的依赖
- 典型的文件拆分结构为:
requirements.txt:仅存放包运行必须的核心依赖,提供给普通终端用户安装使用requirements-dev.txt:存放pytest、pylint、代码格式化工具、打包发布工具这类纯开发环节使用的依赖,通常文件开头会通过-r requirements.txt继承核心依赖,避免重复维护版本号,示例内容为:-r requirements.txt pytest>=7.0 pylint>=3.0 black>=23.0 build>=1.0 twine>=4.0requirements-docs.txt:存放sphinx、文档主题渲染工具这类仅文档构建环节使用的依赖
- 这套方案的优势非常明确:零特殊工具依赖,只要支持基础pip指令就可以落地,上手门槛极低
- 对应的短板也很明显:
- 依赖声明和项目的打包元数据完全脱节,普通用户通过PyPI安装包时,完全感知不到这些依赖文件的存在,必须靠贡献指南文档手动指引安装命令
- 跨文件维护依赖版本的成本较高,容易出现不同文件里依赖版本不一致的问题
- 复杂依赖分组的灵活度有限,比如要单独拆分代码检查、单元测试、版本发布这类细分场景的依赖时,需要手动维护多层文件继承关系
2. 当前行业更主流的长期维护方案
随着PEP 621打包标准的普及,现在大部分中型以上的开源包项目,更倾向于把开发依赖直接和项目元数据绑定,从根源上实现依赖隔离,典型实现是在统一的pyproject.toml配置中声明可选依赖分组,示例配置为:
[project] name = "your-package-name" # 这里填写核心运行时依赖 dependencies = ["requests>=2.30", "numpy>=1.24"] [project.optional-dependencies] # 开发全流程依赖分组 dev = ["pytest>=7.0", "pylint>=3.0", "black>=23.0", "build>=1.0", "twine>=4.0"] # 文档构建依赖分组 docs = ["sphinx>=7.0", "sphinx-rtd-theme>=1.2"]
- 这种方案的使用方式和独立requirements文件的体验完全对齐,开发者只需要执行
pip install .[dev,docs]就可以一键安装全套开发环境,普通用户执行pip install your-package-name从PyPI安装时,完全不会触碰到这些开发依赖 - 相比手动拆分requirements文件的方式,这套方案的长期维护优势非常明显:
- 所有依赖声明统一在一个配置文件里,和包的发布流程完全打通,不会出现文档指引和实际配置脱节的问题
- 不需要跨文件同步依赖版本,减少了版本错配的概率
- 兼容所有符合PEP 621标准的打包工具(setuptools、hatch、poetry、uv等),没有工具绑定的问题
3. 实际选型建议
- 如果你维护的是不需要发布到公共PyPI的内部项目、个人小项目,或者需要兼容非常旧版本的pip环境,独立拆分requirements-dev.txt、requirements-docs.txt的方式完全够用,也是经过大量项目验证的可靠方案
- 如果你维护的是面向公众发布的开源包,有持续的迭代维护需求,优先选择在
pyproject.toml中声明可选开发依赖分组的方式,长期维护成本更低 - 两种方案并不互斥,很多成熟开源项目会在
pyproject.toml声明可选依赖的同时,自动生成对应的requirements-dev.txt文件,兼顾不同使用习惯的贡献者
内容的提问来源于stack exchange,提问作者reducing activity
相关产品推荐
相关产品推荐

