Pare o pip de falhar no pacote único ao instalar com requirements.txt

138

Estou instalando pacotes de requirements.txt

pip install -r requirements.txt

O requirements.txtarquivo diz:

Pillow
lxml
cssselect
jieba
beautifulsoup
nltk

lxmlé o único pacote que falha na instalação e isso leva a que tudo falhe (resultados esperados, conforme apontado por larsks nos comentários). No entanto, a lxmlfalha após pipainda é executada e baixa o restante dos pacotes.

Pelo que entendi, o pip install -r requirements.txtcomando falhará se algum dos pacotes listados na requirements.txtfalha na instalação.

Existe algum argumento que eu possa passar ao executar pip install -r requirements.txtpara dizer para instalar o que puder e pular os pacotes que não podem ou sair assim que houver alguma falha?

emh
fonte
3
Remova o lxml do seu requirements.txt
RickyA 7/14
1
Obrigado, isso funcionaria neste caso, mas em geral, existe alguma maneira de contornar isso? Ou é normal apenas executar o comando, ver se ele falha e remover a lista de pacotes?
EMH
5
Se um pacote está listado requirements.txt, é presumivelmente necessário , portanto, faz sentido que pipfalhe se o pacote não puder ser instalado. Se o código for executado de qualquer maneira sem esse pacote, dificilmente será um requisito. Podar aleatoriamente a remoção de pacotes com falha requirements.txtparece causar problemas com dependências ausentes.
Larsks 7/03
1
@larsks, pode ser muito comum ter vários arquivos requirements.txt para um único ambiente ou pacote de desenvolvimento. Por exemplo, pode haver uma cheia de ferramentas opcionais que podem ser usadas para aprimorar o ambiente de teste de unidade / integração ou o perfil de desempenho, mas que não são estritamente necessários. Você ainda deseja controlar a versão de um único arquivo de origem que expresse esses pacotes e quaisquer versões fixadas e conte com o mesmo pip install -r <some file>fluxo de trabalho para padronizar a criação do ambiente apropriado.
Ely
4
Diante disso, parece muito surdo sugerir que o pip não deve suportar algum tipo de falha normal / comportamento de pulo opcional que imprime um aviso, mas instala o que pode. Essa é uma necessidade muito comum de exatamente esse tipo de instalação baseada em pip a partir de um arquivo de requisitos.
Ely

Respostas:

230

A execução de cada linha com pip installpode ser uma solução alternativa.

cat requirements.txt | xargs -n 1 pip install

Nota: o -aparâmetro não está disponível no MacOS, portanto, o gato antigo é mais portátil.

MZD
fonte
21
para mac:cat requirements.txt | xargs -n 1 pip install
Walty Yeung 4/16
5
Eu tinha que fazer: cat requirements.txt | cut -f1 -d"#" | sed '/^\s*$/d' | xargs -n 1 pip installremover qualquer coisa nos comentários e me livrar das linhas vazias.
Narek
1
Pelo menos com o GNU xargs, há a -aopção flag, que permite xargsler argumentos do arquivo, então isso pode ser feito como xargs -n 1 -a requirements.txt pip install. Impede UUOC e canalização excessiva
Sergiy Kolodyazhnyy
7
Para Windows :)FOR /F %k in (requirements.txt) DO pip install %k
wcyn
Mesmo sem a -abandeira, considere < requirements.txt xargs -n 1 pip installou se você não gosta do redirecionamento na frente xargs -n 1 pip install < requirements.txt,. :-)
torek 6/07
10

Esta solução lida com linhas vazias, linhas de espaço em branco, # linhas de comentário, espaço em branco e depois # linhas de comentário no seu requirements.txt.

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

Dica de chapéu para esta resposta para a magia sed.

rublo
fonte
1
Funciona bem. Eu usei em pip freezevez de cat requirements.txt.
Vishal
5

Para Windows:

versão do 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)

versão pip <18

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)
Etienne Prothon
fonte
'main' não faz parte do pip. Erro.
Pranzell 29/07/19
4

A xargssolução funciona, mas pode ter problemas de portabilidade (BSD / GNU) e / ou ser complicada se você tiver comentários ou linhas em branco no seu arquivo de requisitos.

Quanto ao caso de uso em que esse comportamento seria necessário, eu uso, por exemplo, dois arquivos de requisitos separados, um que lista apenas as dependências principais que precisam ser sempre instaladas e outro arquivo com dependências não essenciais em 90% dos casos não é necessário para a maioria dos casos de uso. Isso seria equivalente à Recommendsseção de um pacote debian.

Eu uso o seguinte script de shell (requer sed) para instalar dependências opcionais :

#!/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
Leo Cavaille
fonte
0

Obrigado, Etienne Prothon, por estojos de janelas.

Mas, após a atualização para o pip 18, o pacote pip não expõe main ao público. Portanto, você pode precisar alterar um código como este.

 # 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)
Jaeyoon Jeong
fonte
-1

Para 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()
  1. Crie um diretório local e coloque seu requirements.txtarquivo nele.
  2. Copie o código acima e salve-o como um arquivo python no mesmo diretório. Lembre-se de usar a .pyextensão, por exemplo,install_packages.py
  3. Execute este arquivo usando um cmd: python install_packages.py
  4. Todos os pacotes mencionados serão instalados de uma só vez, sem parar. :)

Você pode adicionar outros parâmetros na função de instalação. Gostar: main(['install'] + [str(package)] + ['--update'])

Pranzell
fonte