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

如何在setup.cfg中自动整合多组依赖到all项?及setup.py报错处理

自动合并Python包setup.cfg的extras依赖(避免手动维护all项)

问题背景

我在为Python包编写setup.cfg时,需要根据不同用途定义多组依赖。目前手动在[options.extras_require]里维护all项来包含所有依赖,但每次依赖变更都要手动更新,非常繁琐。希望实现all项自动包含option1、option2、option3的所有依赖,无需手动维护。

当前setup.cfg的相关配置:

[options.extras_require]
option1 =
    pkg1
    pkg2
    pkg3
    pkg4
    pkg5
option2 =
    pkg1
    pkg2
    pkg6
    pkg7
    pkg8
option3 =
    pkg3
    pkg4
    pkg9
    pkg10
all = 
    pkg1
    pkg2
    pkg3
    pkg4
    pkg5
    pkg6
    pkg7
    pkg8
    pkg9
    pkg10

配套的极简setup.py:

from __future__ import annotations

import setuptools

if __name__ == "__main__":
    # Do not add any parameters here. Edit setup.cfg instead.
    setuptools.setup()

环境信息:测试用Python 3.11.8、setuptools 68.2.2、pip 23.3.1;包需兼容Python 3.9+,要适配多版本setuptools和pip。

尝试的方案及报错

我尝试修改setup.py来合并依赖,但执行pip install -e .[all]时出现错误:

修改后的setup.py:

from __future__ import annotations

from setuptools import setup
from setuptools.config.setupcfg import read_configuration

# Run code only if file is run as a script
if __name__ == "__main__":
    # Read the configuration from setup.cfg
    config = read_configuration("setup.cfg")

    # Get the dependencies from the other sections
    option1_deps = config["options"]["extras_require"]["option1"]
    option2_deps = config["options"]["extras_require"]["option2"]
    option3_deps = config["options"]["extras_require"]["option3"]

    # Combine dependencies
    all_deps = option1_deps + option2_deps + option3_deps

    # Update the config with the combined dependences
    config["options"]["extras_require"]["all"] = all_deps

    # Pass the udpated configuration to setuptools.setup()
    setup(**config["options"])

报错信息:

Preparing metadata (setup.py) ... error
  error: subprocess-exited-with-error
  
  × python setup.py egg_info did not run successfully.
  │ exit code: 1
  ╰─> [1 lines of output]
      error in setup command: 'python_requires' must be a string containing valid version specifiers; 'SpecifierSet' object has no attribute 'split'
      [end of output]
  
  note: This error originates from a subprocess, and is likely not a problem with pip.
error: metadata-generation-failed

× Encountered error while generating package metadata.
╰─> See above for output.

note: This is an issue with the package mentioned above, not pip.

解决方案

方案1:直接在setup.cfg中引用其他extras(推荐)

setuptools从38.3.0版本开始支持在extras中直接引用其他extras组,无需修改setup.py。只需修改setup.cfg的all项:

[options.extras_require]
option1 =
    pkg1
    pkg2
    pkg3
    pkg4
    pkg5
option2 =
    pkg1
    pkg2
    pkg6
    pkg7
    pkg8
option3 =
    pkg3
    pkg4
    pkg9
    pkg10
all =
    option1
    option2
    option3

这样执行pip install -e .[all]时,setuptools会自动递归安装option1、option2、option3的所有依赖,且依赖变更时all项会自动同步,完全无需手动维护。该方案兼容Python3.9+对应的所有setuptools版本,无需担心兼容性问题。

方案2:修复setup.py的类型问题

如果一定要通过setup.py实现,需要将read_configuration解析后的python_requires(SpecifierSet对象)转换为字符串,再传入setup():

from __future__ import annotations

from setuptools import setup
from setuptools.config.setupcfg import read_configuration

if __name__ == "__main__":
    config = read_configuration("setup.cfg")
    
    # 合并并去重依赖(去重可选,避免重复条目)
    extras = config["options"]["extras_require"]
    all_deps = extras["option1"] + extras["option2"] + extras["option3"]
    all_deps = list(dict.fromkeys(all_deps))  # 保持依赖顺序的同时去重
    extras["all"] = all_deps
    
    # 将SpecifierSet对象转为字符串,修复python_requires报错
    if "python_requires" in config["options"]:
        config["options"]["python_requires"] = str(config["options"]["python_requires"])
    
    setup(**config["options"])

修改后执行pip install -e .[all]即可正常安装所有依赖,同时all项会自动同步其他组的依赖变更。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 19:14:55