Evite que el pip falle en un paquete único cuando se instale con require.txt

138

Estoy instalando paquetes de requirements.txt

pip install -r requirements.txt

El requirements.txtarchivo lee:

Pillow
lxml
cssselect
jieba
beautifulsoup
nltk

lxmles el único paquete que no se instala y esto lleva a que todo falle (resultados esperados como lo señalan los larsks en los comentarios). Sin embargo, después de lxmlfallas pipaún se ejecuta y descarga el resto de los paquetes.

Por lo que entiendo, el pip install -r requirements.txtcomando fallará si alguno de los paquetes enumerados en la requirements.txtfalla no se instala.

¿Hay algún argumento que pueda pasar al ejecutar pip install -r requirements.txtpara decirle que instale lo que pueda y omita los paquetes que no puede, o que salga tan pronto como vea que algo falla?

emh
fuente
3
Elimine lxml de sus requerimientos.txt
RickyA
1
Gracias, eso funcionaría en este caso, pero en general, ¿hay alguna forma de evitar esto? ¿O es normal simplemente ejecutar el comando, ver si falla y luego podar la lista de paquetes?
emh
55
Si un paquete aparece en la lista requirements.txt, presumiblemente es obligatorio , por lo que tiene sentido que pipfalle si el paquete no se puede instalar. Si el código se ejecuta de todos modos sin ese paquete, entonces no era un requisito. La poda aleatoria de paquetes fallidos requirements.txtparece que solo va a causar problemas con las dependencias faltantes.
Larsks
1
@larsks puede ser muy común tener múltiples archivos require.txt para un solo entorno o paquete de desarrollo. Por ejemplo, puede haber una herramienta llena de herramientas opcionales que se pueden utilizar para mejorar el entorno de prueba de unidad / integración o el perfil de rendimiento, pero que no son estrictamente necesarios. Aún desea controlar la versión de un único archivo fuente que exprese estos paquetes y cualquier versión anclada, y confiar en el mismo pip install -r <some file>flujo de trabajo para estandarizar la creación del entorno apropiado.
ely
44
Dado esto, parece muy sordo sugerir que pip no debería admitir algún tipo de falla graciosa / comportamiento de omisión opcional que imprime una advertencia pero instala lo que puede. Esa es una necesidad muy común para exactamente este tipo de instalación basada en pip desde un archivo de requisitos.
ely

Respuestas:

230

Ejecutar cada línea con pip installpuede ser una solución alternativa.

cat requirements.txt | xargs -n 1 pip install

Nota: el -aparámetro no está disponible en MacOS, por lo que el gato viejo es más portátil.

MZD
fuente
21
para mac:cat requirements.txt | xargs -n 1 pip install
Walty Yeung
55
Tenía que hacer: cat requirements.txt | cut -f1 -d"#" | sed '/^\s*$/d' | xargs -n 1 pip installeliminar cualquier cosa en los comentarios y deshacerme de las líneas vacías.
Narek
1
Al menos con GNU xargs, hay una -aopción de marca, que permite xargsleer argumentos del archivo, por lo que esto se puede hacer como xargs -n 1 -a requirements.txt pip install. Previene UUOC y plomería excesiva
Sergiy Kolodyazhnyy
77
Para windows :)FOR /F %k in (requirements.txt) DO pip install %k
wcyn
Incluso sin la -abandera, considere < requirements.txt xargs -n 1 pip install, o si no le gusta la redirección en el frente xargs -n 1 pip install < requirements.txt,. :-)
torek
10

Esta solución maneja líneas vacías, líneas de espacios en blanco, # líneas de comentarios, espacios en blanco y luego # líneas de comentarios en su require.txt.

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

Sombrero de punta a esta respuesta para la magia sed.

rublo
fuente
1
Funciona bien Solía ​​en pip freezelugar de cat requirements.txt.
Vishal
5

Para ventanas:

versión 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)

versión 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
fuente
'main' no es parte de pip. Error.
Pranzell
4

La xargssolución funciona pero puede tener problemas de portabilidad (BSD / GNU) y / o ser engorrosa si tiene comentarios o líneas en blanco en su archivo de requisitos.

En cuanto al caso de uso donde se requeriría tal comportamiento, utilizo, por ejemplo, dos archivos de requisitos separados, uno que solo enumera las dependencias centrales que deben instalarse siempre y otro archivo con dependencias no centrales que se encuentran en el 90% de los casos no es necesario para la mayoría de los casos de uso. Eso sería un equivalente de la Recommendssección de un paquete debian.

Utilizo el siguiente script de shell (requiere sed) para instalar dependencias opcionales :

#!/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
fuente
0

Gracias, Etienne Prothon por las vitrinas.

Pero, después de actualizar a pip 18, el paquete pip no expone main al público. Por lo tanto, es posible que deba cambiar un 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
fuente
-1

Para ventanas:

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. Cree un directorio local y coloque su requirements.txtarchivo en él.
  2. Copie el código anterior y guárdelo como un archivo python en el mismo directorio. Recuerde usar la .pyextensión, por ejemplo,install_packages.py
  3. Ejecute este archivo usando un cmd: python install_packages.py
  4. Todos los paquetes mencionados se instalarán de una vez sin detenerse en absoluto. :)

Puede agregar otros parámetros en la función de instalación. Me gusta: main(['install'] + [str(package)] + ['--update'])

Pranzell
fuente