Empêche pip d'échouer sur un seul paquet lors de l'installation avec requirements.txt

138

J'installe des packages à partir de requirements.txt

pip install -r requirements.txt

Le requirements.txtfichier lit:

Pillow
lxml
cssselect
jieba
beautifulsoup
nltk

lxmlest le seul package qui ne parvient pas à s'installer et cela conduit à tout échouer (résultats attendus comme indiqué par larsks dans les commentaires). Cependant, après lxmléchec, pipcontinue de fonctionner et télécharge le reste des packages.

D'après ce que j'ai compris, la pip install -r requirements.txtcommande échouera si l'un des packages répertoriés dans le requirements.txtfichier échoue à installer.

Y a-t-il un argument que je peux passer lors de l'exécution pip install -r requirements.txtpour lui dire d'installer ce qu'il peut et d'ignorer les paquets qu'il ne peut pas, ou de quitter dès qu'il voit quelque chose échouer?

emh
la source
3
Supprimer lxml de votre requirements.txt
RickyA
1
Merci, cela fonctionnerait dans ce cas, mais en général, y a-t-il un moyen de contourner cela? Ou est-il normal d'exécuter simplement la commande, de voir qu'elle échoue, puis d'élaguer la liste des packages?
emh
5
Si un package y est répertorié, requirements.txtil est probablement nécessaire , il est donc logique que piple package échoue si le package ne peut pas être installé. Si le code s'exécute de toute façon sans ce package, alors ce n'était guère une exigence. L'élagage aléatoire des packages ayant échoué requirements.txtsemble entraîner des problèmes avec les dépendances manquantes.
larsks
1
@larsks, il peut être très courant d'avoir plusieurs fichiers requirements.txt pour un seul environnement de développement ou package. Par exemple, il peut y avoir un plein d'outils optionnels qui peuvent être utilisés pour améliorer l'environnement de test d'unité / intégration ou le profilage des performances, mais qui ne sont pas strictement nécessaires. Vous souhaitez toujours contrôler la version d'un fichier source unique exprimant ces packages et toutes les versions épinglées, et vous appuyer sur le même pip install -r <some file>flux de travail pour standardiser la création de l'environnement approprié.
ely
4
Compte tenu de cela, il semble très sourd de suggérer que pip ne devrait pas prendre en charge un certain type d'échec gracieux / comportement de saut facultatif qui affiche un avertissement mais installe ce qu'il peut. C'est un besoin très courant pour exactement ce type d'installation basée sur pip à partir d'un fichier d'exigences.
ely

Réponses:

230

L'exécution de chaque ligne avec pip installpeut être une solution de contournement.

cat requirements.txt | xargs -n 1 pip install

Remarque: le -aparamètre n'est pas disponible sous MacOS, donc old cat est plus portable.

MZD
la source
21
pour mac:cat requirements.txt | xargs -n 1 pip install
Walty Yeung
5
Je devais faire: cat requirements.txt | cut -f1 -d"#" | sed '/^\s*$/d' | xargs -n 1 pip installsupprimer quoi que ce soit dans les commentaires et se débarrasser des lignes vides.
Narek
1
Au moins avec GNU xargs, il y a l' -aoption flag, qui permet de xargslire les arguments à partir d'un fichier, donc cela peut être fait comme xargs -n 1 -a requirements.txt pip install. Empêche UUOC et plomberie excessive
Sergiy Kolodyazhnyy
7
Pour Windows :)FOR /F %k in (requirements.txt) DO pip install %k
wcyn
Même sans le -adrapeau, pensez < requirements.txt xargs -n 1 pip install, ou si vous ne le faites pas comme la redirection à l'avant, xargs -n 1 pip install < requirements.txt. :-)
torek le
10

Cette solution gère les lignes vides, les lignes d'espacement, les # lignes de commentaire, les # lignes de commentaire dans votre requirements.txt.

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

Pointe du chapeau à cette réponse pour la magie sed.

rouble
la source
1
Fonctionne bien. J'ai utilisé à la pip freezeplace de cat requirements.txt.
Vishal
5

Pour les fenêtres:

version 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)

version 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
la source
«main» ne fait pas partie de pip. Erreur.
Pranzell
4

La xargssolution fonctionne mais peut avoir des problèmes de portabilité (BSD / GNU) et / ou être encombrante si vous avez des commentaires ou des lignes vides dans votre fichier d'exigences.

En ce qui concerne le cas d'utilisation où un tel comportement serait requis, j'utilise par exemple deux fichiers d'exigences distincts, l'un qui ne répertorie que les dépendances principales qui doivent toujours être installées et un autre fichier avec des dépendances non essentielles qui sont dans 90% des cas pas nécessaire pour la plupart des cas d'utilisation. Ce serait l'équivalent de la Recommendssection d'un paquet Debian.

J'utilise le script shell suivant (nécessite sed) pour installer les dépendances facultatives :

#!/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
Léon Cavaille
la source
0

Merci, Etienne Prothon pour les vitrines.

Mais, après la mise à niveau vers pip 18, le package pip n'expose pas main au public. Vous devrez peut-être changer de code comme celui-ci.

 # 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
la source
-1

Pour les fenêtres:

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. Créez un répertoire local et placez-y votre requirements.txtfichier.
  2. Copiez le code ci-dessus et enregistrez-le en tant que fichier python dans le même répertoire. N'oubliez pas d'utiliser l' .pyextension, par exemple,install_packages.py
  3. Exécutez ce fichier à l'aide d'un cmd: python install_packages.py
  4. Tous les packages mentionnés seront installés en une seule fois sans s'arrêter du tout. :)

Vous pouvez ajouter d'autres paramètres dans la fonction d'installation. Comme: main(['install'] + [str(package)] + ['--update'])

Pranzell
la source