setup.py与pip:如何覆盖requirements.txt中的某个依赖的子依赖

27 投票
1 回答
24255 浏览
提问于 2025-04-18 08:08

我现在正在开发一个软件包,在我的 requirements.txt 文件中,有一个依赖项:wikipedia。现在,wikipedia 的版本是 1.3,它依赖于 requests-2.2.1,而我的软件包使用的是 2.3.0 版本。

而且,正如你所想的,安装 wikipedia-1.3 需要它的依赖项先存在。

但是,如果我新建一个虚拟环境,然后直接在 requirements.txt 中包含 wikipedia,就会出现 ImportError 错误,提示找不到 requests。这是因为在 setup.py 运行时,requests-2.3.0setup.py 不会执行,除非其他所有的都执行完。在下面的图中,requests 解压后并没有 运行 setup.py

request getting installed but not running setup.py simultaneously

奇怪的是,wikipediasetup.py 里包含了 import wikipedia,这会在依赖项还没安装之前就尝试导入它们;不过它通过了 CI 测试,因为它是通过 pip 分别安装依赖项,然后再运行 setup.py

为了克服这个问题,我写了一个安装脚本,内容包括:

pip install -r requirements.txt
pip install wikipedia
pip install -e .
  • 首先安装 requests-2.3.0beautifulsoup4
  • 然后安装 wikipedia(这时可以运行 setup.py,安装 wikipediarequests-2.2.1);
  • 最后使用 'pip install -e .' 选项再次安装我的软件包和 requests-2.3.0

因此,requests-2.3.0 首先被安装,然后被旧版本 2.2.1 替换,最后又被 2.3.0 替换回来。

我尝试过各种方法来解决这个问题,但都让我感到困惑。我该如何解决这个麻烦呢?

1 个回答

14

正如Martijn所提到的,正确的方法是为项目指定一个最低版本,前提是未来的子依赖版本能够保持完全兼容。

如果你没有办法修改需求文件,你可以下载这个项目,然后在本地编辑需求文件,指定你想要的任何版本。你可以通过 pip download 命令来做到这一点:

pip download wikipedia==1.3

另外,如果你想用 pip 完成整个过程,并且保持 requests==2.3.0 的版本,而不需要删除再重新安装,你可以指定一个 constraints 文件。这样做可以通过:

pip install -c constraints.txt wikipedia==1.3

其中,constraints.txt 文件的内容可以是这样的:

requests>=2.3.0
beautifulsoup4

这样会产生一个警告,但 wikipedia 包会被安装:

wikipedia 1.3.0 has requirement requests==2.2.1, but you'll have requests 2.3.0 which is incompatible.
Installing collected packages: wikipedia
Successfully installed wikipedia-1.3.0

现在,如果你真的知道自己在做什么(或者只是想试试是否有效),你可以使用 --no-deps 这个选项,它会完全忽略包的依赖关系,并且不会产生上面的警告:

pip install --no-deps -c constraints.txt wikipedia==1.3

在这两种情况下,使用 pip freeze 可以看到:

beautifulsoup4==4.6.0
bs4==0.0.1
requests==2.3.0
wikipedia==1.3.0

注意:这是在 pip 10.0.1 版本下测试的,但在任何较新的 pip 版本中都应该可以正常工作。

撰写回答