依赖解析¶
pip 能够确定并安装包的依赖。确定要安装的依赖项的哪个版本的进程称为依赖解析。通过将 --no-deps
传递给 pip install,可以禁用此行为。
工作原理¶
当用户执行 pip install
(例如,pip install tea
)时,pip 需要找出包的依赖(例如,spoon
、hot-water
、tea-leaves
等)以及应该安装的每个依赖项的版本。
在 pip install
运行开始时,pip 并不拥有所有请求包的依赖信息。它需要找出请求包的依赖、这些依赖的依赖,等等。在依赖解析过程中,pip 将需要下载包的分布文件,这些文件用于获取包的依赖。
回溯¶
在版本 20.3 中更改: pip 的依赖解析器现在能够回溯。
在依赖解析过程中,pip 需要对它需要安装的包版本做出假设,并在以后检查这些假设是否正确。当 pip 发现它之前做出的假设不正确时,它需要回溯,这意味着它还需要丢弃已经完成的一些工作,并回到另一个选择路径。
这看起来像是 pip 下载了同一个包的多个版本,因为 pip 明确地向用户展示了每次下载。此步骤中做出的选择回溯并非预料之外的行为或错误。这是 Python 包依赖解析的工作方式的一部分。
示例
用户请求 pip install tea
。包 tea
声明了对 hot-water
、spoon
、cup
等的依赖。
pip 从选择最新的 tea
版本开始,获取该版本的 tea
的依赖项列表。然后,它会对这些包重复此过程,选择最新的 spoon
版本,然后是 cup
版本。现在,pip 注意到它选择的 cup
版本与它选择的 spoon
版本不兼容。因此,pip 将“返回”(回溯)并尝试使用另一个版本的 cup
。如果成功,它将继续处理下一个包(例如 sugar
)。否则,它将继续回溯 cup
,直到找到与所有其他包兼容的 cup
版本。
这看起来像
$ pip install tea
Collecting tea
Downloading tea-1.9.8-py2.py3-none-any.whl (346 kB)
|████████████████████████████████| 346 kB 10.4 MB/s
Collecting spoon==2.27.0
Downloading spoon-2.27.0-py2.py3-none-any.whl (312 kB)
|████████████████████████████████| 312 kB 19.2 MB/s
Collecting cup>=1.6.0
Downloading cup-3.22.0-py2.py3-none-any.whl (397 kB)
|████████████████████████████████| 397 kB 28.2 MB/s
INFO: pip is looking at multiple versions of this package to determine
which version is compatible with other requirements.
This could take a while.
Downloading cup-3.21.0-py2.py3-none-any.whl (395 kB)
|████████████████████████████████| 395 kB 27.0 MB/s
Downloading cup-3.20.0-py2.py3-none-any.whl (394 kB)
|████████████████████████████████| 394 kB 24.4 MB/s
Downloading cup-3.19.1-py2.py3-none-any.whl (394 kB)
|████████████████████████████████| 394 kB 21.3 MB/s
Downloading cup-3.19.0-py2.py3-none-any.whl (394 kB)
|████████████████████████████████| 394 kB 26.2 MB/s
Downloading cup-3.18.0-py2.py3-none-any.whl (393 kB)
|████████████████████████████████| 393 kB 22.1 MB/s
Downloading cup-3.17.0-py2.py3-none-any.whl (382 kB)
|████████████████████████████████| 382 kB 23.8 MB/s
Downloading cup-3.16.0-py2.py3-none-any.whl (376 kB)
|████████████████████████████████| 376 kB 27.5 MB/s
Downloading cup-3.15.1-py2.py3-none-any.whl (385 kB)
|████████████████████████████████| 385 kB 30.4 MB/s
INFO: pip is looking at multiple versions of this package to determine
which version is compatible with other requirements.
This could take a while.
Downloading cup-3.15.0-py2.py3-none-any.whl (378 kB)
|████████████████████████████████| 378 kB 21.4 MB/s
Downloading cup-3.14.0-py2.py3-none-any.whl (372 kB)
|████████████████████████████████| 372 kB 21.1 MB/s
这些多行的 Downloading cup-{version}
显示 pip 正在回溯它在依赖解析期间做出的选择。
如果 pip 在依赖解析过程中开始回溯,它不知道将重新考虑多少个选择,以及需要多少计算。
对于用户来说,这意味着当 pip 开始回溯时,它可能需要很长时间才能完成。在包有很多版本的案例中,找到一个好的候选者可能需要很长时间。时间长短取决于包大小、pip 需要尝试的版本数量以及其他各种因素。
回溯降低了安装新包会意外破坏现有已安装包的风险,从而降低了环境被搞乱的风险。为了做到这一点,pip 需要做更多工作,才能找出包的哪个版本是安装的合适候选者。
可能减少回溯的方法¶
对于 pip 在依赖解析过程中过度回溯的情况,没有万能的解决方案。尽管有一些方法可以减少 pip 回溯的程度。几乎所有这些方法都需要一定程度的反复试验。
允许 pip 完成回溯¶
在大多数情况下,pip 将成功完成回溯过程。这可能需要很长时间才能完成,所以这可能不是你的首选方案。
但是,pip 可能无法找到一组兼容的版本。为此,pip 将尝试所有可能的组合,并确定不存在兼容的组合。
如果你不想等待,可以中断 pip(Ctrl+c)并尝试下面列出的策略。
减少 pip 尝试使用的版本数量¶
通常建议在 pip 正在回溯的包上添加约束(例如,在上面的示例中,是 cup
)。
你可以尝试以下操作:
$ python -m pip install tea "cup >= 3.13"
$ python -m pip install tea "cup >= 3.13"
C:> py -m pip install tea "cup >= 3.13"
这将减少它尝试的 cup
版本的数量,并可能减少 pip 安装所需的时间。
添加约束可能不正确。当这种情况发生时,缩小的搜索空间使 pip 更容易更快速地确定导致冲突的原因,并将其呈现给用户。它也可能导致 pip 由于其他冲突而回溯到其他包。
使用约束文件或锁定文件¶
此选项是上一节的进展。它要求用户了解如何检查
他们尝试安装的包
包的发布频率和兼容性策略
他们过去版本的发布说明和变更日志
在部署期间,你可以创建一个锁定文件,该文件声明每个包的每个依赖的精确包和版本号。你可以使用 pip-tools 创建它。
这意味着“工作”在开发过程中完成一次,因此将避免在部署期间执行依赖解析。
处理依赖冲突¶
本节为遇到 ResolutionImpossible
错误的 pip 用户提供实用建议,在这种错误中,由于依赖冲突,pip 无法安装他们指定的包。
理解你的错误信息¶
当你收到 ResolutionImpossible
错误时,你可能会看到类似以下内容:
$ python -m pip install package_coffee==0.44.1 package_tea==4.3.0
[regular pip output]
ERROR: Cannot install package_coffee==0.44.1 and package_tea==4.3.0 because these package versions have conflicting dependencies.
The conflict is caused by:
package_coffee 0.44.1 depends on package_water<3.0.0,>=2.4.2
package_tea 4.3.0 depends on package_water==2.3.1
$ python -m pip install package_coffee==0.44.1 package_tea==4.3.0
[regular pip output]
ERROR: Cannot install package_coffee==0.44.1 and package_tea==4.3.0 because these package versions have conflicting dependencies.
The conflict is caused by:
package_coffee 0.44.1 depends on package_water<3.0.0,>=2.4.2
package_tea 4.3.0 depends on package_water==2.3.1
C:> py -m pip install package_coffee==0.44.1 package_tea==4.3.0
[regular pip output]
ERROR: Cannot install package_coffee==0.44.1 and package_tea==4.3.0 because these package versions have conflicting dependencies.
The conflict is caused by:
package_coffee 0.44.1 depends on package_water<3.0.0,>=2.4.2
package_tea 4.3.0 depends on package_water==2.3.1
在此示例中,pip 无法安装你请求的包,因为它们都依赖于同一个包 (package_water
) 的不同版本
package_coffee
版本0.44.1
依赖于package_water
的版本,该版本小于3.0.0
但大于或等于2.4.2
package_tea
版本4.3.0
依赖于package_water
的2.3.1
版本。
有时这些消息很容易理解,因为它们使用常用的比较运算符来指定所需的版本(例如 <
或 >
)。
但是,Python 包管理也支持一些更复杂的方式来指定包版本(例如 ~=
或 *
)。
运算符 |
描述 |
示例 |
---|---|---|
|
任何大于指定版本的版本。 |
|
|
任何小于指定版本的版本。 |
|
|
任何小于或等于指定版本的版本。 |
|
|
任何大于或等于指定版本的版本。 |
|
|
完全是指定的版本。 |
|
|
任何不等于指定版本的版本。 |
|
|
任何兼容1 版本。 |
|
|
可以在版本号的末尾使用以表示所有。 |
|
1 兼容版本是指仅在最后一个部分不同的更高版本。 ~=3.1.2
等同于 >=3.1.2, ==3.1.*
。 ~=3.1
等同于 >=3.1, ==3.*
。
支持的比较运算符的详细规范可以在 PEP 440 中找到。
可能的解决方案¶
解决您错误的解决方案将取决于您的具体用例。以下是一些尝试的方法:
审核您的顶级需求¶
第一步,审核您的项目,删除任何不必要或过时的需求(例如来自您的 setup.py
或 requirements.txt
文件)。删除这些可以显著降低依赖树的复杂性,从而减少发生冲突的机会。
放宽您的顶级需求¶
有时,您要求 pip 安装的包不兼容,因为您在指定包版本时过于严格。
在我们的第一个示例中,package_coffee
和 package_tea
都被固定为使用特定版本 (package_coffee==0.44.1 package_tea==4.3.0
)。
要找到 package_coffee
和 package_tea
的版本,它们依赖于 package_water
的相同版本,您可以考虑以下方法:
放宽您愿意安装的包范围(例如
pip install "package_coffee>0.44.*" "package_tea>4.0.0"
)。要求 pip 安装
package_coffee
和package_tea
的任何版本,完全删除版本说明符(例如pip install package_coffee package_tea
)。
在第二种情况下,pip 将自动找到 package_coffee
和 package_tea
的版本,它们依赖于 package_water
的相同版本,安装
package_coffee 0.44.1
,它依赖于package_water 2.6.1
package_tea 4.4.3
,它也依赖于package_water 2.6.1
如果您想优先考虑一个包而不是另一个包,您可以只为更重要的包添加版本说明符。
$ python -m pip install package_coffee==0.44.1 package_tea
$ python -m pip install package_coffee==0.44.1 package_tea
C:> py -m pip install package_coffee==0.44.1 package_tea
这将导致
package_coffee 0.44.1
,它依赖于package_water 2.6.1
package_tea 4.4.3
,它也依赖于package_water 2.6.1
现在您已经解决了问题,您可以根据需要重新固定兼容的包版本。
放宽依赖项的要求¶
假设您无法通过放宽所需包的版本来解决冲突(如上所述),您可以尝试通过以下方法修复依赖项中的问题:
请求包维护者放宽他们的依赖项。
对包进行分叉,并自行放宽依赖项。
警告
如果您选择自行分叉包,您就放弃了包维护者提供的任何支持。自担风险!
所有需求都合适,但不存在解决方案¶
有时,根本不可能找到不冲突的包版本组合。欢迎来到 依赖地狱。
在这种情况下,您可以考虑以下方法:
使用替代包,如果这对您的项目是可以接受的。请查看 Awesome Python,了解类似的包。
重构您的项目以减少依赖项的数量(例如,将单体代码库分解成更小的部分)。
寻求帮助¶
如果以上建议均对您无效,我们建议您在以下地方寻求帮助:
请查看 “如何提出一个好问题?”,了解如何寻求帮助的技巧。
不幸的是,pip 团队无法为个别依赖冲突错误提供支持。请仅在 pip 的问题跟踪器 上创建一个工单,如果您认为您的问题暴露了 pip 中的错误。