Alles, was wir bis Teil 4 gemacht haben, war eigentlich nur ein Bild zu zeichnen. Das ist nicht nur eine Metapher, sondern durchaus korrekt dargestellt. Wir haben Code geschrieben, der dem Fenster-Manager sagt: Ich brauche ein Fenster mit zwei farbigen Rahmen und einem Bild darin. Wirklich etwas falsch machen kann man hier nicht, außer fehlerhaften Code einzugeben. Der Compiler würde uns dann schon sagen, was nicht läuft. Wir können das bisher Erarbeitete also als Kunst verbuchen, und Kunst ist nun mal Ansichtssache.
Nun sind wir fürs Erste fertig mit diesem Teil und wollen dazu übergehen, Informationen auszulesen und sie unserem GUI anzeigen zu lassen. Ab jetzt gibt es unzählige Möglichkeiten und Varianten, dies zu tun. Wir kommen in einen Bereich, der viel Lektüre beansprucht und bei dem es um Lesbarkeit, Simplizismus, Effektivität und auch Sicherheit geht.
Es wird unvermeidbar sein, auf Bugs zu stoßen oder Probleme mit Distro-übergreifenden Funktionen zu bekommen. Sprich: Wir werden die einfachsten Lösungen nutzen, wir werden Fehler machen und versuchen, diese zu beseitigen, aber wir müssen uns auch damit auseinandersetzen, dass das, was wir zusammen gebaut haben, vielleicht gar nicht auf den Systemen anderer Leute funktioniert.
Unser Workflow:
DENKEN > Code schreiben > Testen > DENKEN > Fehler beheben > Testen
Der User
Es gibt dutzende Wege, den aktuellen Nutzer auszulesen. Wir gehen den Weg über das os-Modul. Hiermit kann man so einiges nicht nur auslesen, sondern auch manipulieren. Im Laufe der Serie werden wir `os` noch besser beleuchten; die schiere Menge an Möglichkeiten kann aber schnell überfordern. Wie immer gilt: Eines nach dem anderen.
Das Modul ist standardmäßig in Python implementiert, und ihr müsst nichts nachinstallieren.
os.getlogin()
Return the name of the user logged in on the controlling terminal of the process. For most purposes, it is more useful to use getpass.getuser() since the latter checks the environment variables LOGNAME or USERNAME to find out who the user is, and falls back to pwd.getpwuid(os.getuid())[0] to get the login name of the current real user id.
Test-Code
import os user = os.getlogin() print(user)Der Output sollte Euer Nutzer-Name sein.
Einbauen
Zu unserer Importliste fügen wir import os. Nun legen wir die Variable user = os.getlogin()an. Als Nächstes müssen wir den Text des Labels manipulieren. Jetzt kommt der f-String ins Spiel.
Vorher:
user_host_label = tk.Label(stat_frame,text="USER@HOST") user_host_label.pack(anchor=tk.NW)Nachher:
user_host_label = tk.Label(stat_frame,text=f"{user}@HOST") user_host_label.pack(anchor=tk.NW)Logik
- Vor die Quotes(" ") wird ein "f" gesetzt, um den String zu manipulieren
- Es wird USER ersetzt durch user in { } (geschweifte Klammern)
- die Variable user am Anfang des Codes wird gespeichert und innerhalb des Strings ausgegeben
Der Host
Diesen können wir mit dem socket-Modul auslesen, welches ebenfalls in Python enthalten sein sollte. Es bietet Zugriff auf die Netzwerk-Schnittstellen des Betriebssystems und ermöglicht es, Netzwerkkommunikation mittels Sockets durchzuführen. Ein Socket ist ein Endpunkt einer bidirektionalen Kommunikationsverbindung zwischen zwei Programmen, die über ein Netzwerk kommunizieren.
Wir benötigen erstmal nur eine Funktion dieses Moduls
socket.gethostname()
Einbauen
Wir auch zuvor binden wir socket in den Code ein mit import socket, Dann legen wir die nötige Variable an.
hostname = socket.gethostname()Ich hoffe, ihr hab aufgepasst und wisst, was nun folgt. Die Erklärung solltet ihr Euch selbst erschließen können.
user_host_label = tk.Label(stat_frame,text=f"{user}@{hostname}") user_host_label.pack(anchor=tk.NW)Der Code bis hier
## Teil 5 ### import tkinter as tk from PIL import Image, ImageTk import os import socket user = os.getlogin() hostname = socket.gethostname() # Erstelle das Hauptfenster root = tk.Tk() root.title("Neofetch-Tk") root.geometry("800x500") distro_logo = tk.PhotoImage(file="images/test.png") # Einen Frame Zeichen logo_frame = tk.Frame(root,background="yellow") logo_frame.pack(fill="both",expand=False,side='left',padx=10,pady=10) # Distro-Logo-Label distro_icon = tk.Label(logo_frame,text="DISTRO LOGO",image=distro_logo,background="yellow") distro_icon.pack(anchor=tk.NW) # Einen Frame Zeichen stat_frame = tk.Frame(root,background="cyan") stat_frame.pack(fill="both",expand=True,side='left',padx=10,pady=10) # Label mit Text USER@HOST user_host_label = tk.Label(stat_frame,text=f"{user}@{hostname}") user_host_label.pack(anchor=tk.NW) # Starte die Hauptschleife root.mainloop()Ist Euch eigentlich etwas aufgefallen? Nein? Schade. In Teil 4 war 2x user_host_label vorhanden. Python liest das File von oben nach unten durch und es ist dem Interpreter egal, ob die vorherige Variable genauso hieß. Bei Labels ist das weiter nicht schlimm. Wenn ihr aber eine Variable mit einem wichtigen, wer verseht z.B. zahl_eins = 1 und danach aus Versehen zahl_eins = 2 als setzt, ist kann das zum Problem werden. Also achtet auf die Benennung.
OS Label
Wir korrigieren nun diesen Fehler und benennen die Variable um, das sollte dann so aussehen:
Wie kommen wir jetzt an unseren OS-NAMEN?
Wir werfen zunächst einen Blick in /bin/neofetch. Ob Ihr das nun mit cat macht, oder Eurem Liebling-Editor ist vollkommen egal. Um die betreffende Stelle zu finden, müssten wir zunächst an hunderten auskommentierte Zeilen vorbei.
Nicht ganz ausführlich, aber ausreichten erklärt holt sich neofetch die Information aus /etc/os-release und/oder /etc/lsb-release. Das ist noch wichtig zu wissen für später.
Wie wir das nachbilden können, habe ich schon in dem Artikel zur Terminal-Version veranschaulichen:
# Get Name of Distro os_release = subprocess.run(["grep", "-E", "^(PRETTY_NAME)=", "/etc/os-release"], stdout=subprocess.PIPE, text=True) nice_name = os_release.stdout.strip().split('=')[1].strip('"') print(f"OS: {nice_name}")Das ist aber viel zu kompliziert und dieses Konzept der Daten-Erfassung werden wir uns zu einem späteren Zeitpunkt anschauen.
Es gibt ein Python-Modul, das es relativ einfach macht, den os-release auszulesen.
distro
Sollte auf Eurem Debian/Ubuntu-Derivat das Paket nicht installiert sein:
sudo apt install python3-distroWir wollen also den Pretty-Name und den bekommen wir so:
import distro pretty_name = distro.name(pretty=True) print("Pretty Name:", pretty_name)>>> Pretty Name: Ubuntu 24.04 LTS (In meinem Fall)
Logik
- distro ist das Modul
- name die Methode
- mit distro.name greifen wir darauf zu.
- distro.name(pretty=True)
Ohne pretty=True würde das so aussehen:
import distro pretty_name = distro.name() print("Pretty Name:", pretty_name)>>> Pretty Name: Ubuntu
Ganz ausführlich wäre:
import distro print(f"Pretty Name: {distro.name(pretty=True)}") print(f"Name: {distro.name()}") print(f"Version: {distro.version()}") print(f"ID: {distro.id()}") print(f"Alles: {distro.info()}")Das Modul in unseren Code einbauen
Ihr bekommt jetzt eine kleine Denkaufgabe:
- distro importieren
- die Variable os_release_pretty setzen
- os_release_pretty in den Text von os_label einbauen
Der Ganze Code
## Teil 5 ### import tkinter as tk from PIL import Image, ImageTk import os import socket import distro user = os.getlogin() hostname = socket.gethostname() os_release_pretty = distro.name(pretty=True) # Erstelle das Hauptfenster root = tk.Tk() root.title("Neofetch-Tk") root.geometry("800x500") distro_logo = tk.PhotoImage(file="images/test.png") # Einen Frame Zeichen logo_frame = tk.Frame(root,background="yellow") logo_frame.pack(fill="both",expand=False,side='left',padx=10,pady=10) # Distro-Logo-Label distro_icon = tk.Label(logo_frame,text="DISTRO LOGO",image=distro_logo,background="yellow") distro_icon.pack(anchor=tk.NW) # Einen Frame Zeichen stat_frame = tk.Frame(root,background="cyan") stat_frame.pack(fill="both",expand=True,side='left',padx=10,pady=10) # Label mit Text USER@HOST user_host_label = tk.Label(stat_frame,text=f"{user}@{hostname}") user_host_label.pack(anchor=tk.NW) # Label mit Text OS: os_label = tk.Label(stat_frame,text=f"OS: {os_release_pretty}") os_label.pack(anchor=tk.NW) # Starte die Hauptschleife root.mainloop()Zum Abschluss
Ich habe schon ein paar Mal darauf hingewiesen, dass wir ab jetzt in Bug-Territorium kommen. Vorweg nehme ich schon einmal, dass es sein kann, dass z.B. auf MX-Linux in der OS-Zeile "GNU/Linux Debian 12" stehen könnte. Das ist aber nicht unser Fehler, sondern der Fehler der Distro-Entwickler. Es gibt die eine oder andere Distribution, die in os-release nicht ausreichend deklariert, wie denn nun deren Derivat heißt. Letztendlich helfen Schuldzuweisungen auch nicht weiter. Wir bekommen das aber hin.
Um so etwas zu umgehen, müssten wir noch zusätzliche Informationen einbinden. Ich gehe auch nur kurz darauf ein. Sagen wir, die Distro gibt den Wert Debian aus, wir aber auf MX unterwegs sind, können wir es etwas zurechtbasteln.
Beispiel: Wenn die Distro Debian ergibt und die Datei /bin/mx-tools existiert, soll os_release_pretty den Wert MX-Linux ausgeben. Das ist nicht unbedingt akkurat, denn wir wissen noch immer nicht, welche Versionsnummer und welchen Codenamen wir nutzen. Lass das erstmal sacken, mit diesen Mechaniken werden wir uns bald auseinandersetzen müssen.
Hausaufgabe
Sollte der OS-Output auf Eurem PC nicht Eurer Distro entsprechen, dann postet es doch mal unter dem Artikel. So können wir uns einen Überblick darüber machen, für welche Distros wir einen Workaround basteln müssen. Vielleicht findet sich ja in lsb_release etwas Brauchbares.
cat /etc/os-release cat /etc/lsb-releaseTo-Do (aus Rückmeldungen)
Distro-Sonder-Fälle
- Siduction: /etc/siduction-version
Get User Error
import os user = os.environ["USER"] # ODER: import pwd import os user = pwd.getpwuid(os.getuid()).pw_nameBis nächste Woche
GNU/Linux.ch ist ein Community-Projekt. Bei uns kannst du nicht nur mitlesen, sondern auch selbst aktiv werden. Wir freuen uns, wenn du mit uns über die Artikel in unseren Chat-Gruppen oder im Fediverse diskutierst. Auch du selbst kannst Autor werden. Reiche uns deinen Artikelvorschlag über das Formular auf unserer Webseite ein.