应该选择哪个Python依赖管理器更好?

689 阅读11分钟

关于Python的美好事物之一是其全面的库生态系统,通常称为包。它们是可重复使用的代码块,对提高开发速度和代码整洁度有很大帮助。你可以前往Python包索引(PyPI),利用Stack Overflow的一些帖子征求意见,并挑选出适合你需要的包。

但是在导入和使用所选的包之前,该包的代码必须存在于你的环境中。此外,在发布你的应用程序时,用户必须能够访问这些包。你的项目所使用的包被称为依赖项,因为没有它们,你的代码就无法运行。而依赖品往往通过拉入自己的依赖品使事情变得更加复杂。

开发人员依靠 Python 包来保持他们的依赖关系在新版本到来时有新的功能或修补过的安全漏洞。但是项目可能会把一个包钉在一个特定的版本上,因为代码依赖于它不改变。

将一个软件包固定在一个特定的版本上可能会成为一个管理的噩梦。例如,你可能会在你的项目中出现两个需要同一依赖关系的不同版本的包。

此外,许多Python库依赖于非Python代码,如C或Fortran,以执行(通常)计算密集型的程序,如数学计算。困难在于,这些语言的代码在使用前需要编译。

这就是依赖性管理工具的用武之地,特别是可以管理Python和非Python依赖关系的Python包管理工具。

理想情况下,你希望你的安装是简单、安全和快速的。持续部署的一个关键部分是保持应用程序在所有环境中的不可改变性,从功能测试到生产。你所使用的包管理解决方案必须有助于实现这一点。

有许多Python依赖性管理工具可用,每个都有自己的优点和缺点。这篇文章看了一些比较流行的选择,并通过向你展示这些工具中的一些实际操作来提供一些实际帮助。

读完这篇文章后,你应该能够做出明智的选择,即哪种软件包管理工具最适合你的项目需要,并适合你喜欢的工作方式。

Pip

Python 软件开发社区的许多成员几乎只使用 Pip。Pip随Python 2.7.9之后的版本一起出现,是默认的首选打包工具。

然而,它的依赖性管理能力是非常基本的,而且它的速度被认为很慢。

默认情况下,Pip会全局安装所有东西。全局安装一切似乎是个好主意,但正如过去20年中大量显示的那样,如果你在不同的项目上工作或选择升级你的依赖,随着时间的推移你会遇到麻烦。一个解决方案是在一个虚拟环境中使用Pip,比如venvyenv

pipenv

Pipenv

Pipenv通过包装和扩展它来解决Pip的一些问题,以便在虚拟环境中工作。

在命令行中,Pipenv既丰富多彩又方便用户使用。安装Pipenv会自动为你设置一个虚拟环境。

这个虚拟环境被映射到目录路径上,使得如果你在多个项目上工作,虚拟环境的管理很容易。而且它还创建了一个Pipfile.lock文件,将你的依赖关系的版本固定下来,以帮助确保你的应用程序的环境在安装到其他系统上时是可重复的。

pipfile.lock

值得注意的是安全检查功能。 在环境中运行pipenv检查 可以突出安全漏洞。

Vulnerabilities

优点

Pipenv的优点包括:

  • 从.env 文件中自动加载环境变量
  • 与pyenv一起使用时,可以管理不同的Python版本
  • 通过使用Pipfile.lock实现环境的可重复性

缺点

Pipenv的缺点包括:

  • 历史上不经常发布
  • 安装速度慢
  • pipenv lock 命令不能捕获Pipfile中提供的Python轮子的依赖关系。这可能会导致非确定性的构建,在这种情况下,每次运行可能不会拉入相同的依赖关系,导致运行环境之间的不一致。

Pipenv是一个优秀的通用工具, Python打包机构 (PyPA)推荐它。

Poetry

Poetry是一个拥有忠实用户群的依赖管理器,它提供了与Pipenv类似的功能,即在设置时提供自动虚拟环境。它创建了一个pyproject.toml文件,这是一个Python标准,当你为在PyPI或其他地方发布而创建你的包时,你可以用它代替setup.py。

即使你不为社区建立软件包,它也能方便地跟踪项目的依赖关系。

运行poetry init 可以引导你完成创建过程。

Poetry

Poetry在处理复杂的依赖关系树方面有很好的声誉,而且由于有效地使用了缓存,它可以带来比Pipenv更快的体验。

然而,Poetry对过渡性依赖的解决方案 并不十分正确。此外, 在一个包含有漏洞的软件包的pypackage.toml文件上快速运行 poetry检查, 并没有发现任何安全漏洞。

Poetry Check

从正面看,Poetry的错误信息是高度可读的,并提供了真正的问题解决方案。另外,将开发的依赖性与生产的依赖性分开是很容易的,而且发布到PyPI 就像Poetry发布一样简单 。

优点

Poetry的优点包括:

  • 你可以把它看作是Pipenv,但安装速度更快
  • 易于发布 - 一个不常见但很重要的用例
  • 用依赖性解决方法处理依赖性冲突

缺点

Poetry的缺点包括:

  • 没有普遍地与Python预先打包在一起
  • 将虚拟环境限制在项目目录中
  • 关于 依赖解决器的问题的报告

你会注意到,依赖性解决器既是优点又是缺点。这是因为,虽然有解决方法总比没有好(依赖性地狱 不好玩),但它也会有问题,正如一篇题为《 依赖性解决仍然困难,但我们正在变得更好》的 文章所强调的 。这是一个没有明确解决方案的问题--即使在最强大的计算机上。

Conda

Conda是一个由Anaconda提供的软件包和环境管理工具。你可以用它来管理任何软件栈的软件包,但它往往是科学和机器学习的Python爱好者的首选。

它在Anaconda的旗舰版本中可用,其中包括一个Python版本、conda和数百个预置的流行软件包。它也可以在轻量级的Miniconda发行版中使用,其中只包括一个版本的Python和conda。

虽然conda是不分语言的,但PyPI和PyPA都没有正式支持它。此外,它没有像Pip那样定义好的治理模式。

你可以使用conda来创建一个新的虚拟环境,然后添加/管理你的依赖关系。你可以从文件系统的任何地方激活你的虚拟环境,这使得它成为在存储库中分发代码的绝佳选择。

Conda对于安装目前在PyPI中没有轮子的本地Python扩展包也很有用。然而,需要注意的是,conda的发布有时会被推迟。例如,众所周知,用于 conda 的 Pandas 的新版本会被推迟。

在通过运行(例如)创建一个新的 Python 环境之后:

conda create -n TestEnv python=3.9

你必须在使用前通过运行来激活环境:

conda activate TestEnv

然后,你可以用以下方式安装软件包:

conda install <package name> 

或:

pip install <package name>

Anaconda 向社区提供了 conda forge,以便为 conda 构建软件包。然而,并不是PyPi上的每一个软件包都是为conda构建的,所以你可能还需要Pip。然而,你应该注意,混合安装conda和Pip安装的软件包可能是危险的。确保你遵循 最佳实践 ,在用Pip安装剩余的软件包之前,尽可能多地用conda安装。

Conda

如果你确实遇到了依赖性冲突,通常会有一些信息来帮助你解决这个问题。

Conda Dependency Clash

虽然你仍然要靠自己来找出解决方案,但至少你有一个起点。

优点

conda的优点包括:

  • 适用于管理多种环境,包括需要Python2遗留代码的项目和需要Python3的项目,比如说
  • 当你需要为多个资源库提供相同的环境时,快速而简单。
  • 与语言无关

缺点

conda的缺点包括:

  • 由于Anaconda专注于数据科学,一些常见的Python包可能无法用于conda,迫使你混入Pip安装。混合和匹配可能会带来问题(公平地说,所有的软件包管理器都将努力控制他们没有安装的软件包)。
  • 在没有警告的情况下安装有安全漏洞的依赖项

Hatch

Hatch是一个功能丰富的项目经理,有一个内置的依赖关系管理器。它为使许多Python项目的附加组件成为多余而做出的努力是令人钦佩的。例如,它包括集成测试和管理代码覆盖率的工具等功能。像Poetry一样,它使用一个pyproject.toml文件。

Hatch

所展示的大多数命令行工具在功能上都像Poetry,但Hatch提供了更多的功能。

Hatch Tools

Hatch不会警告你有安全漏洞,但它会警告你有冲突。然后,它将安装一个可以解决冲突的所需软件包的版本。

Hatch Dependency Conflict

优点

Hatch的优点包括:

  • 与conda协同工作,帮助安装本地代码的依赖性
  • 是减少项目中工具数量的好选择

缺点

Hatch的缺点包括:

  • 大量的功能,这可能意味着一个陡峭的学习曲线

ActiveState平台

ActiveState Platform是一个适用于Python、Perl和Tcl的通用软件包和环境管理工具,以安全为优先。和Anaconda一样,ActiveState Platform也有自己的Python生态系统,为传统的Python依赖性管理工具提供了一个替代方案。

你可以使用Web GUI来配置云中的Python环境。GUI为您提供清晰的视觉效果,并为您的环境创建一个中央真理源,您可以通过一个命令轻松地与您的团队分享。

另外,你也可以使用命令行界面,即State Tool,来安装和管理自定义的Python环境,这些环境的特点是依赖性(以及任何链接的C/Fortran库)是根据源代码建立的。

因此,不需要在本地设置和管理复杂的构建环境。

无论你使用GUI还是CLI,ActiveState还提供了对软件包依赖关系的安全审计,包括交叉依赖关系,以防止你进一步引入安全漏洞。

当在你的项目中发现漏洞时,你可以收到电子邮件通知,然后选择一个有漏洞的包的版本进行升级或降级,并自动重建一个无漏洞的环境。

ActiveState Platform

在上面的截图中,你可以看到ActiveState平台是如何识别出有漏洞的软件包,并提供一个链接到细节。

优点

ActiveState平台的优点包括:

  • 用户友好的Web GUI
  • 一致的、可重复的环境
  • 在整个依赖关系树中进行清晰的安全检查
  • 为现代DevSecOps而建,具有先进的依赖性解决功能
  • 根据需求从源代码构建软件包,提高安全性

缺点

ActiveState平台的缺点包括:

  • 目前对macOS的支持很少
  • 文档需要改进
  • 管理V3.9版本之前的Python环境可能非常缓慢

结论 - 消除依赖地狱和漏洞的依赖管理

软件包管理本身就是一个困难的问题,但自从它被扩展到包括环境管理之后,它就变得更加困难了。尽管很复杂,但要把它做好还是很重要的。

不幸的是,对于Python,历来都很容易出错。这也是Python具有这么多不同的包管理器的关键原因之一。

在开发过程中,为了解决环境中的问题而把时间沉入依赖性地狱是浪费时间的。因此,许多开发者选择了一个复杂的解决方案,尽可能多地完成繁重的工作,使他们能够自由地专注于编码。

在现代技术世界中,安全的编码方式应该是最简单的编码方式。但是,在你的项目中引入一个依赖性,不可避免地会带来其他的依赖性,从而产生多米诺骨牌效应,使发现安全漏洞成为挑战。

即使你发现了这些漏洞,除非它们是关键漏洞,否则解决它们的时间和精力意味着它们很少被解决,从而使你的开发和测试环境暴露于网络攻击。

如果你想消除依赖地狱,并在开发和测试中创建更安全的代码,同时又不拖累你的冲刺,我会推荐一个能够解决所有其他限制的依赖管理器。看看 ActiveState平台吧。