setup.py与pip:如何覆盖requirements.txt中的某个依赖的子依赖
我现在正在开发一个软件包,在我的 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.0
的 setup.py
不会执行,除非其他所有的都执行完。在下面的图中,requests
解压后并没有 运行 setup.py
。
奇怪的是,wikipedia
的 setup.py
里包含了 import wikipedia
,这会在依赖项还没安装之前就尝试导入它们;不过它通过了 CI 测试,因为它是通过 pip 分别安装依赖项,然后再运行 setup.py
。
为了克服这个问题,我写了一个安装脚本,内容包括:
pip install -r requirements.txt
pip install wikipedia
pip install -e .
- 首先安装
requests-2.3.0
和beautifulsoup4
; - 然后安装
wikipedia
(这时可以运行setup.py
,安装wikipedia
和requests-2.2.1
); - 最后使用 'pip install -e .' 选项再次安装我的软件包和
requests-2.3.0
。
因此,requests-2.3.0
首先被安装,然后被旧版本 2.2.1 替换,最后又被 2.3.0
替换回来。
我尝试过各种方法来解决这个问题,但都让我感到困惑。我该如何解决这个麻烦呢?
1 个回答
正如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 版本中都应该可以正常工作。