【问题标题】:Resolving new pip backtracking runtime issue解决新的 pip 回溯运行时问题
【发布时间】:2021-03-15 06:58:09
【问题描述】:

随版本 20.3 一起发布的 new pip dependency resolver 安装包的时间过长。 昨天在我们的 CI 管道上,一个 docker 构建在 1 小时的 pip 安装消息后超时约 10 分钟(几乎对于任何依赖项安装的每个库都有类似的日志输出):

INFO: pip is looking at multiple versions of setuptools to determine which version is compatible with other requirements. This could take a while.
  Downloading setuptools-50.0.0-py3-none-any.whl (783 kB)
  Downloading setuptools-49.6.0-py3-none-any.whl (803 kB)
  Downloading setuptools-49.5.0-py3-none-any.whl (803 kB)
  Downloading setuptools-49.4.0-py3-none-any.whl (803 kB)
  Downloading setuptools-49.3.2-py3-none-any.whl (790 kB)
INFO: This is taking longer than usual. You might need to provide the dependency resolver with stricter constraints to reduce runtime. If you want to abort this run, you can press Ctrl + C to do so. To improve how pip performs, tell us what happened here: https://pip.pypa.io/surveys/backtracking
  Downloading setuptools-49.3.1-py3-none-any.whl (790 kB)
  Downloading setuptools-49.3.0-py3-none-any.whl (790 kB)
  Downloading setuptools-49.2.1-py3-none-any.whl (789 kB)
  Downloading setuptools-49.2.0-py3-none-any.whl (789 kB)
  Downloading setuptools-49.1.3-py3-none-any.whl (789 kB)
  Downloading setuptools-49.1.2-py3-none-any.whl (789 kB)
  Downloading setuptools-49.1.1-py3-none-any.whl (789 kB)
  Downloading setuptools-49.1.0-py3-none-any.whl (789 kB)
  Downloading setuptools-49.0.1-py3-none-any.whl (789 kB)
  Downloading setuptools-49.0.0-py3-none-any.whl (789 kB)
  Downloading setuptools-48.0.0-py3-none-any.whl (786 kB)
  Downloading setuptools-47.3.2-py3-none-any.whl (582 kB)
  Downloading setuptools-47.3.1-py3-none-any.whl (582 kB)
  Downloading setuptools-47.3.0-py3-none-any.whl (583 kB)
  Downloading setuptools-47.2.0-py3-none-any.whl (583 kB)
  Downloading setuptools-47.1.1-py3-none-any.whl (583 kB)
  Downloading setuptools-47.1.0-py3-none-any.whl (583 kB)
  Downloading setuptools-47.0.0-py3-none-any.whl (583 kB)
  Downloading setuptools-46.4.0-py3-none-any.whl (583 kB)
  Downloading setuptools-46.3.1-py3-none-any.whl (582 kB)
  Downloading setuptools-46.3.0-py3-none-any.whl (582 kB)
  Downloading setuptools-46.2.0-py3-none-any.whl (582 kB)
  Downloading setuptools-46.1.3-py3-none-any.whl (582 kB)
  Downloading setuptools-46.1.2-py3-none-any.whl (582 kB)
  Downloading setuptools-46.1.1-py3-none-any.whl (582 kB)
  Downloading setuptools-46.1.0-py3-none-any.whl (582 kB)
  Downloading setuptools-46.0.0-py3-none-any.whl (582 kB)
  Downloading setuptools-45.3.0-py3-none-any.whl (585 kB)
  Downloading setuptools-45.2.0-py3-none-any.whl (584 kB)
  Downloading setuptools-45.1.0-py3-none-any.whl (583 kB)
  Downloading setuptools-45.0.0-py2.py3-none-any.whl (583 kB)
  Downloading setuptools-44.1.1-py2.py3-none-any.whl (583 kB)
  Downloading setuptools-44.1.0-py2.py3-none-any.whl (583 kB)
  Downloading setuptools-44.0.0-py2.py3-none-any.whl (583 kB)
  Downloading setuptools-43.0.0-py2.py3-none-any.whl (583 kB)
  Downloading setuptools-42.0.2-py2.py3-none-any.whl (583 kB)
  Downloading setuptools-42.0.1-py2.py3-none-any.whl (582 kB)
  Downloading setuptools-42.0.0-py2.py3-none-any.whl (582 kB)
  Downloading setuptools-41.6.0-py2.py3-none-any.whl (582 kB)
  Downloading setuptools-41.5.1-py2.py3-none-any.whl (581 kB)
  Downloading setuptools-41.5.0-py2.py3-none-any.whl (581 kB)
  Downloading setuptools-41.4.0-py2.py3-none-any.whl (580 kB)
  Downloading setuptools-41.3.0-py2.py3-none-any.whl (580 kB)
  Downloading setuptools-41.2.0-py2.py3-none-any.whl (576 kB)
  Downloading setuptools-41.1.0-py2.py3-none-any.whl (576 kB)
  Downloading setuptools-41.0.1-py2.py3-none-any.whl (575 kB)
  Downloading setuptools-41.0.0-py2.py3-none-any.whl (575 kB)
  Downloading setuptools-40.9.0-py2.py3-none-any.whl (575 kB)
  Downloading setuptools-40.8.0-py2.py3-none-any.whl (575 kB)
  Downloading setuptools-40.7.3-py2.py3-none-any.whl (574 kB)
  Downloading setuptools-40.7.2-py2.py3-none-any.whl (574 kB)
  Downloading setuptools-40.7.1-py2.py3-none-any.whl (574 kB)
  Downloading setuptools-40.7.0-py2.py3-none-any.whl (573 kB)
  Downloading setuptools-40.6.3-py2.py3-none-any.whl (573 kB)
  Downloading setuptools-40.6.2-py2.py3-none-any.whl (573 kB)
  Downloading setuptools-40.6.1-py2.py3-none-any.whl (573 kB)
  Downloading setuptools-40.6.0-py2.py3-none-any.whl (573 kB)
  Downloading setuptools-40.5.0-py2.py3-none-any.whl (569 kB)
  Downloading setuptools-40.4.3-py2.py3-none-any.whl (569 kB)
  Downloading setuptools-40.4.2-py2.py3-none-any.whl (569 kB)
  Downloading setuptools-40.4.1-py2.py3-none-any.whl (569 kB)
  Downloading setuptools-40.4.0-py2.py3-none-any.whl (568 kB)
  Downloading setuptools-40.3.0-py2.py3-none-any.whl (568 kB)

我很困惑我们是否正确使用了新的 pip 解析器,尤其是因为

- Substantial improvements in new resolver for performance, output and error messages, avoiding infinite loops, and support for constraints files.

看到的行为在发行说明中描述为backtracking。我明白它为什么在那里。 它指定我可以使用一个约束文件(看起来像 requirements.txt)来修复依赖项的版本以减少运行时使用 pip install -c constraints.txt setup.py.

生成此约束文件的最佳方法是什么?目前,我能想到的最好方法是在新的虚拟环境中本地运行pip install setup.py,然后使用pip freeze > constraints.txt。但是,本地安装仍然需要很多时间(现在已经卡住了大约 10 分钟)。 笔记确实提到This means the “work” is done once during development process, and so will save users this work during deployment.

使用旧的依赖解析器,我可以在不到一分钟的时间内在本地安装这个包。

这里推荐的流程是什么?

编辑:我刚刚发现一些依赖项直接指向内部 gitlab 服务器。如果我直接从我们的内部包注册表安装,它会在几分钟内再次运行。

【问题讨论】:

  • 我也有同样的问题。您的编辑看起来很有趣,您能否就如何检测到 gitlab 的依赖链接以及如何修复它添加一些指导?
  • 在 setup.py 中,依赖类似于my_lib @ git+ssh://git@gitlab.our-company.com/libraries/my_lib.git@v1.2.0,所以如果你没有手动放一些东西来指向你自己的 gitlab 服务器,你就不会遇到这个问题
  • 谢谢。事实上,这不是我们的情况。
  • 我可能会再次降级到 pip 19..
  • 不幸的是 pip 19 产生了强盗安全警告:/ 所以,不再是一个选项 :( 很遗憾,因为 pip 19 工作得非常好。我真的不喜欢新的变化。至少应该有一个像这样的选项--no-backtracking。当我要求安装包 A 时,没有指定版本,并且该包尚未安装,我希望 pip 安装最新版本的 A,或者死在尝试。我不希望它安装某个版本两年前的包裹。

标签: python pip


【解决方案1】:

由于我遇到了类似的问题,我同意这很烦人。回溯可能是有用的功能,但您不希望等待数小时才能完成不确定的成功。

我找到了几个可能有帮助的选项:

  • 使用@Daniel Davee 的答案中建议的旧解析器 (--use-deprecated=legacy-resolver),但这更像是临时解决方案,而不是适当的解决方案。
  • 使用--no-deps 选项跳过解析依赖项。我一般不建议这样做,但在某些情况下,尽管存在一些冲突,但您可以拥有一组工作包版本。
  • 减少 pip 将尝试回溯的版本数量并对包依赖项更加严格。这意味着而不是把例如numpy 在我的 requirements.txt 中,我可以尝试 numpy >= 1.18.0 或者更严格地使用 numpy == 1.18.0。严格性可能会有很大帮助。

检查以下来源:

我仍然没有一个总能有所帮助的正确答案,但 requirements.txt 的最佳实践似乎是“固定”包版本。我发现 pip-tools 可以帮助您管理此问题,即使使用了 constrains.txt(但我正处于实验阶段,因此无法告诉您更多信息)。

更新(2021-04):

似乎问题的作者能够解决问题(使用自定义 gitlab 服务器),但我想扩展这个答案,因为它可能对其他人有用。

在阅读和尝试之后,我最终将我所有的包版本都固定到了一个特定的版本。这确实应该是正确的方法。尽管没有它一切仍然可以工作,但在某些情况下,如果您不固定依赖项,您的包管理器将静默安装一个新版本(当它发布时)可能存在错误或不兼容(这发生在我身上 dask去年)。

有几个工具可以帮助你,我推荐以下方法之一:

pipreqs 最简单的一个

  • pipreqs 是一个库,可以根据任何项目的导入生成 pip requirements.txt 文件
  • 您可以从 pip install pipreqs 开始,然后在项目根目录中运行 pipreqs(如果您的要求已经存在,则最终使用 --force 标志)
  • 它将根据您项目中的导入和从您的环境中获取的版本轻松创建带有固定版本的requirements.txt
  • 那么您可以随时基于此requirements.txt 创建新环境

这是一个非常简单的工具(你甚至不需要编写你的 requirements.txt)。它不允许你创建复杂的东西(对于大型项目可能不是一个好的选择),上周我发现了一个奇怪的行为(见this)但总的来说我对这个工具很满意,因为它通常工作得很好。

使用pip-tools

还有其他几种常用的工具,例如 pip-toolsPipenvPoetry。您可以在Faster Docker builds with pipenv, poetry, or pip-toolsPython Application Dependency Management in 2018 中阅读更多内容(较旧但对我来说似乎仍然有效)。在我看来,最好的选择(尽管它取决于您的项目/用例)仍然是pip-tools

您可以(这是一种选择,在docs 中查看更多信息):

  • 创建requirements.in(格式与requirements.txt相同,是否固定某些包依赖取决于您)
  • 然后您可以通过pip install pip-tools 使用它并运行pip-compile requirements.in
  • 这将生成新的requirements.txt 文件,其中所有版本都固定,很明显,来源是什么
  • (可选)您可以使用--generate-hashes 选项运行它
  • 然后您可以(与pipreqs 一样)随时基于此requirements.txt 创建新环境
  • pip-tools 为您提供--upgrade 选项以升级最终要求
  • 支持分层需求(例如具有开发和生产版本)
  • pre-commit有集成
  • 提供pip-sync 工具来根据 requirements.txt 更新您的环境

你可以用它做更多的事情,我真的很喜欢与pre-commit 的集成。这允许您使用与以前相同的要求(仅使用.in 后缀)并添加自动更新requirements.txt 的预提交挂钩(因此您将永远不会遇到与生成的requirements.txt 不同的本地环境,这可能很容易发生当你手动运行某些东西时)。

【讨论】:

  • 我已经将所有内容都固定到了确切的版本,但我仍然收到永恒的“pip 正在查看多个版本”消息。 :(
  • @PeterBengtsson:你能分享一下你的 requirements.txt 吗?
  • gist.github.com/peterbe/48ed9016a3f715ea15fa80be983b3263 我使用 pip 21.1.1 并输入:pip install -r dev-requirements.txt -r requirements-constraints.txt -r requirements.txt
  • 仍然挂起。试过很多次。每个依赖项都被完全固定。
【解决方案2】:

所以他们正在更改解析器,这似乎是一个错误。有用的是使用旧的解析器,通过使用标志

--use-deprecated=legacy-resolver

这显然可以工作到 pip 21.0。

来源 https://github.com/pypa/pip/issues/9215

【讨论】:

  • 我特意寻求不使用旧解析器的解决方案
  • @Bromide,OP 已经提供了消息和错误跟踪。你还需要什么?不仅仅是他,包括我自己在内的多人都遇到了同样的错误,我们正在寻找解决这个问题的解决方案。
  • 这实际上非常有用,因为当您切换到旧的解析器时,它会为未解析的依赖项打印一个错误,并准确说明是哪个版本引脚导致了问题。
  • 仅供参考,pip 21.1.2 中仍支持--use-deprecated=legacy-resolver
  • 感谢您添加此内容,我花了几个小时等待 pip 安装完成。使用旧的解析器,它在 2 分钟内完成。
【解决方案3】:

我已固定所有依赖项。您将不得不稍后或现在固定它们,所以现在最好这样做。我在pip 20.3.1

如果我们不固定任何依赖项,则新的依赖项解析器算法会检查每个可用版本与每个依赖项(从最新版本到初始版本标签)。

【讨论】:

  • 对于我们中的许多人来说,这个问题仍然存在。
【解决方案4】:

就我而言,它从未完成。原因是将djangorestframework 更新为与django 不兼容的版本。我希望它安装djangorestframework-3.12.4,它依赖于django >= 2.2,并且在requirements.txt 中也有django==2.0.2

【讨论】:

    【解决方案5】:

    将您的点子降级到版本 20.x 这是您在 pip 版本 21.x 中将面临的问题

    【讨论】:

    • 请通过添加一些相关信息、确切步骤等来改进您的回复。
    • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
    • 不是我自己的选择,因为 20.x 存在由 bandit 标记的安全问题。
    【解决方案6】:

    即使我在 requirements.txt 中的所有包都已修复版本,但问题仍然存在。我只是将它们更新到最新版本。当然,这会带来额外的努力来保证没有任何问题,但它似乎为我解决了这个问题。

    【讨论】:

      猜你喜欢
      • 2021-09-07
      • 2020-06-30
      • 1970-01-01
      • 2020-07-04
      • 1970-01-01
      • 2017-02-24
      • 2021-05-29
      • 2011-08-15
      • 2019-10-22
      相关资源
      最近更新 更多