如何在 conda 中限制包版本?
How to constrain package versions in conda?
我在预装了一堆包的 conda 环境中工作(conda 列表有 360 个包,很多 ML 工具和一些 bioconda)。我有时需要添加一个包;但是,我发现 conda install newpackage
通常非常慢(在“解决环境”中花费数小时或数天),如果它完成了,它通常会建议更新我真的不想接触的包。
我想固定一些核心包(python、numpy、scipy 等)的当前版本,以便 conda 甚至认为修改它们是不可能的。这既是为了速度,也是为了避免任何无意的更新。如果这意味着无法安装我想尝试添加的某个包,那没关系!我宁愿有一个像“newpackage 与你的 numpy 版本冲突”这样的快速回答,也不愿没有答案。然后我可以决定是否要忽略冲突;为这个包创建一个简单的环境; conda 在本地构建,或其他任何构建。
我该怎么做?
另请参阅:https://www.anaconda.com/blog/understanding-and-improving-condas-performance(未解决问题)
包固定
包可以在 per-environment 的基础上固定到特定版本。参见 the documentation on package pinning。例如,假设我们想要将 numpy
和 scipy
固定到我们当前在名为 foo
的环境中拥有的确切版本。我们可以处理 conda list
的输出以匹配 Conda 固定规范的预期语法:
conda activate foo
conda list "^(numpy|scipy)$" | tail -n+4 | awk '{ print " ==" }' > $CONDA_PREFIX/conda-meta/pinned
这里有几点需要注意:
conda list
采用正则表达式:利用它对您有利
tail
只是跳过 header
- 这取决于在激活的环境中定义
$CONDA_PREFIX
- 这会覆盖任何现有的
pinned
文件
冻结安装
保持一切不变的劳动强度较低的方法是使用 --freeze-installed
标志。然而,在最新版本的 Conda 中,这在第一轮求解中默认使用。所以实际上这个标志现在所做的就是跳过第二轮解决方案,允许更新不属于明确规范的包。
PyPI 包
Pip 安装的 PyPI 包需要一些额外的配置才能让 Conda 固定它们。具体来说,需要在 envs/<env>/conda-meta/pinned
文件中使用以下语法:
numpy=1.21.4=pypi*
即表明pypi
应该在构建字符串中。为了尊重这一点,必须启用 Pip 互操作性并允许灵活的通道优先级:
## settings only for this environment
conda activate foo
conda config --env --set pip_interop_enabled True
conda config --env --set channel_priority flexible
启用它会告诉 Conda 将 PyPI 包视为解决依赖关系的有效替代品。
就个人而言,我会小心使用它,因为 Conda 是一个通用的包管理器,有时通过 Pip 安装的包(例如 yaml
或 wget
)与 Conda 包不对应一样的名字。因此,为什么我在示例中使用 --env
仅在 within foo 环境中启用此配置设置。
我在预装了一堆包的 conda 环境中工作(conda 列表有 360 个包,很多 ML 工具和一些 bioconda)。我有时需要添加一个包;但是,我发现 conda install newpackage
通常非常慢(在“解决环境”中花费数小时或数天),如果它完成了,它通常会建议更新我真的不想接触的包。
我想固定一些核心包(python、numpy、scipy 等)的当前版本,以便 conda 甚至认为修改它们是不可能的。这既是为了速度,也是为了避免任何无意的更新。如果这意味着无法安装我想尝试添加的某个包,那没关系!我宁愿有一个像“newpackage 与你的 numpy 版本冲突”这样的快速回答,也不愿没有答案。然后我可以决定是否要忽略冲突;为这个包创建一个简单的环境; conda 在本地构建,或其他任何构建。
我该怎么做?
另请参阅:https://www.anaconda.com/blog/understanding-and-improving-condas-performance(未解决问题)
包固定
包可以在 per-environment 的基础上固定到特定版本。参见 the documentation on package pinning。例如,假设我们想要将 numpy
和 scipy
固定到我们当前在名为 foo
的环境中拥有的确切版本。我们可以处理 conda list
的输出以匹配 Conda 固定规范的预期语法:
conda activate foo
conda list "^(numpy|scipy)$" | tail -n+4 | awk '{ print " ==" }' > $CONDA_PREFIX/conda-meta/pinned
这里有几点需要注意:
conda list
采用正则表达式:利用它对您有利tail
只是跳过 header- 这取决于在激活的环境中定义
$CONDA_PREFIX
- 这会覆盖任何现有的
pinned
文件
冻结安装
保持一切不变的劳动强度较低的方法是使用 --freeze-installed
标志。然而,在最新版本的 Conda 中,这在第一轮求解中默认使用。所以实际上这个标志现在所做的就是跳过第二轮解决方案,允许更新不属于明确规范的包。
PyPI 包
Pip 安装的 PyPI 包需要一些额外的配置才能让 Conda 固定它们。具体来说,需要在 envs/<env>/conda-meta/pinned
文件中使用以下语法:
numpy=1.21.4=pypi*
即表明pypi
应该在构建字符串中。为了尊重这一点,必须启用 Pip 互操作性并允许灵活的通道优先级:
## settings only for this environment
conda activate foo
conda config --env --set pip_interop_enabled True
conda config --env --set channel_priority flexible
启用它会告诉 Conda 将 PyPI 包视为解决依赖关系的有效替代品。
就个人而言,我会小心使用它,因为 Conda 是一个通用的包管理器,有时通过 Pip 安装的包(例如 yaml
或 wget
)与 Conda 包不对应一样的名字。因此,为什么我在示例中使用 --env
仅在 within foo 环境中启用此配置设置。