Modul zum Nachinstallieren fehlender Pythonpakete

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Code: Alles auswählen

        process = subprocess.Popen(commando, stdout=subprocess.PIPE)
        output = process.stdout.readlines()
        process.wait()
Dafür gibt es `process.communicate` (Die rote Warnung bei `process.stdout` hast du wohl übersehen), bzw. `check_call` oder `check_output`.

Zeile 4 bis 21 finde ich witzig, wieso sollte das Importieren beim zweiten Mal funktionieren?

Zeile 328, wieso fängst du `BaseException` ab und nicht `Exception`, denn `BaseException` fängt auch einen KeyboardInterrupt (aka Strg+C) ab?
the more they change the more they stay the same
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Hallo Dav1d, Danke für Deine Info! :wink:

In diesem Fall, funktioniert `process.communicate()` prima und vereinfacht hier auch den Code.

Code: Alles auswählen

outputerror = list()
def installation(paket):
    for line in install_command:
        commando = list(line)
        commando.append(paket.lstrip('-'))
        break

    counter = 0
    while counter != 4:
        counter += 1
        process = subprocess.Popen(commando)
        process.communicate()
        process.wait()
        install = process.returncode
        if install == 0:
            print ('Installation von %s war erfolgreich!\n' % paket)
            counter = 4
            return
        if counter < 4:
            print ('\nInstallationsfehler: %s, die Installation wird wiederholt!' % paket)
            time.sleep(5)
        elif counter == 4:
            outputerror.append('Es ist ein Fehler bei der Installation von aufgetreten, %s konnte nicht installiert werden!' % paket)
            return
Bei zwei anderen Funktionen, benötige ich für das Ausgabehandling 'process.stdout.readlines()'.

Zeile 4 bis 21 konnte ich noch kürzen, da 2 der Imports nicht mehr benötigt werden.
Warum ich zwei mal das Gleiche importiere. 'import pip' funktioniert nur, wenn das Paket 'pip' bzw. 'python-pip' auch installiert ist, was bei einer Python-Standardinstallation unter Debian / Ubuntu nicht der Fall ist. Daher habe ich das in eine 'try .. ecxept' gesteckt. Vielleicht gibt es da auch noch eine einfachere Lösung?

Bei Zeile 328, habe ich mir gedacht am Besten alle Fehler abzufangen. Ist das nicht von Vorteil?
Benutzeravatar
snafu
User
Beiträge: 6744
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Dav1d hat geschrieben:Dafür gibt es `process.communicate` (Die rote Warnung bei `process.stdout` hast du wohl übersehen), bzw. `check_call` oder `check_output`.
Er sagte irgendwo in diesem Thread mal, dass er die Doku nicht benutzt, weil er kein Englisch kann. Das erklärt wohl auch den Umstand, wieso er überhaupt solche Fragen stellt. ;)

Meiner bescheidenen Meinung nach sollten solche Leute ja besser die Finger vom Programmieren lassen, ebenso wie man besser kein Handwerker wird, wenn man zwei linke Hände hat. Aber da ich niemandem den Spaß verderben will (und an sich auch kein böser Mensch sein will), halte ich mich mal halbwegs zurück. :)
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

`communicate` gibt dir ein Tuple zurück welches STDOUT und STDERR-Ausgabe enthält, das ersetzt `process.stdout.readlines` und ist auch noch sicherer, des Weiteren brauchst du dann auch kein `process.wait` mehr (→ Dokumentation, wenn es stimmt was snafu gesagt hat, dass du kein Englisch kannst, dann nimm dir einen Übersetzer!)

4-21:

Code: Alles auswählen

import sys
import os
import time
import platform
import shlex
import subprocess
import imp
from subprocess import PIPE

try:
    import pip
except ImportError:
    pip = None
Dein `except BaseException` verhindert das Abbrechen deines Programms mit Strg+C, würde ein Programm das in meiner Konsole versuchen würde es ziemlich schnell fliegen (nach einem `kill` (-9)).
the more they change the more they stay the same
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

@snafu, das stimmt so nicht!
Ich versuche mich wohl durch die englischen Dokus mit einem Translater zu lesen, leider ist es oft so mit der Übersetzung, daß der Sinn dabei allzu oft auf der Strecke bleibt und man sich selbst das zusammenreimen darf ...
Du kennst mich und meine Gründe nicht, warum Dir manches fraglich vorkommt.
Es gibt immer zwei Möglichkeiten, man lässt es oder man tut es ... :wink:

@Dav1d, das mit dem Englisch stimmt schon, Problem ist den Sinn bei solchen Übersetzungen richtig zu erkennen und das ist oft nicht so einfach. :wink:
Danke für Deine Info zu 'communicate' und dem Import-Vorschlag der besser und verständlicher aussieht.
Bei 'communicate' stört mich eins, daß ich die Ausgabe nicht an eine Variable übergeben kann und dies dann zu einem späteren Zeitpunkt abrufen kann. Wenn ich 'process.communicate()' aufrufe, erfolgt auch umgehend die Ausgabe und das ist vielleicht nicht immer erwünscht. Vielleicht gibt es auch dafür eine Lösung, die ist mir aber noch nicht bekannt, deshalb verwende ich noch bei zwei Funktionen eben `process.stdout.readlines`. Siehe Zeile 105 - 114 und 117 - 134 im aktuellen Link.

Hier die aktuelle modul_control.py: https://gist.github.com/3111763
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

@Dav1d, vergiss was ich über die Notwendigkeit über `process.stdout.readlines` geschrieben habe.
Habe nochmals die Doku durchgearbeitet und an 'check_call, check_output' gedacht was Du vor zwei Posts mir angeraten hast. Mit 'check_output' konnte ich auch dieses Problem lösen und der Code ist dabei noch viel einfacher geworden! :)
Mit dem Translater, wäre ich darauf nicht gekommen, aber dank der selbsterklärenden Beispiele!
Siehe Zeile 105 - 111 und 116 - 128.

Aktuelle modul_control.py: https://gist.github.com/3112039
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Diese Beispiel sollte dir zeigen wie `communicate` wirklich funktioniert:

Code: Alles auswählen

p = Popen([…], stderr=PIPE, stdout=PIPE)
stdout, stderr = p.communicate()
print stdout, stderr
print p.returncode
the more they change the more they stay the same
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Danke für das Beispiel!
Habe es getestet, verhält sich so, wie in meinem Modul.

Da ja Python3 auch in der nächsten Ubuntu-Version Standard sein wird, habe ich noch ein paar kleine Änderungen vorgenommen, so daß es auf Python 2.7 und auch auf Python 3 läuft.

https://gist.github.com/3116344

Zukünftig werde ich mich mit Python3 beschäftigen.
Antworten