Python 依赖地狱:virtualenv 和全局依赖之间的妥协?

新手上路,请多包涵

到目前为止,我已经测试了多种在 Python 中 管理项目依赖 项的方法:

  1. 使用 pip 全局安装所有东西(节省空间,但迟早会给你带来麻烦)
  2. pip & venv 或 virtualenv(管理起来有点麻烦,但在很多情况下没问题)
  3. pipenv & pipfile(比 venv/virtualenv 简单一点,但速度慢,而且有些供应商锁定,虚拟环境隐藏在实际项目文件夹之外的其他地方)
  4. conda 作为包和环境管理器(只要包在 conda 中都可用就很好,混合 pip 和 conda 有点 hacky)
  5. 诗歌-我没试过这个

我对所有这些(除了 1.)的问题是我的硬盘空间很快就被填满了:我不是开发人员,我在日常工作中使用 Python。因此,我有数百个小项目,它们都各司其职。 Unfortunately, for 80% of projects I need the “big” packages: numpy , pandas , scipy , matplotlib - you name it .一个典型的小项目大约有 1000 到 2000 行代码,但在 venv/virtualenv/pipenv 中有 800MB 的包依赖。 _实际上_,我有大约 100+ GB 的硬盘驱动器充满了 python 虚拟依赖项。

此外,在每个虚拟环境中安装所有这些需要时间。我在 Windows 中工作,许多软件包无法从 Windows 中的 pip 轻松安装: Shapely , Fiona , GDAL 编译轮这很简单,但它会破坏大多数工作流程(例如 pip install -r requirements.txtpipenv install 来自 pipfile)。我觉得我有 40% 的时间在安装/更新包依赖项,而只有 60% 的时间在编写代码。 Further, none of these package managers really help with publishing & testing code, so I need other tools eg setuptools , tox , semantic-release , twine

我和同事谈过,但他们都面临同样的问题,而且似乎没有人有真正的解决方案。我想知道是否有一种方法可以全局安装一些软件包,例如您在大多数项目中使用的软件包——例如 numpy , pandas , scipy , matplotlib would be installed with pip in C:\Python36\Lib\site-packages or with conda in C:\ProgramData\Miniconda3\Lib\site-packages - these are well developed packages that don’t often打破东西。如果,我想尽快在我的项目中解决这个问题。

其他东西会放在本地 virtualenv 文件夹中 - 我很想将我当前的工作流程从 pipenv 移动到 conda

这种方法是否有意义?至少最近 python 有了很多发展,也许出现了一些我还没有看到的东西。是否有关于如何在这样一个混合的全局本地环境中设置文件的最佳实践指南,例如如何维护 setup.pyrequirements.txtpyproject.toml 共享通过 Gitlab、Github 等开发项目?有哪些陷阱/注意事项?

Chris Warrick 也有 这篇很棒的博客文章,对它进行了非常全面的解释。

[2021 年更新]

由于这篇文章仍然有很多观点,这里是一个主观的 2021 年更新:

  • 如果你是数据科学的,(mini) conda 还是值得一看的
  • 否则, 诗歌pyproject.toml 似乎是共同商定的分母

[2020 年更新]

半年后,我可以说使用 Conda ( Miniconda ) 解决了我的大部分问题:

  • 它在每个系统、WSL、Windows、本机 Linux 等上运行 conda env create -f myenv.yml 在每个平台上都是相同的
  • 大多数包已经在 conda-forge 上可用,很容易让自己的包在 conda-forge 上被接受
  • 对于那些不在 conda 上的包,我可以在 conda 环境中安装 pip 并使用 pip 从 pypi 添加包。提示: conda update --all -n myenv -c conda-forge 只会更新来自 conda 的包,而不是那些安装了 pip 的包。必须使用 pip install pack_name --upgrade 手动更新 Pip 安装的依赖项。请注意,在 conda 中使用 pip 安装软件包是一种通常应 避免 的紧急解决方案
  • 我可以创建 strict 或 open environment.yml ,指定 conda 通道优先级、来自 conda 的包和来自 pip 的包
  • 我可以在单个语句中从这些 yml 创建 conda 环境,例如在 Gitlab 持续集成中设置开发环境,使用 Miniconda3 Docker - 这使得测试运行非常简单直接
  • yml 中的包版本可以根据情况定义为严格或开放。例如,您可以将 env 修复为 Python 3.6,但让它检索此版本范围内的任何安全更新(例如 3.6.9)
  • 我发现 conda 几乎解决了 Windows 中 c 编译依赖的所有问题; Windows 中的 conda env 确实允许将 python 代码 冻结 为可执行文件(已测试!),该可执行文件可以分发给由于某种原因无法使用包管理器的 Windows 最终用户。
  • 关于“大依赖”的问题:我最终创建了许多特定的(即小的)和一些非特定的(即大的)conda 环境:例如,我有一个相当大的 jupyter_env ,其中 jupyter 实验室和我的大部分科学包都已安装(numpy、geos、pandas scipy 等)——每当我需要访问这些工具时,我都会激活它,我可以在一个地方使它们保持最新状态。对于特定包的开发,我有仅用于包依赖项的额外环境(例如 packe1_env )。我总共有大约 10 个环境,这是可以管理的。基本 conda 环境中安装了一些通用工具,例如 pylint 。警告:要使 pylint/pycodestyle/autopep8 等在 VS Code 中工作(例如),它必须安装到包含 python-code-dependencies 的相同环境中 - 否则,您将收到未解决的导入警告
  • 我用 Windows 的 Chocolatey 包管理器安装了 mini conda。我使用 conda update -n base conda 保持最新状态,我的环境使用 conda update --all -n myenv -c conda-forge 每周一次,效果很好!
  • 新更新: 有一个 --stack 标志可用(截至 2019-02-07 ),允许堆叠 conda 环境,例如 conda activate my_big_env 然后 conda activate --stack dev_tools_env 许多环境中可用的软件包。但是,请谨慎使用——我发现代码 linter,例如 pylint,必须与被 lint 的代码的依赖项位于相同的环境中
  • 新更新 2 :我开始使用 conda 来自 Windows Subsystem for Linux (WSL),这再次显着改善了我的工作流程:包安装速度更快,我可以在直接连接到的 Windows 中使用 VS Code Insiders WSL 和 Linux 环境中 python 包的错误要少得多。
  • 附带说明的 另一个更新Miniconda Docker 允许将本地 conda env 工作流完美地转换为容器化基础设施(CI 和 CD),现在测试了一段时间并且非常满意 - Dockerfile 比 Python Docker 更干净,因为 conda 管理更多依赖工作比 pip 做的。我现在越来越多地使用它,例如,在使用从容器内启动的 jupyter 实验室时。
  • 是的,我偶然发现了 conda env 中某些包之间的兼容性问题,但很少见。有两种方法:如果它是一个必须稳定工作的重要环境,启用 conda config --env --set channel_priority strict 这将只安装兼容的版本。对于非常少和罕见的包组合,这可能会导致无法解决的依赖冲突(即无法创建 env)。在这种情况下,我通常会为实验性开发创建较小的环境,使用较少的包并将 channel_priority 设置为 flexible (默认值)。 Sometimes, package subsets exists that are easier to solve such as geoviews-core (instead of geoviews ) or matplotlib-base (instead of matplotlib ).对于那些无法使用 strict 解决的实验性环境,例如 conda create -n jupyter_exp_env python=3.6 -c conda-forge --- ,这也是一种尝试较低 python 版本的好方法。万不得已的方法是使用 pip 安装包,这避免了 conda 的包解析器(但可能会导致环境不稳定和其他问题,您已被警告!)。确保首先在您的环境中明确安装 pip

一个总体缺点是 conda 在使用大型 conda-forge 通道时变得有点慢。他们正在 努力,但与此同时 conda-forge 指数增长得非常快。

原文由 Alex 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.1k
2 个回答

问题

您列出了许多没有一种方法可能能够完全解决的问题:

  • 空间

“我需要‘大’包:numpy、pandas、scipy、matplotlib……实际上我有大约 100+ GB 的硬盘驱动器充满了 python 虚拟依赖项”

  • 时间

…在每个虚拟环境中安装所有这些需要时间

  • 出版

…这些包管理器都没有真正帮助发布和测试代码…

  • 工作流程

我很想将我当前的工作流程从 pipenv 转移到 conda。

值得庆幸的是,您所描述的并不是困扰包管理器的经典依赖问题——循环依赖、固定依赖、版本控制等。


细节

我在 Windows 上使用 conda 多年,在类似的限制下取得了合理的成功。 Conda 最初旨在使安装 scipy 相关包更容易。它仍然如此。

如果您使用的是“scipy stack”(scipy、numpy、pandas……),conda 是您最可靠的选择。

康达 可以

  • 安装 scipy 包
  • 安装 C 扩展和非 Python 包(需要运行 numpy 和其他包)
  • 集成 conda 包、conda 通道(你应该看看这个)和 pip 来访问包
  • 与虚拟环境的依赖分离

康达 不能

  • 帮助发布代码

可重现的环境

如果需要,以下步骤应该有助于重现 virtualenvs:

  • 不要使用 pip 安装 scipy 包。我会依靠 conda 来完成繁重的工作。它更快更稳定。您可以在 conda 环境中 pip 安装不太常见的包。
  • 有时,pip 包可能会与环境中的 conda 包发生冲突(请参阅解决此问题的 发行说明)。

避免 pip 问题

我想知道是否有一种方法可以让一些包,例如你在大多数项目中使用的包,全局安装……其他的东西会放在本地 virtualenv-folders

非 conda 工具

  • pipx 是一个类似 pip 的工具,可以创建全局虚拟环境。
  • virtualenv 传统上为每个项目制作虚拟环境,但幸运的是@jwodder 的回答解释了如何使用全局包。
  • virtualenv-wrapper 促进全局 virtualenvs。

康达

但是,如果您想继续使用 conda,可以尝试以下操作:

A. 将工作环境与您的基础环境分开,例如 workenv 。将此视为您的 goto, “global” env 来完成您的大部分日常工作。

 > conda create -n workenv python=3.7 numpy pandas matplotblib scipy
> activate workenv
(workenv)>

B. 在工作环境的 克隆 中测试不常见的 pip 包(或重要的 conda 包)的安装

> conda create --name testenv --clone workenv
> activate testenv
(testenv)> pip install pint

或者,使用 requirements.txt 文件创建包含最小包的新环境

C. 将依赖项备份到 requirements.txt 文件,名为 environment.yml 每个 virtualenv。 (可选)制作脚本以在每个环境中运行此命令。请参阅有关共享/创建环境文件的 文档。将来从此文件创建环境:

 > conda create --name testenv --file environment.yml
> activate testenv
(testenv)> conda list

出版

打包问题是一个持续的、独立的问题,随着 pyproject.toml 通过 PEP 518 文件的出现而受到关注(参见作者 B. Cannon 的相关 博客文章)。诸如 flitpoetry 之类的打包工具采用了这种现代惯例来进行分发并将它们发布到服务器或打包索引 (PyPI)。 pyproject.toml 概念试图摆脱传统的 setup.py 特定依赖于 setuptools 的文件。

依赖关系

pipenvpoetry 这样的工具有一种独特的现代方法来通过“锁定”文件解决依赖性问题。该文件允许您跟踪和重现依赖关系图的状态,这是迄今为止 Python 打包世界中的新事物(请在 此处 查看更多关于 Pipfile 与 setup.py 的信息)。此外,有人声称您仍然可以将这些工具与 conda 结合使用,尽管我尚未测试这些声明的范围。锁定文件尚未标准化,但根据核心开发人员 B. Canon 在关于 Python 打包的未来采访 中所说,(~33m) “我想让我们达到目标。” (见更新)。

概括

如果您正在使用 scipy 堆栈中的任何包,请使用 conda( _推荐_):

  • 为了节省空间、时间和工作流问题,请使用 conda 或 miniconda。
  • 要解决部署应用程序或对依赖项使用“锁定”文件的问题,请结合 conda 考虑以下内容:
    • pipenv :用于部署和制作 Pipfile.lock
    • poetry :用于部署和制作 poetry.lock
  • 要在 PyPI 上发布库,请考虑:
    • pipenv :通过 pipenv install -e. 开发并使用 twine 手动发布
    • flit : 自动打包和*发布
    • poetry : 自动打包 发布

也可以看看

  • 关于管理环境文件的 conda 文档
  • 播客采访 B. Cannon 讨论一般打包问题, pyproject.toml锁定文件工具
  • 播客采访 K. Reitz,讨论打包 工具pipenv vs. pip ,37m)和开发环境。

更新

原文由 pylang 发布,翻译遵循 CC BY-SA 4.0 许可协议

我想知道是否有一种方法可以让一些包,例如你在大多数项目中使用的包,全局安装……其他的东西会放在本地 virtualenv-folders

是的,virtualenv 支持这个。全局安装全局所需的包,然后,每当您创建 virtualenv 时,提供 --system-site-packages 选项,以便生成的 virtualenv 仍然能够使用全局安装的包。使用 tox 时,您可以通过在适当的 [testenv] 部分中包含 sitepackages=true 来在创建的 virtualenvs 中设置此选项。

原文由 jwodder 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题