Das Ubuntuusers-Supporttool

Du hast eine Idee für ein Projekt?
arkarin
User
Beiträge: 2
Registriert: Sonntag 21. Juni 2009, 09:54

Hallo Pythoniacs,

die ubuntuusers.de Community hat ein kleines Projekt gestartet.
Hierbei soll es sich um ein kleines Tool handeln, das Informationen zu den Systemeinstellungen und der Hardware eines Benutzers sammelt.
Mit diesem Tool können die Nutzer, die auf Hilfe angewiesen sind dann den Forenmitgliedern die nötigen Informationen zu ihrem System und ihrer Hardware übermitteln, ohne dass man sie gleich mit dem Terminal überfordert..
Die Anforderungen an das Tool sind hier zu finden:
http://ikhaya.ubuntuusers.de/2009/05/14 ... g-gesucht/
Eine Wiki-Seite gibt es hier:
http://wiki.ubuntuusers.de/Baustelle/Ve ... upporttool

Ich habe Lust das Ding zu programmieren, habe aber noch nicht unglaublich viel Erfahrung mit Python. Bisher habe ich vor allem für mich selbst programmiert und da kam es mir nur darauf an, dass das Programm läuft, nicht aber das es einen schönen Quelltext hat oder man es sogar mit Plugins erweitern kann.

Es wäre schön, wenn einige von euch sich bereit erklären könnten, ein paar Ideen zu dem Programm beizusteuern, vor allem was die Pluginfähigkeit angeht.
Gerne dürft ihr natürlich auch mitprogrammiern.
Ich würde mich wirklich freuen, wenn was aus dem Projekt werden und ich dabei auch noch was lernen würde.

Ich freue mich auf eure Antworten

Arkarin


PS: Ich habe schon mal einen ganz winzig kleinen Teil programmiert, der Informationen über die Releasnummer und Kernelversion sammelt, Kritik und Anregungen erwünscht:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# sysinfo.py
import subprocess

def version_info():
    ''' get the distribution's release number '''
    file = open('/etc/lsb-release', 'r')
    data = file.read()
    data = data.split()
    release = data[1]
    release = release.split('=')
    release = release[1]
    return(release)

def kernel_info():
    ''' get information about kernel-version and 32 or 64 bit version'''
    process = subprocess.Popen(['uname', '-ar'], stdout=subprocess.PIPE)
    process.wait()
    data = process.stdout.read()
    data = data.split()
    kernel_version = data[2] + " " + data[-2]
    return(kernel_version)

def print_sysinfo(release, kernel_version):
    ''' print all the informations'''
    print "Distributions-Version: ", release
    print "Kernel-Version: ", kernel_version

if __name__ == "__main__":
    release = version_info()
    kernel_version = kernel_info()
    print_sysinfo(release, kernel_version)
[/code]
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Hallo arkarin, willkommen im Forum,

``file`` zu überschreiben ist keine gute Idee, außerdem verstehe ich nicht ganz warum man ein Konsolentool schreibt, wenn man User nicht mit dem Terminal verschrecken will. Da würde man IMHO ja eher PyGTK nutzen um dem User eine grafische Übersicht gibt, am besten noch mit "Copy to Clipboard"-Button.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Mal ein paar Anmerkungen zum Code:
- am Anfang und am Ende der Doc-Strings musst du keine Leerzeichen machen
- ein Objekt an den Namen "file" zu binden ist keine gute Idee, da du damit einen built-in Namen verdeckst
- Pfade solltest du als Konstanten ablegen
- den "close"-Aufruf nicht vergessen
- "version_info" kannst du verkürzen, indem du nicht alles immer an einen Namen bindest. "release.split('=')[1]" ist durchaus ok
- um die Werte hinter "return" kommen keine Klammern, einfach nur "return wert"
- Wenn du Strings zusammensetzt, dann benutze besser String Formatting
- "kernel_info" könnte die Informationen auch als Tupel zurückgeben, dann kommt man auch an die Einzelinformationen
- überhaupt könnte man überlegen, ob man nicht alle Informationen noch weiter zerlegt.
- Ausgaben solltest du bündig formatiert machen, andernfalls sieht es leicht sehr unübersichtlich aus.
- alles was gerade hinter dem "if __name__ == '__main__'" versteckt ist solltest du gleich noch in eine "main"-Funktion verpacken
Das Leben ist wie ein Tennisball.
Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

Ja, ich fand es auch etwas komisch, dass alle immer vom "Konsolentool" sprechen: Was die aber eigentlich meinen ist, dass das UUST modular aufgebaut sein soll und es sowohl ein PyGTK als auch ein Konsolen-Frontend geben soll.

Ich will auch wirklich nicht böse sein, aber bei dem Aufruf in Ikhaya hatte ich auch einwenig den Eindruck, dass sich da wirklich überwiegend Anfänger gemeldet haben. Wenn jemand wirklich Interesse an dem Ding hätte, gäbe es das wahrscheinlich auch schon - zumindest glaube ich, dass sich sowas leicht in deutlich unter 5000 Zeilen Code machen ließe - zumindest die Grundfunktionen.

Aber ich will ja nicht unken. Auf ubuntuusers.de hat übrigens auch schon jemand im UUST-Strang ein Beispiel des Tools mit Plugin-Schnittstelle eingestellt.
arkarin
User
Beiträge: 2
Registriert: Sonntag 21. Juni 2009, 09:54

Vielen Dank für die vielen schnellen und konstruktiven Rückmeldungen !
Ich habe jetzt mal versucht möglichst alles umzusetzen, was EyDu erwähnt hat.
Eine GUI soll es auch noch geben, ich dachte mir nur, dass es vllt sinnvoller ist, wenn ich erst mal die Informationen beschaffe und sie dann später in eine GUI einbaue.
Oder mache ich mir das so unnötig schwer?
Probelamtisch an der GUI sehe ich auch die Anforderung, das das Programm ohne die installation zusätzlicher Pakete zu "ubuntu-minimal" laufen soll, da bei Ubuntu im mit installierten Python-Paket noch nicht mal Tk dabei ist.. Ideen ?

Neue Version:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# sysinfo.py
import subprocess

def version_info():
    '''get the distribution's release number'''
    path = '/etc/lsb-release'
    f = open(path, 'r')
    data = f.read()
    f.close()
    release = data.split()[1]
    release = release.split('=')[1]
    return release

def kernel_info():
    '''get information about kernel-version'''
    process = subprocess.Popen(['uname', '-ar'], stdout=subprocess.PIPE)
    process.wait()
    data = process.stdout.read()
    kernel_version = data.split()[2]
    return kernel_version
    
def processor_arch():
    '''get information about 32 or 64 bit version'''
    process = subprocess.Popen(['uname', '-ar'], stdout=subprocess.PIPE)
    process.wait()
    data = process.stdout.read()
    processor_arch = data.split()[-2]
    return processor_arch
   

def print_sysinfo(release, kernel_version, processor_arch):
    '''print all the informations'''
    print "%-23s %-s" %("Distributions-Version: ", release)
    print "%-23s %-s" %("Kernel-Version: ", kernel_version)
    print "%-23s %-s" %("32 oder 64 Bit: ", processor_arch)

def main():
    release = version_info()
    kernel_version = kernel_info()
    arch = processor_arch() 
    print_sysinfo(release, kernel_version, arch)
    
if __name__ == "__main__":
    main()
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Du gehst das schon richtig an: erst die Funktionalität und am Ende kann man immer noch ein GUI drüber setzen.

Die "path"-Konstante sollte nicht in der Funktion stehen, sondern auf Modul-Ebene. Namen von Konstanten werden nach PEP 8 in Großbuchstaben geschrieben. Also

Code: Alles auswählen

PATH = '/etc/lsb-release'
. Man sollte sich aber noch einen passenderen Namen einfallen lassen.

Mit dem zurückgeben der aufgeteilten Informationen meinte ich übrigens nicht, dass du zwei identische Funktionen schreibst, welche nur einen anderen Index besitzen, sondern so:

Code: Alles auswählen

def kernel_info():
    ''' get information about kernel-version and 32 or 64 bit version'''
    process = subprocess.Popen(['uname', '-ar'], stdout=subprocess.PIPE)
    process.wait()
    data = process.stdout.read()
    data = data.split()
    
    return data[2], data[-2]
Vielleicht nur kurz zur Ausgabe:

Code: Alles auswählen

def print_sysinfo(release, kernel_version, processor_arch):
    '''print all the informations'''
    data = [("Distributions-Version: ", release),
                ("Kernel-Version: ", kernel_version),
                ("32 oder 64 Bit: ", processor_arch)]
    
    name_length = max(len(name) for name, _ in data) + 1
    format_ string = "%%-%ds %%-s" % name_length

    for element in data:
        print format_string % element
Das Leben ist wie ein Tennisball.
BlackJack

Es gibt übrigens das `platform`-Modul, was hier ein paar Aufrufe von externen Programmen ersetzen kann.

Ich zweifle allerdings so ein bisschen den Sinn von dem Vorhaben an. Es gibt doch schon solche Werkzeuge, z.B. `lshw`.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

arkarin hat geschrieben:Probelamtisch an der GUI sehe ich auch die Anforderung, das das Programm ohne die installation zusätzlicher Pakete zu "ubuntu-minimal" laufen soll, da bei Ubuntu im mit installierten Python-Paket noch nicht mal Tk dabei ist.. Ideen ?
Hmm? Wenn ich mich richtig erinnere ist in der Ubuntu Standardinstallation ja PyGTK mit dabei, da einige Verwaltungstools das sowieso schon nutzen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
apollo13
User
Beiträge: 827
Registriert: Samstag 5. Februar 2005, 17:53

Ubuntu != Kubuntu etc…
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

apollo13 hat geschrieben:Ubuntu != Kubuntu etc…
Ja, aber die Mehrheit nutzt wohl Ubuntu. Man *kann* kein GUI-Toolkit finden um die Nutzer von Ubuntu und Kubuntu zufriedenzustellen:
  • PyGTK: Gut für Ubuntu, Xubuntu (+2), weniger gut für Kubuntu (0) = +2
  • wxPython: Da es unter Linux GTK+ verwendet, genauso wie PyGTK = +2
  • PyQt: Gut für Kubuntu (+1), weniger gut für alle anderen (0) = +1
  • Tkinter: Schlecht für alle drei (-1): -3
Also am besten das geringste Übel nehmen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Andyh
User
Beiträge: 319
Registriert: Dienstag 8. Januar 2008, 19:52
Kontaktdaten:

Hallo

Bin dabei!!!

Gruß
Andyh
Meinen Dickschädel schon bemerkt?
Ich bin jetzt FACHARBEITER (Zerspanungsmechaniker)!!!
[code]import sys

if sys.platform == "win32":
print "this program only runs on operating systems!!!"
sys.TotalError()[/code]
Benutzeravatar
tiax
User
Beiträge: 152
Registriert: Samstag 23. Juli 2005, 17:28
Kontaktdaten:

in diesem Artikel vom Portal sind recht viele Anforderungen. Sind die denn absolut verbindlich?

Wieso wird eine Lizenz vorgeschrieben? Dass das mit den GUI-Toolkits recht problematisch ist, wurde ja schon diskutiert.
Ne invoces expellere non possis
[url=xmpp://florian@florianheinle.de]xmpp:florian@florianheinle.de[/url]
Andyh
User
Beiträge: 319
Registriert: Dienstag 8. Januar 2008, 19:52
Kontaktdaten:

Hallo

Was haltet ihr davon:

Code: Alles auswählen

class Analyse_Software():
    def __init__(self):
        '''
        Sammelt informationen über die Software
        '''
        pass
    
    def get_name(self):
        '''
        gibt den System Namen zurück
        '''
        return ["System Namen", platform.dist()[0]]
    
    def get_version(self):
        '''
        gibt die Systemversion zurück 
        '''
        return ["System Version", platform.dist()[1]]
    
    def get_deckname(self):
        '''
        gibt den Deckname zurück
        '''
        return ["Deckname", platform.dist()[2]]
    
    def get_computer_name(self):
        '''
        gibt den Pc Name zurück
        '''
        return ["Computer Name", platform.node()]
    
    def get_machine(self):
        '''
        gibt den type der Maschine zurück
        '''
        return ["Maschine", platform.machine()]
    
    def get_bit(self):
        '''
        gibt die bit Version des systems zurück
        '''
        return ["Bit" ,platform.architecture()[0]]
    
    def get_py_version(self):
        '''
        gibt die Pythonversion zurück
        '''
        return ["Python Version", platform.python_version()]
    
    def get_py_art(self):
        '''
        gibt zurück welchen pythoninterpret man benützt
        '''
        return ["Python Interpret", platform.python_implementation()]
    
    def get_system(self):
        '''
        gibt den namen der system art aus (linux)
        '''
        return ["System Art", platform.system()]
    
    def get_kernel(self):
        '''
        gibt die Kernel Version zurück
        '''
        return ["Kernel Version" ,platform.release()]
    
    def get_all_debs(self):
        '''
        gibt alle instalierten packete zurück
        '''
        process = subprocess.Popen(["dpkg", " -l | awk '{print $2}'"], stdout=subprocess.PIPE)
        process.wait()
        data = process.stdout.read() 
        return ["dpkg", data]
    
    def get_xorg(self):
        '''
        gibt die xorg configuration zurück
        '''
        return ["/etc/X11/xorg.conf", open("/etc/X11/xorg.conf").read()]
    
    def get_xorg_log(self):
        '''
        gibt die xorg log datei zurück
        '''
        return ["/var/log/Xorg.0.log", open("/var/log/Xorg.0.log").read()]
    
    def get_apt_conf(self):
        '''
        gibt die Packetverwaltung aus
        '''
        data = open("/etc/apt/sources.list", "r")
        datei = ""
        for line in data.readlines():
            if not line.startswith("#"):
                datei += line
                
        return ["/etc/apt/sources.list", datei]
    
class Analyse_Hardware():
    def __init__(self):
        '''
        Sammelt informationen über die Hardware
        '''
        pass 
    
    def get_video(self):
        '''
        gibt informationen über die anzeige aus
        '''
        process = subprocess.Popen(["lspci", " | grep VGA"], stdout=subprocess.PIPE)
        process.wait()
        data = process.stdout.read() 
        return ["lspci | grep VGA", data]
    
    def get_audio(self):
        '''
        gibt informationen über das audiogerät aus
        '''
        process = subprocess.Popen(["aplay", "-l"], stdout=subprocess.PIPE)
        process.wait()
        data = process.stdout.read() 
        return ["aplay" ,data.replace("**** Liste von PLAYBACK Geräten ****", "")]
    
    def get_network(self):
        '''
        gibt informationen über die netzwerk konfiguration aus
        '''
        process = subprocess.Popen(["iwconfig"], stdout=subprocess.PIPE)
        process.wait()
        data = process.stdout.read() + "\n\n"
         
        process = subprocess.Popen(["ifconfig"], stdout=subprocess.PIPE)
        process.wait()
        data += process.stdout.read() 
        return ["iwconfig und ifconfig", data]
    
    def get_ip_info(self):
        '''
        gibt informationen über die Ip_adresse aus
        '''
        process = subprocess.Popen(["route", "-n"], stdout=subprocess.PIPE)
        process.wait()
        data = process.stdout.read()
        return ["route -n", data]
    
    def get_lan_card(self):
        '''
        gibt die Lankarte aus
        '''
        process = subprocess.Popen(["lspci", "-nn | grep -i net"], stdout=subprocess.PIPE)
        process.wait()
        data = process.stdout.read()
        return ["lspci -nn | grep -i net", data]
    
    def get_pci(self):
        '''
        gibt die per pci angeschlossenen geräte aus
        '''
        process = subprocess.Popen(["lspci"], stdout=subprocess.PIPE)
        process.wait()
        data = process.stdout.read()
        return ["lspci", data]
    
    def get_usb(self):
        '''
        gibt die per usb angeschlossenen geräte aus
        '''
        process = subprocess.Popen(["lsusb"], stdout=subprocess.PIPE)
        process.wait()
        data = process.stdout.read()
        return ["lsusb", data]
Ist doch mal ein anfang.
ACHTUNG: ungetestet
für 20 min aufjedenfall OK

Gruß
Andyh
Meinen Dickschädel schon bemerkt?
Ich bin jetzt FACHARBEITER (Zerspanungsmechaniker)!!!
[code]import sys

if sys.platform == "win32":
print "this program only runs on operating systems!!!"
sys.TotalError()[/code]
lunar

Gar nichts.

Die Klassen sind künstlich und überflüssig, es fehlt jede Ausnahmebehandlung, die Aufrufe der Unterprozesse sind kaputt (Pipes benötigen eine Shell, um sie auszuwerten, und im Übrigen hat Python ja auch Funktionen zur Zeichenkettenverarbeitung), die Rückgabewerte "komisch".
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Warum Klassen, wenn sie nur ein Namensraum für Funktionen sind?

Warum ``__init__`` überschreiben, wenn es nichts tut?

Vorschlag: Sammel die Daten in ``__init__`` und halte sie dann als Attribut vor. Das würde allerlei redundante Aufrufe erledigen.
Die komplizierteren Aufrufe kannst du auch als ``property`` vorhalten.

Generell solltest du die Ausgabe von den Methoden trennen, aber das fällt auch nicht an, wenn du den Vorschlag berücksichtigst.
Andyh
User
Beiträge: 319
Registriert: Dienstag 8. Januar 2008, 19:52
Kontaktdaten:

Hallo

@Lunar
Upps da habe ich ja woll "shell=True" unterschlagen

Klassen mache ich eingentlich immer gerne der ordung wegen

Die Rückgabe werte sind nicht komisch du weis nur nicht wie ich mir das denke :D

@cofi
Ich lege immer gleiche eine __init__ an weil fast immer eine brauche, nur nicht immer gleich an anfang und wenn ich si dann brauche ist sie schon da.
alles in die __init__ zu legen um es einfache abzuruffen hört sich nicht schlecht an.

mir gehts es jetzt erstmal darum soviel wie möglich informationen zusammel gestallten kann ich das dann noch in ruhe.

Also wenn ihr denket da fehlt noch was Grundlegendes dan bitte melden!

Gruß
Andyh
Meinen Dickschädel schon bemerkt?
Ich bin jetzt FACHARBEITER (Zerspanungsmechaniker)!!!
[code]import sys

if sys.platform == "win32":
print "this program only runs on operating systems!!!"
sys.TotalError()[/code]
lunar

Andyh hat geschrieben:Upps da habe ich ja woll "shell=True" unterschlagen
In einem ordentlichen Programm wäre "shell=True" unnötig. Die Zeichenkettenverarbeitung kannst du auch in Python erledigen, dazu benötigt es weder grep noch awk.
Klassen mache ich eingentlich immer gerne der ordung wegen
In deinem Fall erhöhen die Klassen weder die Übersicht noch gestalten sie das Programm ordentlicher, sie erhöhen nur unnötigerweise die Komplexität. Klassen sind kein Selbstzweck.
busfahrer
User
Beiträge: 111
Registriert: Donnerstag 9. Oktober 2008, 17:42

Hallo
eine frage an die "Profis" :wink:

Was wäre denn die empfehlenswertere Funktion(sie tun ja wohl beide das selbe) oder ist das egal und Geschmacksache?

das Original

Code: Alles auswählen

def processor_arch(): 
    '''get information about 32 or 64 bit version''' 
    process = subprocess.Popen(['uname', '-ar'], stdout=subprocess.PIPE) 
    process.wait() 
    data = process.stdout.read() 
    processor_arch = data.split()[-2] 
    return processor_arch
und so hab ich sie jetzt gebaut

Code: Alles auswählen

def processor_arch(): 
    '''get information about 32 or 64 bit version''' 
    process = subprocess.Popen(['uname', '-ar'], stdout=subprocess.PIPE) 
    data = process.communicate()[0].split()[-2]
    return data
Gruß...busfahrer
Alles wird gut ;-)
encbladexp
User
Beiträge: 61
Registriert: Freitag 7. März 2003, 19:28
Kontaktdaten:

Die Lizenz ist natürlich noch Verhandlungssache, man könnte also auch BSD nehmen. Die Features sind aber gewünscht, den es muss gehen egal ob man Ubuntu, Kubuntu, Xubuntu oder ggf. überhaupt kein X hat.

mfg Betz Stefan
BlackJack

@busfahrer: Erst einmal ist es unsinnig `uname` so aufzurufen, dass es maximal viele Informationen liefert, wenn man nur eine davon haben möchte, statt nur das abzufragen *was* man haben möchte:

Code: Alles auswählen

bj@s8n:~$ uname -m
i686
Und dann würde der Profi eher das hier schreiben:

Code: Alles auswählen

import platform

processor_arch = platform.machine
Wobei man den Namen nicht abkürzen sollte, der DocString passt nicht zur Information, die da geliefert wird.

Und *wenn* man über externe Programme geht, die mehrere Informationen auf einen Schlag liefern können, dann sollte man das auch ausnutzen und alle Abfragen und zwischenspeichern.
Antworten