使用 requirements.txt 安装时,阻止 pip 在单个包上失败

Posted

技术标签:

【中文标题】使用 requirements.txt 安装时,阻止 pip 在单个包上失败【英文标题】:Stop pip from failing on single package when installing with requirements.txt 【发布时间】:2014-04-10 14:57:51 【问题描述】:

我正在从requirements.txt 安装软件包

pip install -r requirements.txt

requirements.txt 文件内容如下:

Pillow
lxml
cssselect
jieba
beautifulsoup
nltk

lxml 是唯一无法安装的软件包,这会导致一切都失败(正如 larsks 在 cmets 中指出的预期结果)。但是,lxml 失败后,pip 仍然运行并下载其余的包。

据我了解,如果requirements.txt 中列出的任何软件包安装失败,pip install -r requirements.txt 命令将失败。

在运行pip install -r requirements.txt 时,我是否可以传递任何参数来告诉它安装它可以安装的内容并跳过它不能安装的软件包,或者在它看到失败时立即退出?

【问题讨论】:

从你的 requirements.txt 中删除 lxml 谢谢,这在这种情况下会起作用,但总的来说,有什么办法可以解决这个问题吗?还是只是运行命令,看到它失败然后修剪包列表是正常的? 如果包在requirements.txt 中列出,它可能是必需的,因此如果无法安装包,pip 将失败是有道理的。如果代码在没有该包的情况下仍然运行,那么它几乎不是必需的。从requirements.txt 随机修剪失败的包似乎只会导致缺少依赖项的问题。 @larsks 对于单个开发环境或包,拥有多个 requirements.txt 文件是很常见的。例如,可能有一个完整的可选工具可用于增强单元/集成测试环境或性能分析,但并非严格要求。您仍然希望对表示这些包和任何固定版本的单个源文件进行版本控制,并依赖相同的pip install -r <some file> 工作流来标准化相应环境的创建。 鉴于此,建议 pip 不应该支持某种类型的优雅失败/可选的跳过行为,它会打印警告但安装它可以安装的东西,这似乎是非常聋的。这正是从需求文件中进行这种基于 pip 的安装的常见需求。 【参考方案1】:

在@MZD 的答案的基础上,这里有一个过滤掉所有以注释符号#开头的文本的解决方案

cat requirements.txt | grep -Eo '(^[^#]+)' | xargs -n 1 pip install

【讨论】:

【参考方案2】:

一行 PowerShell:

Get-Content .\requirements.txt | ForEach-Object pip install $_

如果你需要忽略某些行,那么:

Get-Content .\requirements.txt | ForEach-Object if (!$_.startswith("#"))pip install $_

Get-Content .\requirements.txt | ForEach-Object if ($_ -notmatch "#")pip install $_

【讨论】:

【参考方案3】:

对于使用 PowerShell 的 Windows:

foreach($line in Get-Content requirements.txt) 
    if(!($line.StartsWith('#')))
        pip install $line
    

【讨论】:

【参考方案4】:

对于 windows 用户,你可以使用这个:

FOR /F %k in (requirements.txt) DO ( if NOT # == %k ( pip install %k ) )

逻辑:对于文件(requirements.txt)中的每个依赖项,安装它们并忽略以“#”开头的那些。

【讨论】:

【参考方案5】:

对于 Windows:

import os
from pip.__main__ import _main as main

error_log = open('error_log.txt', 'w')

def install(package):
    try:
        main(['install'] + [str(package)])
    except Exception as e:
        error_log.write(str(e))

if __name__ == '__main__':
    f = open('requirements1.txt', 'r')
    for line in f:
        install(line)
    f.close()
    error_log.close()
    创建一个本地目录,并将您的requirements.txt 文件放入其中。 复制上面的代码,将其作为python文件保存在同一目录下。记得使用.py 扩展名,例如install_packages.py 使用 cmd 运行此文件:python install_packages.py 提到的所有软件包都将一次性安装,而不会停止。 :)

您可以在安装功能中添加其他参数。喜欢: main(['install'] + [str(package)] + ['--update'])

【讨论】:

【参考方案6】:

对于 Windows:

pip 版本 >=18

import sys
from pip._internal import main as pip_main

def install(package):
    pip_main(['install', package])

if __name__ == '__main__':
    with open(sys.argv[1]) as f:
        for line in f:
            install(line)

pip 版本
import sys
import pip

def install(package):
    pip.main(['install', package])

if __name__ == '__main__':
    with open(sys.argv[1]) as f:
        for line in f:
            install(line)

【讨论】:

'main' 不是 pip 的一部分。错误。【参考方案7】:

此解决方案在您的 requirements.txt 中处理空行、空白行、# 注释行、空白-然后-# 注释行。

cat requirements.txt | sed -e '/^\s*#.*$/d' -e '/^\s*$/d' | xargs -n 1 pip install

感谢answer 的 sed 魔法。

【讨论】:

效果很好。我使用pip freeze 而不是cat requirements.txt 这不会在声明要求的同一行处理 cmets。为此,您需要将 -e 's/\s*#.*$//' 添加到 sed 命令中。 我得到以下信息:'cat' 不是内部或外部命令、可运行程序或批处理文件。【参考方案8】:

感谢 Etienne Prothon 提供 windows 机箱。

但是,升级到 pip 18 后,pip 包不会向公众公开 main。因此,您可能需要像这样更改代码。

 # This code install line by line a list of pip package 
 import sys
 from pip._internal import main as pip_main

 def install(package):
    pip_main(['install', package])

 if __name__ == '__main__':
    with open(sys.argv[1]) as f:
        for line in f:
            install(line)

【讨论】:

【参考方案9】:

使用pip install 运行每一行可能是一种解决方法。

cat requirements.txt | xargs -n 1 pip install

注意:-a参数在MacOS下不可用,所以老猫更便携。

【讨论】:

Mac 版:cat requirements.txt | xargs -n 1 pip install 我必须这样做:cat requirements.txt | cut -f1 -d"#" | sed '/^\s*$/d' | xargs -n 1 pip install 删除 cmets 中的任何内容并删除空行。 至少对于 GNU xargs,有 -a 标志选项,它允许 xargs 从文件中读取参数,所以这可以作为 xargs -n 1 -a requirements.txt pip install 完成。防止UUOC 和过多的管道 对于 Windows :) FOR /F %k in (requirements.txt) DO pip install %k 即使没有-a 标志,考虑< requirements.txt xargs -n 1 pip install,或者如果你不喜欢前面的重定向,xargs -n 1 pip install < requirements.txt。 :-)【参考方案10】:

xargs 解决方案有效,但可能存在可移植性问题 (BSD/GNU) 和/或如果您的需求文件中有 cmets 或空行,则可能会很麻烦。

至于需要这种行为的用例,我使用例如两个单独的需求文件,一个只列出需要始终安装的核心依赖项,另一个文件包含 90% 的非核心依赖项大多数用例不需要的情况。这相当于 debian 包的 Recommends 部分。

我使用以下shell脚本(需要sed)来安装可选依赖项

#!/bin/sh

while read dependency; do
    dependency_stripped="$(echo "$dependency" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
    # Skip comments
    if [[ $dependency_stripped == \#* ]]; then
        continue
    # Skip blank lines
    elif [ -z "$dependency_stripped" ]; then
        continue
    else
        if pip install "$dependency_stripped"; then
            echo "$dependency_stripped is installed"
        else
            echo "Could not install $dependency_stripped, skipping"
        fi
    fi
done < recommends.txt

【讨论】:

以上是关于使用 requirements.txt 安装时,阻止 pip 在单个包上失败的主要内容,如果未能解决你的问题,请参考以下文章

Bash脚本到Conda使用PIP后续安装requirements.txt

Django:安装 requirements.txt 时出现 distutils 错误

如何自动生成和安装requirements.txt依赖

转载如何自动生成和安装requirements.txt依赖

conda 创建虚拟环境——安装requirements.txt依赖

Python使用requirements.txt安装类库