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.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Leonidas wollte damit nicht ausdrücken, dass du das Modul in mehrere untereilen sollst, sondern dass der Code zu großen Teilen unterirdisch ist. Viele Dinge wurden ja schon genannt, auch in mindestens einem anderen Thread, die Hinweise scheinst du aber oft einfach zu ignorieren. Daher spar ich mir die Kommentare zu deinem Code.
Das Leben ist wie ein Tennisball.
Nobuddy
User
Beiträge: 996
Registriert: Montag 30. Januar 2012, 16:38

@EyDu, ich ignoriere bestimmt nicht mit Absicht!
Benötige in manchen Dingen einfach mehr Zeit, bis mir das klar geworden ist.
Das hat wiederum nichts etwa mit mangelnder Intelligenz zu tun, sondern hat einen anderen Grund, den ich aber hier nicht weiter erörtern möchte. Sollte es Dich persönlich interessieren, schreibe mir eine Nachricht. :wink:

Wie dem Einen und Anderen von Euch bekannt ist, hapert es ja mit meinem Englisch, deshalb ist es oft auch schwierig für mich englische Texte richtig zu verstehen (trotz Translater).
Jetzt bin ich hier http://wiki.python-forum.de/PEP%208%20% ... setzung%29 auf die deutsche Übersetzung von PEP8 gestoßen. Diese habe ich schon des öfteren unter die Nase gerieben bekommen und werde diese Gelegenheit nutzen, mir PEP8 durchzulesen. :D
Nobuddy
User
Beiträge: 996
Registriert: Montag 30. Januar 2012, 16:38

Hallo Leonidas,
habe Deinen letzten Post durchgearbeitet und entsprechende Änderungen vorgenommen, allerdings konnte ich Deinen Einwand gegen shlex noch nicht lösen. Ich poste hier mal den Code, in dem shlex enthalten ist.

Code: Alles auswählen

# Funktion zur Überprüfung
# ob ausgewähltes Paket schon installiert ist.
def installcheck(paket):
    # Überprüfe ob Paket nicht installiert ist.
    install_test = 'apt-cache policy %s' % paket
    args = shlex.split(install_test)
    process = subprocess.Popen(args, shell=False, stdout=subprocess.PIPE)
    process.wait()
    output = process.stdout.readlines()
    global installinfo
    if output:
        for installinfo in output:
            if 'Installiert:' in installinfo and not 'Installiert: (keine)' in installinfo:
                print ('\nPaket %s ist installiert!\nÜberprüfen Sie bitte Ihr Modul auf Fehler!\n' % (paket, paket))
            else:
                return installinfo
    else:
        installinfo = False
Ich habe dies versucht:

Code: Alles auswählen

    args = 'apt-cache policy %s' % paket
    process = subprocess.Popen(args, shell=False, stdout=subprocess.PIPE)
Leider funktioniert dies so nicht. Was mache ich da falsch?

Ich poste hier mal den aktuellen Code, damit Ihr meine Fortschritte überprüfen könnt. http://www.python-forum.de/viewtopic.ph ... 1&start=45
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Du solltest ``Popen`` auch keine Strings übergeben, sondern eine Liste, dann ist der Code auch gleich sauberer:

Code: Alles auswählen

process = subprocess.Popen(['apt-cache', 'policy', paket], stdout=subprocess.PIPE)
Kein ``shlex``, kein String-Formatting. Der Standardwert von ``shell`` ist sowieso ``False``, daher braucht man das *auch* nicht anzugeben.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

btw. es gibt auch das Python Modul apt, mit den man direkt in den Paketverwaltungsdaten wühlen kann.
Kurze such ergibt:
http://apt.alioth.debian.org/python-apt-doc/index.html
http://stackoverflow.com/questions/tagg ... sort=votes

Ich selbst habe es vor einiger Zeit auf einer anderen Baustelle genutzt:
https://github.com/jedie/autoaptitude/b ... agelist.py

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Nobuddy
User
Beiträge: 996
Registriert: Montag 30. Januar 2012, 16:38

Ja, das

Code: Alles auswählen

process = subprocess.Popen(['apt-cache', 'policy', paket], stdout=subprocess.PIPE)
funktioniert, habe dies vorhin getestet.
Also keine Strings sondern eine Liste, bei obigem Beispiel kein Problem.
Beim installieren von Paketen, wo 'apt-get, aptitude und pip' ins Spiel kommen, muß ich da für jeden Befehl eine eigene subprocess-Zeile erstellen?
Den Installationsbefehl, erhalte ich aus dem Modul command(e_name), das zu installierende Paket von dem Modul noname(e_name).
Ich glaube im Moment stehe ich auf der Leitung ... :wink:

PS: Nachtrag, denke daß ich das gelöst bekomme!
Nobuddy
User
Beiträge: 996
Registriert: Montag 30. Januar 2012, 16:38

Ok, dies z.B.

Code: Alles auswählen

APT_GET = 'sudo', 'apt-get', 'install', '-y'
gebe ich mit der globalen Variable 'install_command' weiter und mache daraus

Code: Alles auswählen

commando = install_command[0], install_command[1], install_command[2], install_command[3], paket.lstrip('-')
das dann in

Code: Alles auswählen

process = subprocess.Popen(commando, stdout=subprocess.PIPE)
problemlos verarbeitet wird. :)

Das ist jetzt nichts Endgültiges!
Ich überlege, wie ich die Zeile mit 'commando = ...' optimieren kann, weil ja vielleicht nicht jeder Installationsbefehl wie hier 4 Wörter hat, wie mit 'pid install' z.B.?
Habe mal gesehen, daß man dies mit ''{} ...'.format(....)'' lösen kann, komme aber da nicht drauf. Ich weiß nur, daß 'len(install_command)' hier zur Lösung beiträgt ... ?
Weiß da jemand von Euch, was ich meine?
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Code: Alles auswählen

>>> mylist = ["foo", "bar"]
>>> mylist + ["baz"]
['foo', 'bar', 'baz']
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Wobei mylist.append("baz") normaler ist ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Nobuddy
User
Beiträge: 996
Registriert: Montag 30. Januar 2012, 16:38

jens hat geschrieben:Wobei mylist.append("baz") normaler ist ;)
Dies funktioniert auch bei mir, das Andere hat es nicht!
Danke auch für die Links aus Deinem vorhergehenden Post, dafür muß ich mir allerdings etwas Zeit nehmen, da meine Englischkenntnisse ....

Hier mal eine ganz kurze Zusammenfassung:

Code: Alles auswählen

APT_GET = 'sudo', 'apt-get', 'install', '-y'
install_command = APT_GET
commando = list(install_command)
commando.append(paket.lstrip('-'))
print (commando)
Beispielergebnis:

Code: Alles auswählen

['sudo', 'apt-get', 'install', '-y', 'python-pip']
Was mich noch beschäftigt, ist ein Rückgabewert der Installation (Fehler oder installiert).

Code: Alles auswählen

def installation(paket):
    commando = list(install_command)
    commando.append(paket.lstrip('-'))

    global outputerror
    outputerror = ''
    counter = 0
    while outputerror == '':
        counter += 1
        try:
            process = subprocess.Popen(commando, stdout=subprocess.PIPE)
            process.wait()
            output = process.stdout.readlines()
            if output:
                for line in output:
                    print (line)
                time.sleep(5)
                outputerror = False
                return
        except BaseException, e:
            if counter < 4:
                print ('\nInstallationsfehler: %s, die Installation wird wiederholt!' %e)
            elif counter == 4:
                print ('\nEs ist ein Fehler bei der Installation von aufgetreten, \n%s konnte nicht installiert werden!\n' % paket)
                return
Habt Ihr da vielleicht eine Idee?
Nobuddy
User
Beiträge: 996
Registriert: Montag 30. Januar 2012, 16:38

Bin auf dies gekommen, die Exception habe ich weggelassen, wird nicht benötigt.

Code: Alles auswählen

def installation(paket):
    commando = list(install_command)
    commando.append(paket.lstrip('-'))

    global outputerror
    outputerror = ''
    counter = 0
    while outputerror == '':
        counter += 1
        process = subprocess.Popen(commando, stdout=subprocess.PIPE)
        process.wait()
        output = process.stdout.readlines()
        if output:
            for line in output:
                print (line)
                if paket in line and 'wird eingerichtet ...' in line:
                    time.sleep(3)
                    outputerror = False
                    return
        if counter < 4:
            print ('\nInstallationsfehler: %s, die Installation wird wiederholt!' %e)
        elif counter == 4:
            print ('\nEs ist ein Fehler bei der Installation von aufgetreten, \n%s konnte nicht installiert werden!\n' % paket)
            return
Wenn etwas am Code nicht ok ist, würde ich mich über eine Info freuen!
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Das `global` ist kaputt.
the more they change the more they stay the same
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

snafu hat geschrieben:>>> mylist + ["baz"]
Du meinst wohl mylist += ["baz"] gemeint.
Nobuddy hat geschrieben:

Code: Alles auswählen

APT_GET = 'sudo', 'apt-get', 'install', '-y'
install_command = APT_GET
commando = list(install_command)
commando.append(paket.lstrip('-'))
print (commando)
Das ist aber recht umständlich.

Einfacher:

Code: Alles auswählen

APT_GET = ['sudo', 'apt-get', 'install', '-y']
commando = APT_GET[:] # Kopie der liste
commando.append(paket.lstrip('-'))
print (commando)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ich habe es genau so gemeint, wie ich es geschrieben habe. Das "Addieren" zu einer Liste führt als Ergebnis zu einer neuen Liste mit dem hinzugefügten Element. Das ist quasi ein ``mylist = alist[:]; mylist.append(item)`` in einem Schritt und kann, wenn man die neue Liste danach eh wegschmeißen würde, IMHO durchaus sinnvoll sein.

Oder von mir aus auch:

Code: Alles auswählen

kommando = APT_GET + paket.lstrip('-')
Nobuddy
User
Beiträge: 996
Registriert: Montag 30. Januar 2012, 16:38

@Dav1d, warum ist global kaputt?

@jens, den Code was ich zusammen gepostet habe, ist in unterschiedlichen Funktionen enthalten. Ich habe 3 Installationsbefehle zur Auswahl, daher übergebe ich als Erstes den ausgewählten Befehl an 'install_command'. 'APT_GET[:]' ist auch eine Alternative, aber 'list(APT_GET)' geht doch auch, oder soll man dies so nicht verwenden?

Was mich momentan beschäftigt, ist das 'process.wait()'.
Wird hier so lange gewartet, bis der Prozess positiv abgeschlossen ist?
Ich habe da beobachtet, daß wenn die Installation aus einem Grund fehlerhaft war, dies so lange geht bis die Installation erfolgreich war. Wenn das so ist (wäre), würden meine 2 ifś mit dem counter, nicht aktiv werden können.
Hoffe dabei kann mir jemand helfen!
BlackJack

@Nobuddy: ``global`` verwendet man nicht wenn man wartbare, verständliche Programme schreiben möchte. Ich bin mir ziemlich sicher dass das Thema schon mal angeschnitten wurde.

Ich würde ``list(obj)`` vorziehen weil das mit *jedem* iterierbaren Objekt funktioniert und nicht nur mit solchen, die die Slice-Syntax verstehen.

Das `process.wait()` ist an der falschen Stelle. Du kannst nicht auf das Ende des Prozesses warten und *danach* erst die Ausgabe auslesen. Wenn der andere Prozess mehr ausgibt als in den Puffer passt, den das Betriebssystem zwischen den beiden Prozessen verwaltet, dann hast Du eine Verklemmung. Dein Programm wartet auf das Ende des anderen Prozesses, und der andere Prozess wartet, dass dein Programm endlich die Ausgaben abnimmt, damit er zum Ende kommen kann. Beides passiert deswegen nie.
Nobuddy
User
Beiträge: 996
Registriert: Montag 30. Januar 2012, 16:38

@BlackJack, Danke für Deine Info, habe dies geändert.

Code: Alles auswählen

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

    counter = 0
    while counter != 4:
        counter += 1
        process = subprocess.Popen(commando, stdout=subprocess.PIPE)
        output = process.stdout.readlines()
        process.wait()
        if output:
            for line in output:
                print (line)
                if paket in line and 'wird eingerichtet ...' in line:
                    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
Das mit dem 'process.wait()' sollte jetzt an der richtigen Stelle stehen, oder?
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

du solltest den Zurückgabewert vom process überprüfen: http://docs.python.org/library/subproce ... returncode

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Nobuddy
User
Beiträge: 996
Registriert: Montag 30. Januar 2012, 16:38

etwa so:

Code: Alles auswählen

def installation(paket):
    commando = list(install_command)
    commando.append(paket.lstrip('-'))

    counter = 0
    while counter != 4:
        counter += 1
        process = subprocess.Popen(commando, stdout=subprocess.PIPE)
        output = process.stdout.readlines()
        process.wait()
        install = process.returncode
        if output:
            for line in output:
                print (line)
            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
Nobuddy
User
Beiträge: 996
Registriert: Montag 30. Januar 2012, 16:38

'global' konnte ich nun auch komplett durch 'list(obj)' ersetzen. :)

Poste hier mal den aktuellen Code von modul_control.py: https://gist.github.com/3109885

Vielleicht fallen Euch noch ein paar Leichen im Keller auf?
Antworten