43

我即将发布一个我过去几周一直在研究的 Python 库。我已经阅读了很多关于 Python 依赖项的内容,但还不太清楚:

有些人假装你永远不应该固定你的依赖版本,因为它会阻止你的库的用户升级这些依赖。

其他一些人声称您应该始终固定您的依赖项版本,因为这是保证您的版本按照开发时的方式工作的唯一方法,并防止依赖项中的重大更改对您的库造成严重破坏。

我不知何故选择了一个混合解决方案,我假设我的依赖项使用语义版本控制并且只固定主要版本号somelib >= 2.3.0, < 30比如即使只是补丁号被撞)。

截至目前,我不确定哪种方式是最好的。是否有官方指南(甚至可能是 PEP?)规定了有关 Python 依赖项的最佳实践以及如何指定它们?

4

3 回答 3

70

其他两个答案相互矛盾的原因是它们都是正确的(并且值得一读),但它们适用于不同的情况。

如果你在 PyPI 上发布一个库,你应该声明你知道的任何依赖项,而不是固定到特定版本。例如,如果您知道自己需要>= 1.2,但1.4已损坏,则可以编写类似somepkg >= 1.2, != 1.4. 如果您知道其中一件事是somepkg遵循 SemVer,那么您可以添加一个< 2.

如果您正在构建自己部署的 Web 应用程序之类的东西,那么您应该固定所有确切的依赖项,并使用 pyup.io 或 requires.io 之类的服务在新版本发布时通知您。通过这种方式,您可以保持最新状态,同时确保您部署的版本与您测试的版本相同。

请注意,这两条建议是相辅相成的:事实上,如果应用程序 A 使用库 B,那么 A 的作者或 B 的作者可以固定 B 的依赖项,但不能同时固定两者。所以我们必须选择一个。这里的基本原则是最好尽可能晚地完成,即由 A 的作者完成,他可以看到他们的整个系统;图书馆 B 的工作是传递一些有用的提示来帮助 A 做出这些决定。特别是,如果 A 所依赖的所有库都准确地记录了他们对底层依赖项的了解,那么 A 就有可能在它们重叠时做出明智的决定。就像如果依赖项 B 依赖于requests >= 1.0, != 1.2,而依赖项 C 依赖于requests >= 1.1,那么我们可以猜测 1.1 或 1.3 可能是固定的好版本。如果依赖项 B 依赖于requests == 1.1并且依赖项 C 取决于requests == 1.2,那么我们就被卡住了。

于 2017-07-06T02:01:46.630 回答
16

固定可能会出现问题并导致安全风险。特别是对于一个库,就像你的情况一样,如果它通常与其他本身将具有依赖关系的 PyPI 包结合使用,它可能会导致更多的依赖关系冲突。

为什么?在分析了数以万计的 PyPI 包及其当前的依赖冲突率之后,对Python Dependency Resolution的详细研究讨论了这个问题。它解释说:

如果发行版没有安装到它自己的、空的、单一用途的环境中,那么如果依赖版本都被固定而不是保持范围灵活,那么依赖冲突的可能性就会大大增加。

并指出,固定会干扰升级,从而加剧安全问题。

它建议:

如果一个项目固定依赖关系,那么它必须准备好在每次有项目直接或间接依赖的任何重要版本时发布一个新版本,一直到依赖链。

于 2017-04-15T03:45:25.707 回答
10

您应该始终固定您的依赖项,因为它增加了安全、可重复构建的可能性,即使随着时间的推移。固定版本是您作为包维护者的声明,您已验证您的代码在给定环境中工作。这有一个很好的副作用,可以保持您的理智,因为您不会被错误报告所淹没,在这些错误报告中,您必须对每个包的依赖关系和系统细节进行检查。

用户始终可以选择忽略固定的依赖版本,并自行承担风险。但是,当您发布库的新版本时,您应该更新依赖项版本以进行改进和错误修复。

PEP 426 关于语义依赖(Python 软件包的元数据)的部分指出:

“依赖管理严重依赖于PEP 440(PEP 440 - 版本标识和依赖规范)中定义的版本标识和规范方案。”

据此,我推断权威的“最佳实践”是对您的依赖项进行版本控制,因为 PEP 与打包的关系被声明为“高度依赖”相关 PEP 概述的版本控制细节。

于 2015-02-13T23:34:11.670 回答