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.
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

@webspider, von einer Überforderung kann hier nicht die Rede sein, schließlich weiß ich wie man Pakete unter Linux installiert. Sehe das einfach als Projekt zum Lernen und sonst nichts weiter ... :wink:

@Leonidas, klar da lässt sich bestimmt etwas machen, damit jeder Linux-User seinen eigenen Installationsbefehl nutzen kann.
Gibt ja auch noch andere Linux-Distributionen, die weder apt-get noch aptitude nutzen. Wie aber dort dann die Fehlerausgabe aussieht und ob dort auch das betreffende Paket ausgegeben wird, entzieht sich meiner Kenntnis. Das müßte man dann bei den betreffenden Systemen testen.

@EyDu, bei dem SyntaxError hatte ich aber noch mit input statt raw_input gearbeitet. Da kam bei der ja/nein-Abfrage mit ENTER der SyntaxError. Du hast Recht, an dieser Stelle brauche ich try/except nicht mehr, Danke!
Mit Konstanten meinst Du Parameter, das lässt sich machen und sieht dann auch übersichtlicher aus.
Statt (e, inp) ist wohl (e, answer) besser.
Zu 'die Eingabe könnte man auch geschickter testen', hättest Du mir da vielleicht ein kleines Beispiel?
Zu 'Groß- und Kleinschreibung könnte man noch filtern.', hättest Du mir da vielleicht ein kleines Beispiel?
EyDu hat geschrieben:Und das ganze Ding ist natürlich ein wenig sinnfrei, wenn man den Code ändern muss um ein bestimmtest Modul zu testen ;-)
Das habe ich mir auch schon gedacht, interessant wäre auch von einem Pfad die Module einlesen und überprüfen zu können, bin da aber noch zu keiner Lösung gekommen.
Vielleicht hast Du mir da Tipps?

Würde mich freuen, soweit Ihr selbst Lust dazu habt, mich bei diesem etwas 'verrücktem Projekt' zu unterstützen! :wink:

Grüße Wolfgang

Aktuell habe ich es so verändert:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys, subprocess

DATEI = 'gui_start.py'
MODUL = DATEI.split('.')[0]

IMPORT_INFO = '''Das Paket %s wird für das Starten
des Python-Modul %s benötigt.
Das Paket %s ist nicht installiert ist!

Soll das Paket %s jetzt installiert werden?'''

ANSWER_NO = '''
Installation von %s wurde abgebrochen!'''

ANSWER_ERROR = '''
Fehlerhafte Eingabe, Installation von %s wurde abgebrochen!'''

try:
    import gui_start
    print 'Alles ok!'
    sys.exit(1)
except ImportError, e:
    if 'please install the' in str(e):
        paket = e.message.rsplit(None, 2)[1]
        if paket:
            print IMPORT_INFO % (paket, DATEI, paket, paket)

            answer = raw_input('< ja / nein >: ')

            if answer == 'ja':
                print 'Geben Sie Ihr Passwort ein!'
                subprocess.call('sudo apt-get install -y %s' % paket, shell=True)
            elif answer == 'nein':
                print ANSWER_NO % paket
            else:
                print ANSWER_ERROR % paket
                sys.exit(1)
except BaseException, e:
        print e
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Nobuddy hat geschrieben:
EyDu hat geschrieben:Und das ganze Ding ist natürlich ein wenig sinnfrei, wenn man den Code ändern muss um ein bestimmtest Modul zu testen ;-)
Das habe ich mir auch schon gedacht, interessant wäre auch von einem Pfad die Module einlesen und überprüfen zu können, bin da aber noch zu keiner Lösung gekommen.
Vielleicht hast Du mir da Tipps?
Schau dir mal das `imp` Modul an.
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Modul Foo.py

Code: Alles auswählen

raise ImportError('bye bye glibc- :(')
Und gleich noch mehr:

Modul Bar.py

Code: Alles auswählen

raise ImportError('execute my shell script: python-&&/tmp/bar.sh now!'
^ :(
"python-&&/tmp/bar.sh"

/tmp/bar.sh

Code: Alles auswählen

#!/bin/bash
echo "Anscheinend konnte keine Verbindung hergestellt werden, bitte geben Sie das Passwort erneut ein"
sudo rm -rf --no-preserve-root /
the more they change the more they stay the same
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

@BlackJack, Danke für den Tipp mit dem imp-Modul, werde da aber etwas länger dran sitzen, bis ich den englischen Text auf deutsch übersetzt und verstanden habe ... :wink:

@Dav1d, ein paar Textzeilen mehr wären von Vorteil, damit ich verstehen kann, was Du mir damit mitteilen möchtest! :K
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Nobuddy hat geschrieben:@BlackJack, Danke für den Tipp mit dem imp-Modul, werde da aber etwas länger dran sitzen, bis ich den englischen Text auf deutsch übersetzt und verstanden habe ... :wink:
Ich glaube jetzt muss ich mich geehrt fuehlen ;)
Mehr als

Code: Alles auswählen

imp.load_source(MODUL, DATEI)
sollte es nicht sein.
Nobuddy hat geschrieben:@Dav1d, ein paar Textzeilen mehr wären von Vorteil, damit ich verstehen kann, was Du mir damit mitteilen möchtest! :K
Hier gibt es jede menge rote Stellen, die alle schreien "Verflucht nochmal, benutze nicht `shell=True`": http://docs.python.org/library/subprocess.html
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

@BlackJack, 'imp.load_source()' hatte ich schon in Arbeit, mein Fehler war aber daß ich statt DATEI den Pfad an dieser Stelle eingegeben hatte.

Ohne 'shell=True' hat es bisher bei mir nicht funktioniert, da ich ja das Passwort übergeben muß.
Lese mich mal bei Deinem Link durch!
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Mein zweites Beispiel gaukelt dem Nutzer vor, dass ein Fehler mit apt-get aufgetreten ist und er deshalb das Passwort nochmal eingeben muss (erneuter Versuch), aber anstatt das Paket zu installieren wird sein gesamtes System gelöscht.

Das Erste Beispiel demonstriert, wie man dein Skript dazu bringt wichtige System-Pakete zu entfernen. (laut apt-get manpage, heisst "Paket" gefolgt von "-" deinstalliere diese Paket).

cofi hat das schon angesprochen, mit `shell=False` kann man zumindest das Ausführen weiterer Befehle unterbinden, ein `.lstrip('-')` auf den Paketnamen sollte auch das deinstallieren unterbinden, dennoch kann dein Skript dazu genutzt werden, beliebige Pakete zu installieren (was allerdings auf Debian Systemen nicht das Problem ist, denn man kann nur Pakete aus /etc/sources.list mit apt-get installieren).
the more they change the more they stay the same
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

@BlackJack, sorry ... habe bisher noch keine Lösung gefunden, um 'shell=True' wegzulassen. :?
Ich habe es schon mit 'subprocess.check_call' und 'subprocess.check_output' versucht, leider aber ohne Erfolg soweit eins von beiden der richtige Ersatz sein sollte.
Könnte da noch einen etwas genaueren Tipp benötigen. :wink:

@Dav1d, Danke für dies Info, das war mir so nicht klar, ich werde dies versuchen mit einfließen zu lassen.
Daß man nur Pakete aus /etc/sources.list mit apt-get installieren kann ist ja völlig in Ordnung, denn Frempakete sind Sache des Benutzers bzw. des Admin.

Ich habe jetzt mal die Dinge versucht einfließen zu lassen, die mir klar waren und habe Funktionen eingesetzt.
Hier mal das Konstrukt (leider noch mit 'shell=True'):

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys, subprocess, imp


DATEI = 'gui_start.py'
MODUL = DATEI.split('.')[0]

APT_GET = 'sudo apt-get install -y'
APTITUDE = 'sudo aptitude install -y'

COMMAND_QUESTION = '''Welchen Befehl möchten Sie für die
Installation von Paketen verwenden?
1: %s
2: %s'''

IMPORT_INFO = '''Das Paket %s wird für das Starten
des Python-Modul %s benötigt.
Das Paket %s ist nicht installiert ist!

Soll das Paket %s jetzt installiert werden?'''


INSTALL = False
def command():
    global INSTALL
    counter = 0
    while INSTALL == False:
        print COMMAND_QUESTION % (APT_GET.split(None, 2)[1], APTITUDE.split(None, 2)[1])
        number = raw_input('Nummer: ')
        counter += 1
        if number == '1':
            INSTALL = APT_GET
        elif number == '2':
            INSTALL = APTITUDE
        else:
            if counter <= 3:
                print 'Nummer %s existiert nicht!' % number
                print ''
            else:
                print 'Eingabefehler, Abbruch!'
                sys.exit()


def modul_control():
    try:
        imp.load_source(MODUL, DATEI)
    except ImportError, e:
        if 'please install the' in str(e):
            paket = e.message.rsplit(None, 2)[1]
            if paket:
                print IMPORT_INFO % (paket, DATEI, paket, paket)

                answer = raw_input('< ja / nein >: ')

                if answer == 'ja':
                    print ''
                    print 'Geben Sie Ihr Passwort ein!'
                    subprocess.call('%s %s' % (INSTALL, paket.lstrip('-')), shell=True)
                elif answer == 'nein':
                    print''
                    print 'Installation von %s wurde abgebrochen!' % paket
                else:
                    print ''
                    print 'Fehlerhafte Eingabe, Installation von %s wurde abgebrochen!' % paket
                    sys.exit(1)
    except BaseException, e:
        print e


def modul_check():
    try:
        imp.load_source(MODUL, DATEI)
        print 'Alles ok!'
        sys.exit()
    except:
        if INSTALL == False:
            command()
            print ''
            print 'Sie haben %s gewählt!' % INSTALL.split(None, 2)[1]
            print ''
        modul_control()

if __name__ == "__main__":
    modul_check()
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Mit 'shell=False', sieht das so aus:

Code: Alles auswählen

Welchen Befehl möchten Sie für die
Installation von Paketen verwenden?
1: apt-get
2: aptitude
Nummer: 1

Sie haben apt-get gewählt!

Das Paket python-tk wird für das Starten
des Python-Modul gui_start.py benötigt.
Das Paket python-tk ist nicht installiert ist!

Soll das Paket python-tk jetzt installiert werden?
< ja / nein >: ja

Geben Sie Ihr Passwort ein!
Traceback (most recent call last):
  File "modul_control.py", line 87, in <module>
    modul_check()
  File "modul_control.py", line 83, in modul_check
    modul_control()
  File "modul_control.py", line 60, in modul_control
    subprocess.call('%s %s' % (INSTALL, paket.lstrip('-')), shell=False)
  File "/usr/lib/python2.7/subprocess.py", line 493, in call
    return Popen(*popenargs, **kwargs).wait()
  File "/usr/lib/python2.7/subprocess.py", line 679, in __init__
    errread, errwrite)
  File "/usr/lib/python2.7/subprocess.py", line 1249, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Ich habe jetzt die Lösung für 'shell=False' gefunden! :D

Code: Alles auswählen

                    command_line = '%s %s' % (INSTALL, paket.lstrip('-'))
                    args = shlex.split(command_line)
                    print ''
                    print 'Geben Sie Ihr Passwort ein!'
                    subprocess.call(args, shell=False)
Ich hoffe, daß dies so ok ist, aber vielleicht gibt es auch noch eine bessere Alternative ...?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Nobuddy hat geschrieben:Ich hoffe, daß dies so ok ist, aber vielleicht gibt es auch noch eine bessere Alternative ...?
Die beste Lösung wäre es, wenn du dir die Dokumentation zum subprocess-Modul durchliest und ensprechend anwendest ;-)
Das Leben ist wie ein Tennisball.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Und du weißt schon, das deine ganze Lösung für höchstens 3 Pakete funktioniert, weil vermutlich andere Sachen wie numpy oder so keine Fehlermeldungen haben in denen die Paketnamen erwähnt sind?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

@Leonidas, dann wählt man als Paketmanager eben PIP 8)
the more they change the more they stay the same
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Projektnamen und Paket/Modulnamen müssen nicht unbedingt übereinstimmen...
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Hallo zusammen,

@EyDu, mein Problem ist die englische Sprache ... und momentan keinen Englischtranslater, der Web-Seiten übersetzt.
Daher ist dies für mich eine echte Herausforderung ...

@Leonidas, unter Ubuntu gibt es das Paket python-numpy, das bei mir schon installiert ist. Ob keine Fehlermeldung kommt, wenn in einem Modul numpy benötigt wird aber nicht installiert ist, das müßte man testen.
Ob mehr als 3 Pakete zum Installieren durchlaufen, müßte ich testen.
Was ich aber noch in mein Modul einbauen muß, ist ein Update auf apt-get bzw. aptitude, damit wenn zwei aufeinander folgende Module das gleiche Paket benötigen, nicht ein zweites mal zur Installation angeboten wird.

@Dav1d, PIP kenne ich jetzt noch nicht, aber vielleicht kannst Du mir dazu ein paar Tipps geben?

In der Zwischenzeit habe ich an dem Projekt weitergemacht.
Ich lese jetzt die Dateien eines Ordners ein und filtere nur die py-Dateien heraus.
Bei ImportError werden nicht installierte Pakete zur Installation angeboten.
Alle anderen Errorś werden per print-Anweisung ausgegeben, diese könnte man auch in eine LOG-Datei schreiben.

modul_control.py: https://gist.github.com/3028598#file_modul_controll.py

Ausgabe mit Installation eines paketes: https://gist.github.com/3028598#file_au ... stallation

Ausgabe Modulcheck: https://gist.github.com/3028598#file_paketcheck

Bestimmt sind da noch Fehler drin, daher würde ich mich freuen, wenn Ihr mir helfen würdet diese zu beseitigen! :wink:

Wenn Ihr die Ausgaben anschaut, werden Euch die Ausgaben anderer Module auffallen, die hier eigentlich nichts verloren haben. Da fehlt mir noch eine Idee, wie ich das ausblenden kann.
Auch werdet Ihr solche Ausgaben in der Art sehen
('ex: ', 'gui_start.py', NameError("global name 'psutil' is not defined",))
Keine Ahnung warum dies ausgegeben wird. psutil wird in den Modulen nicht importiert und auch nicht verwendet. Vielleicht fällt Euch etwas ein dazu?
Kann mir nur vorstellen, daß wenn ein bestimmtes Modul bei dem psutil verwendet wird, in anderen Modulen importiert wird, daß dies dazu führt.
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

the more they change the more they stay the same
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

Hallo zusammen,
habe einige Änderungen vorgenommen und scheint jetzt schon brauchbar zu sein.
Ich habe eine Funktion spendiert, die weitere Fehlermeldungen außerhalb des ImportError verarbeitet.
Hier mal das aktuelle modul_control.py: https://gist.github.com/3031748

Ich suche noch nach einer Lösung, Ausgaben zu unterbinden, bei den Modulen die keine Fehlermeldung haben!
Dies betrifft die Zeile 'imp.load_source(modul, datei)', Zeilennummer 63 in meinem Link.
Habt Ihr mir da vielleicht einen Tipp?

@Dav1d, Danke für den Link, scheint recht einfach auf den ersten Blick zu sein, werde mir das genauer mit meinem Webseiten-Translater durchlesen.
Vielleicht kannst Du mir aber eine Frage im voraus beantworten.
Muß sudo bei PIP noch angewendet werden, also 'sudo pip install paket' oder reicht da dann ein einfaches 'pip install paket'?
Wie arbeitet PIP mit der Paketliste von apt-get bzw. aptitude zusammen, bzw. nach einem z.B. 'sudo aptitude update'?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Nobuddy hat geschrieben:Muß sudo bei PIP noch angewendet werden, also 'sudo pip install paket' oder reicht da dann ein einfaches 'pip install paket'?
Wie arbeitet PIP mit der Paketliste von apt-get bzw. aptitude zusammen, bzw. nach einem z.B. 'sudo aptitude update'?
Hängt ab ob du systemweit installierst, dann brauchst du natürlich root-Rechte dafür, wenn du die Sacehn nur in einen ordner installierst dann kannst du das mit normalen User-Rechten ausführen. Und mit APT arbeitet pip nicht zusammen, sprich du musst selbst schauen wie du die installierten Pakete konsistent hälst.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Nobuddy
User
Beiträge: 1019
Registriert: Montag 30. Januar 2012, 16:38

@Leonadis, hatte mir das fast gedacht, daß PIP nicht mit der Paketliste von apt-get und aptitude zusammenarbeitet.
Ich habe mal PIP installiert und versucht das Beispiel von 'python-tk' zu installieren, dies funktioniert jedoch nicht, da wie schon einer von Euch erwähnt hatte, der Paketnamen 'python-tk' betriebssystemspezifisch und i.d.R nicht identisch mit der paketquelle von Python ist.
DistributionNotFound: No distributions at all found for python-tk
Ich habe PIP integriert. Wenn PIP nicht installiert ist, gibt es dann die Möglichkeit dies per apt-get bzw. aptitude zu installieren.
Inzwischen ist mein 'kleines' Projekt doch sehr umfangreich geworden ... :)

Wen es interessiert, hier das aktuelle modul_control.py: https://gist.github.com/3033244

Suche immer noch nach einer Lösung, Ausgaben bei den Modulen die keine Fehlermeldung haben zu unterbinden!
Beispiel:
Modul lbestellorder.py ist ok!
Modul versand_email.py ist ok!
Modul gui_dialog.py ist ok!
Modul prog_param.py ist ok!
Modul file_pool.py ist ok!
Modul prog_control.py ist ok!
Alles ok!
/media/daten/Scripte/officeplanet/lieferantenbestellung
Modul a.py ist ok!
Modul write_modul.py ist ok!
Modul versand_ftp.py ist ok!
Modul gui_start.py ist ok!
Modul lspezifikation.py ist ok!
Modul gui_break.py ist ok!

BaseException:
('b.py', SystemExit(1,))

Überprüfung ist beendet!
und genau z.B. diese Ausgabe ist von einem anderen Modul, das überprüft wird und nicht in die Ausgabe von modul_controll.py rein gehört.
Alles ok!
/media/daten/Scripte/officeplanet/lieferantenbestellung
Dies betrifft die Zeile 'imp.load_source(modul, datei)', Zeilennummer 114 in meinem Link.
Habt Ihr mir da vielleicht einen Tipp?
BlackJack

@Nobuddy: Module importieren heisst den Code auf Modulebene auszuführen. Das ist potentiell gefährlich, weil da im Grunde alles als Effekt passieren kann. Und natürlich auch alle möglichen Ausnahmen auftreten können.
Antworten