Zatrzymaj pip przed awarią na pojedynczym pakiecie podczas instalacji przy użyciu Requirements.txt

151

Instaluję pakiety z requirements.txt

pip install -r requirements.txt

requirements.txtPlik brzmi:

Pillow
lxml
cssselect
jieba
beautifulsoup
nltk

lxmljest jedynym pakietem, którego nie można zainstalować, a to prowadzi do awarii wszystkiego (oczekiwane wyniki, jak wskazał larsks w komentarzach). Jednak po lxmlawarii pipnadal działa i pobiera resztę pakietów.

Z tego, co rozumiem, pip install -r requirements.txtpolecenie zakończy się niepowodzeniem, jeśli którykolwiek z pakietów wymienionych w requirements.txtnie zostanie zainstalowany.

Czy jest jakiś argument, który mogę przekazać podczas uruchamiania, pip install -r requirements.txtaby nakazać mu zainstalowanie tego, co może i pominąć pakiety, których nie może, lub zakończyć, gdy tylko zobaczy, że coś się nie powiedzie?

emh
źródło
3
Usuń lxml z Twoich
wymagań.txt
1
Dzięki, to by zadziałało w tym przypadku, ale czy ogólnie można to obejść? A może to normalne, że wystarczy uruchomić polecenie, zobaczyć, że się nie powiedzie, a następnie wyczyścić listę pakietów?
emh
5
Jeśli pakiet jest wymieniony na liście requirements.txt, jest prawdopodobnie wymagany , więc ma sens, że pipnie powiedzie się, jeśli pakiet nie może zostać zainstalowany. Jeśli kod i tak działa bez tego pakietu, to nie był to wymóg. requirements.txtWydaje się, że losowe usuwanie nieudanych pakietów z programu spowoduje problemy z brakującymi zależnościami.
larsks
1
@larsks bardzo często może być wiele plików Require.txt dla jednego środowiska programistycznego lub pakietu. Na przykład może istnieć jedno pełne narzędzi opcjonalnych, które można wykorzystać do ulepszenia środowiska testowego jednostki / integracji lub profilowania wydajności, ale które nie są ściśle wymagane. Nadal chcesz mieć kontrolę nad wersjami pojedynczego pliku źródłowego zawierającego te pakiety i wszelkie przypięte wersje, i polegać na tym samym pip install -r <some file>przepływie pracy, aby ustandaryzować tworzenie odpowiedniego środowiska.
ely
4
Biorąc to pod uwagę, wydaje się bardzo głuche sugerowanie, że pip nie powinien obsługiwać jakiegoś rodzaju wdzięcznego błędu / opcjonalnego zachowania pomijania, które drukuje ostrzeżenie, ale instaluje to, co może. Jest to bardzo częsta potrzeba dokładnie tego typu instalacji opartej na potoku z pliku wymagań.
ely

Odpowiedzi:

246

Uruchomienie każdego wiersza z pip installmoże być obejściem.

cat requirements.txt | xargs -n 1 pip install

Uwaga: -aparametr nie jest dostępny pod MacOS, więc stary kot jest bardziej przenośny.

MZD
źródło
21
dla mac:cat requirements.txt | xargs -n 1 pip install
Walty Yeung,
5
Musiałem zrobić: cat requirements.txt | cut -f1 -d"#" | sed '/^\s*$/d' | xargs -n 1 pip installusunąć cokolwiek z komentarzy i pozbyć się pustych wierszy.
Narek
1
Przynajmniej w przypadku GNU xargsjest -aopcja flagi, która pozwala na xargsodczyt argumentów z pliku, więc można to zrobić jako xargs -n 1 -a requirements.txt pip install. Zapobiega UUOC i nadmiernej hydraulice
Sergiy Kolodyazhnyy
8
Do okien :)FOR /F %k in (requirements.txt) DO pip install %k
wcyn
Nawet bez -aflagi, należy rozważyć < requirements.txt xargs -n 1 pip install, czy jeśli nie podoba ci się przekierowaniem na froncie, xargs -n 1 pip install < requirements.txt. :-)
torek
10

To rozwiązanie obsługuje puste wiersze, białe znaki, # wiersze komentarza, białe znaki-to- # wiersze komentarza w twoim Requirements.txt.

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

Cynk kapelusza do tej odpowiedzi na magię seda.

rubel
źródło
1
Działa ładnie. Użyłem pip freezezamiast cat requirements.txt.
Vishal
5

Dla Windowsa:

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

wersja 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
źródło
„main” nie jest częścią pip. Błąd.
Pranzell
4

Te xargsprace rozwiązanie, ale może mieć problemy Przenośność (BSD / GNU) i / lub być uciążliwe, jeśli masz uwagi lub puste wiersze w pliku wymagań.

Jeśli chodzi o przypadek użycia, w którym takie zachowanie byłoby wymagane, używam na przykład dwóch oddzielnych plików wymagań, jednego, który zawiera tylko podstawowe zależności, które muszą być zawsze instalowane, a drugi plik z zależnościami innymi niż podstawowe, które występują w 90% przypadków nie jest potrzebne w większości zastosowań. Byłby to odpowiednik Recommendssekcji pakietu Debiana.

Używam następującego skryptu powłoki (wymaga sed), aby zainstalować opcjonalne zależności :

#!/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
źródło
0

Dzięki, Etienne Prothon za obudowy Windows.

Ale po aktualizacji do pip 18, pakiet pip nie ujawnia main publicznie. Być może będziesz musiał zmienić kod w ten sposób.

 # 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
źródło
-1

Dla Windowsa:

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. Utwórz katalog lokalny i umieść requirements.txtw nim swój plik.
  2. Skopiuj powyższy kod i zapisz go jako plik Pythona w tym samym katalogu. Pamiętaj o używaniu .pyrozszerzenia, na przykładinstall_packages.py
  3. Uruchom ten plik za pomocą cmd: python install_packages.py
  4. Wszystkie wymienione pakiety zostaną zainstalowane za jednym razem, bez zatrzymywania się. :)

Możesz dodać inne parametry w funkcji instalacji. Lubić: main(['install'] + [str(package)] + ['--update'])

Pranzell
źródło