Labeldruck und was draus folgt

Du hast eine Idee für ein Projekt?
theoS
User
Beiträge: 108
Registriert: Dienstag 5. November 2019, 21:44

Hab nun Zeit gehabt, den Code durchzuschauen. So ganz erschließt sich der Vorteil von map() für mich nicht. Hab gelesen, dass das elegant sein soll, aber den Vorteil daraus? Ist für mich eher verwirrend als logisch.
Aber egal, das funktioniert, und da es elegant sein soll, warum nicht? Wieder was neues kennengelernt.

Den Logger heb ich mir für später auf, der ist mir ein wenig zu redselig. Ich brauch ja nur immer das Zwischenergbnis für mich, dass ich weiß was der Code da tut.
Aber ich sehe schon, dass das noch nützlich werden kann...
Danke für die Tipps!
Den Teil des Codes habe ich nun in mein USB-Überwachungsteil eingebaut, das jetzt so wie ich es jetzt hab, die beiden Dateiinhalte austauscht, wie es das soll.
Gibt bestimmt was zu verbessern. :o)

Code: Alles auswählen

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from pathlib import Path
import pyudev
import time
import pathlib
from datetime import datetime as DateTime
###---------------------------------------------------
PFAD = Path.home() / ".DruckData"
##ABFRAGE_FILENAME = PFAD / "TB_Ausgabe_Abfrage8StueckII.txt"
##ZAEHLER_FILENAME = PFAD / "numbers.csv"
###----------------------------------------------------
MEDIA_PFAD = Path('/media/earl/')
WECHSEL_DATEI_NAMEN = ["numbers.csv", "TB_Ausgabe_8iii.txt"]
print(MEDIA_PFAD)
context = pyudev.Context()
def usb_ansteckerkenner():
    monitor = pyudev.Monitor.from_netlink(context)
    monitor.filter_by('block')
    for device in iter(monitor.poll, None):
        if 'ID_FS_TYPE' in device: ###
            
            print(device.action)
            if device.action == 'add':
                
                name_of_stick = Path(device.get('ID_FS_LABEL'))
                print(name_of_stick)
                time.sleep(2)
                
                return name_of_stick
           
####--------------------------------------------------------------------#####

def copy(source_path, destination_path):    
    try:
        text = source_path.read_text(encoding="utf-8")        
        destination_path.write_text(text, encoding="utf-8")
    except FileNotFoundError as error:
        print(error)
           
####--------------------------------------------------------------------#####

def datei_auf_stick(name_of_stick, dateipfad, timestamp):    
    copy(
        PFAD / dateipfad,
        MEDIA_PFAD
        / name_of_stick
        / dateipfad.with_name(
            f"{dateipfad.stem}_{timestamp:%Y-%m-%d_%H_%M}.csv"
        ),
    )
           
####--------------------------------------------------------------------#####

def datei_auf_arbeitsverzeichnis(name_of_stick, dateipfad):
    copy(MEDIA_PFAD / name_of_stick / dateipfad, PFAD / dateipfad)

           
####--------------------------------------------------------------------#####

def main():
    timestamp = DateTime.now()
    name_of_stick = usb_ansteckerkenner()
    
    for dateiname in map(Path, WECHSEL_DATEI_NAMEN):  
        datei_auf_stick(name_of_stick, dateiname, timestamp)
        datei_auf_arbeitsverzeichnis(name_of_stick, dateiname)
    

if __name__ == "__main__":
    main()        
Nächster Schritt: Fehlerabfangen...
Wenn die Datei nicht da ist, soll da eine kleine Box aufgehen, die knapp drüber informiert, dass da mit den Dateien was nicht passt.
Die Box soll über den Knöpfen des anderen Codeteils liegen und nichts anderes machen als den stick zu unmounten.
Grübel...
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

Da hat es jetzt noch so Zeilen mit vielen Minuszeichen, die den Lesefluß stören. Funktionen trennt man mit zwei Leerzeilen.
theoS
User
Beiträge: 108
Registriert: Dienstag 5. November 2019, 21:44

Danke, die kommen noch raus, das brauch ich im Moment noch um die Trennung zu sehen.
Bin schon ein alter Mann :)
theoS
User
Beiträge: 108
Registriert: Dienstag 5. November 2019, 21:44

Zum Auswerfen des Sticks kann ich so was verwenden.

Code: Alles auswählen

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from pathlib import Path
import subprocess

MEDIA_PFAD = Path("/media/earl/")
def main():
    vpath = MEDIA_PFAD  / "SEAGULL"
    print(vpath)
    cmd = 'umount ' + str(vpath)
    print(cmd)
    subprocess.Popen(str(cmd), shell=True, stdout=subprocess.PIPE)

if __name__ == "__main__":
    main() 
wobei mich da irritiert, dass ich das Path-Objekt in einen String umwandeln muss, aber das muss wohl so sein weil ich das ja an die Shell durchreiche.
Gibts da noch was besseres?
__deets__
User
Beiträge: 14536
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ja, subprocess ohne Shell=True und mit einer Liste statt einem String - dann muss auch kein path konvertiert werden.
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

statt `Popen` benutzt man `run` und statt `shell=True` eine Liste.

Code: Alles auswählen

MEDIA_PFAD = Path("/media/earl/")

def main():
    umount_result = subprocess.run(["umount", MEDIA_PFAD / "SEAGULL"], check=True, stdout=subprocess.PIPE)
    print(umount_result.stdout)

if __name__ == "__main__":
    main()
theoS
User
Beiträge: 108
Registriert: Dienstag 5. November 2019, 21:44

OK, danke. Das funktioniert.
Hab das jetzt in die USB-Ansteckgeschichte oben eingebaut, der Stick wir ausgehängt, allerdings stoppt dann das ganze Programm. Klar, krieg ich hier eine Fehlermeldung weil die Datei nicht da ist, aber das Programm stoppt jetzt auch bei Erfolg.
Das ist doof.
Muss man das so machen wie bei der tkinter-Oberfläche? mit root.mainloop()?
Dann würde das funktionieren wenn ich die Teile dann mit der grafischen Oberfläche vereine?

Dann noch eine Frage.
Bin von VBA das so gewohnt, dass wenn ich eine Variable hab, die ich so oft in gleicher Weise brauch wie hier den name_of_stick, dann deklariere ich den Global und kann dann in jedem Modul drauf zugreifen. Soll schlechter Stil sein, aber wäre das hier nicht geschickter als die x Übergaben? (man wird in VBA zum Faulpelz erzogen...)

Code: Alles auswählen

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from pathlib import Path
import pyudev
import time
#import pathlib
from datetime import datetime as DateTime
import subprocess

PFAD = Path.home() / ".DruckData"
###----wird später gebraucht------
##ABFRAGE_FILENAME = PFAD / "TB_Ausgabe_Abfrage8StueckII.txt"
##ZAEHLER_FILENAME = PFAD / "numbers.csv"
###------------------------------

MEDIA_PFAD = Path('/media/earl/')
WECHSEL_DATEI_NAMEN = ["numbers.csv", "TB_Ausgabe_8iii.txt"]
print(MEDIA_PFAD)
context = pyudev.Context()
def usb_ansteckerkenner():
    monitor = pyudev.Monitor.from_netlink(context)
    monitor.filter_by('block')
    for device in iter(monitor.poll, None):
        if 'ID_FS_TYPE' in device: ###
            
            print(device.action)
            if device.action == 'add':
                
                name_of_stick = Path(device.get('ID_FS_LABEL'))
                print(name_of_stick)
                time.sleep(2)
                
                return name_of_stick
           

def copy(name_of_stick, source_path, destination_path ):    
    try:
        text = source_path.read_text(encoding="utf-8")        
        destination_path.write_text(text, encoding="utf-8")
    except FileNotFoundError as error:
        rauswerfer(name_of_stick)
        print(error)
           

def datei_auf_stick(name_of_stick, dateipfad, timestamp):    
    copy(name_of_stick,   
        PFAD / dateipfad,
        MEDIA_PFAD
        / name_of_stick
        / dateipfad.with_name(
            f"{dateipfad.stem}_{timestamp:%Y-%m-%d_%H_%M}.csv"
        ),
                
    )
           

def datei_auf_arbeitsverzeichnis(name_of_stick, dateipfad):
    copy(name_of_stick, MEDIA_PFAD / name_of_stick / dateipfad, PFAD / dateipfad)

  
def rauswerfer(name_of_stick):
    print(name_of_stick)
    umount_result = subprocess.run(["umount", MEDIA_PFAD / name_of_stick], check=True, stdout=subprocess.PIPE)
    print(umount_result.stdout)
         

def main():
    timestamp = DateTime.now()
    name_of_stick = usb_ansteckerkenner()
    
    for dateiname in map(Path, WECHSEL_DATEI_NAMEN):  
        datei_auf_stick(name_of_stick, dateiname, timestamp)
        datei_auf_arbeitsverzeichnis(name_of_stick, dateiname)
    

if __name__ == "__main__":
    main()        
theoS
User
Beiträge: 108
Registriert: Dienstag 5. November 2019, 21:44

Gut, ich habe jetzt mal was probiert, das scheint zu funktionieren.
Dachte mir, wenn das dann in der Fehlerbehandlung abbricht, rufe ich einfach die main() noch mal auf, dann läuft die wieder...
Also meinen "rauswerfer" eine Zeile dazu.

Code: Alles auswählen

def rauswerfer(name_of_stick):
    print(name_of_stick)
    umount_result = subprocess.run(["umount", MEDIA_PFAD / name_of_stick], check=True, stdout=subprocess.PIPE)
    print(umount_result.stdout)
    main()
Das geht, aber ob das so gut ist?
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

Das ist nicht gut. Ich weiß auch gar nicht genau, was denn Dein Problem mit dem Code oben ist. Du hast gar keine Schleife, also kann das auch nicht dauerhaft laufen.
theoS
User
Beiträge: 108
Registriert: Dienstag 5. November 2019, 21:44

Das läuft sonst weiter, wenn kein Fehler auftritt. Die Überwachung des USB läuft auch wenn das kopieren klappt. Nur wenn ein Fehler auftritt geht das nicht mehr weiter. Wenn ich main aufrufe danach geht's weiter
__deets__
User
Beiträge: 14536
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das ist wirklich wirklich nicht richtig. main sollte genau *einmal* aufgerufen werden. Und in main sollten Dinge stehen, die man auch garantiert nur einmal machen will und kann. Wenn nicht, dann hast du da noch Code an anderen Stellen rumfliegen, wo er nicht hingehoert. Edit: (Wie waere es mal mit einem Gesamtbild, nicht nur Ausschnitten?) - hast du ja geliefert, ich schaue mir das mal an.
__deets__
User
Beiträge: 14536
Registriert: Mittwoch 14. Oktober 2015, 14:29

So, das ist ja auch kein Wunder, dass main wieder aufrufen das Problem loest. Man muss etwas, dass man andauernd machen will, auch andauernd machen. Nicht nur einmal, und sich dann rekursiv selbst aufrufen. So in etwa:

Code: Alles auswählen

from pathlib import Path
import pyudev
import time
#import pathlib
from datetime import datetime as DateTime
import subprocess

PFAD = Path.home() / ".DruckData"
###----wird später gebraucht------
##ABFRAGE_FILENAME = PFAD / "TB_Ausgabe_Abfrage8StueckII.txt"
##ZAEHLER_FILENAME = PFAD / "numbers.csv"
###------------------------------

MEDIA_PFAD = Path('/media/earl/')
WECHSEL_DATEI_NAMEN = ["numbers.csv", "TB_Ausgabe_8iii.txt"]
print(MEDIA_PFAD)


def usb_ansteckerkenner(context):
    monitor = pyudev.Monitor.from_netlink(context)
    monitor.filter_by('block')
    for device in iter(monitor.poll, None):
        if 'ID_FS_TYPE' in device:  ###

            print(device.action)
            if device.action == 'add':

                name_of_stick = Path(device.get('ID_FS_LABEL'))
                print(name_of_stick)
                time.sleep(2)

                return name_of_stick


def copy(name_of_stick, source_path, destination_path ):
    try:
        text = source_path.read_text(encoding="utf-8")
        destination_path.write_text(text, encoding="utf-8")
    except FileNotFoundError as error:
        rauswerfer(name_of_stick)
        print(error)


def datei_auf_stick(name_of_stick, dateipfad, timestamp):
    copy(name_of_stick,
        PFAD / dateipfad,
        MEDIA_PFAD
        / name_of_stick
        / dateipfad.with_name(
            f"{dateipfad.stem}_{timestamp:%Y-%m-%d_%H_%M}.csv"
        ),

    )


def datei_auf_arbeitsverzeichnis(name_of_stick, dateipfad):
    copy(name_of_stick, MEDIA_PFAD / name_of_stick / dateipfad, PFAD / dateipfad)


def rauswerfer(name_of_stick):
    print(name_of_stick)
    umount_result = subprocess.run(["umount", MEDIA_PFAD / name_of_stick], check=True, stdout=subprocess.PIPE)
    print(umount_result.stdout)


def main():
    context = pyudev.Context()

    while True:
        timestamp = DateTime.now()
        name_of_stick = usb_ansteckerkenner(context)

        for dateiname in map(Path, WECHSEL_DATEI_NAMEN):
            datei_auf_stick(name_of_stick, dateiname, timestamp)
            datei_auf_arbeitsverzeichnis(name_of_stick, dateiname)


if __name__ == "__main__":
    main()
theoS
User
Beiträge: 108
Registriert: Dienstag 5. November 2019, 21:44

Muss ich mal ausprobieren. Komisch ist dann aber, dass das mit dem überwachen vom USB port funktioniert. Das läuft weiter wenn ich den Stick einstecke und auswerfe, wird mir das beim nächsten Einstecken wieder angezeigt. Das läuft also doch weiter, sonst würde das doch nur einmal angezeigt.
Das mit der Schleife ist sicher sicherer, oder? Also lag ich mit meiner Annahme so “eine Art root.mainloop()“ gar nicht so verkehrt.
__deets__
User
Beiträge: 14536
Registriert: Mittwoch 14. Oktober 2015, 14:29

Was du mit dem weiterlaufen meinst weiss ich nicht. Bezueglich des "sicherer" - jein. Es ist richtiger. Oder besser "nicht falsch". Denn man benutzt in Python keine Rekursion fuer Schleifen, und vor allem ist der Programmfluss bei deiner "Loesung" kompletter Wahnsinn, und nie wieder zu verstehen. Falls man ihn je verstanden hat.
theoS
User
Beiträge: 108
Registriert: Dienstag 5. November 2019, 21:44

Mit weiter laufen meine ich, dass das Progg immer erkennt ob ein Stick eingesteckt wird oder nicht.
Wenn die Dateien dann da sind, klappt das hin und herkopieren einwandfrei. Vereinfacht, wenn ich mir nur die Aktion anzeigen lasse, kann ich den Stick 100 mal rein und wieder rausmachen, es wird immer die Aktion angezeigt.
Daraus schließe ich nach wie vor, dass das Programm “weiterläuft“.
Da es stoppt, wenn ein Fehler kommt bin ich halt auf die Idee gekommenen das Ganze neu zu starten. Für mich ist das schon logisch, ahnte aber dass das sicher wieder nicht pythonlike ist.
Oder wo anders Murks erzeugt.
theoS
User
Beiträge: 108
Registriert: Dienstag 5. November 2019, 21:44

@__deets__ Leider geht das so nicht.
Wieder kommt die Fehlermeldung und Schluss ist mit dem Programm. Das, und dann noch auf 2 verschiedene Weisen.
Also, Fall 1, numbers.csv ist auf Stick vorhanden, TB_Ausgabe_8ii.txt fehlt:

Code: Alles auswählen

================= RESTART: /home/earl/projekt/USB/usb.iix.py =================
/media/earl
add
SEAGULL
SEAGULL
b''
[Errno 2] No such file or directory: '/media/earl/SEAGULL/TB_Ausgabe_8iii.txt'
remove

Der Code stoppt aber hier, sprich, ich kann den Stick rein oder raus nehmen, egal, es kommt keine Reaktion mehr. (add oder remove sollte ja in jedem Fall so angezeigt werden wenn sich da was tut)

Dann der Fall, wenn die numbers.csv einen anderen Namen hat, die zweite Datei aber da ist:

Code: Alles auswählen

================= RESTART: /home/earl/projekt/USB/usb.iix.py =================
/media/earl
add
SEAGULL
SEAGULL
b''
[Errno 2] No such file or directory: '/media/earl/SEAGULL/numbers.csv'
SEAGULL
Traceback (most recent call last):
  File "/home/earl/projekt/USB/usb.iix.py", line 38, in copy
    destination_path.write_text(text, encoding="utf-8")
  File "/usr/lib/python3.6/pathlib.py", line 1215, in write_text
    with self.open(mode='w', encoding=encoding, errors=errors) as f:
  File "/usr/lib/python3.6/pathlib.py", line 1183, in open
    opener=self._opener)
  File "/usr/lib/python3.6/pathlib.py", line 1037, in _opener
    return self._accessor.open(self, flags, mode)
  File "/usr/lib/python3.6/pathlib.py", line 387, in wrapped
    return strfunc(str(pathobj), *args)
FileNotFoundError: [Errno 2] No such file or directory: '/media/earl/SEAGULL/TB_Ausgabe_8iii_2020-03-29_17_08.csv'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/earl/projekt/USB/usb.iix.py", line 79, in <module>
    main()
  File "/home/earl/projekt/USB/usb.iix.py", line 74, in main
    datei_auf_stick(name_of_stick, dateiname, timestamp)
  File "/home/earl/projekt/USB/usb.iix.py", line 50, in datei_auf_stick
    f"{dateipfad.stem}_{timestamp:%Y-%m-%d_%H_%M}.csv"
  File "/home/earl/projekt/USB/usb.iix.py", line 40, in copy
    rauswerfer(name_of_stick)
  File "/home/earl/projekt/USB/usb.iix.py", line 62, in rauswerfer
    umount_result = subprocess.run(["umount", MEDIA_PFAD / name_of_stick], check=True, stdout=subprocess.PIPE)
  File "/usr/lib/python3.6/subprocess.py", line 438, in run
    output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '['umount', PosixPath('/media/earl/SEAGULL')]' returned non-zero exit status 1.
>>> 
Hier versucht das Programm dann, wenn ich das so richtig lese, den Stick z um zweiten Mal auszuhängen, was natürlich nicht geht.

In beiden Fällen geht es aber danach nicht mehr weiter. Sprich, das Prog stoppt komplett.
Wie soll ich das nu wieder lösen?
Wenn ich main() nicht mehr aufrufen darf, das auslagern in eine eigene Funktion?
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

Du hast hier eine Exception, die Du abfangen mußt, und dann sinnvoll drauf reagieren.
theoS
User
Beiträge: 108
Registriert: Dienstag 5. November 2019, 21:44

@Sirius3
Yep, das weiß ich. Mein Problem: Wie?
Es muss ja so sein, dass es egal ist, welche Exception da ist. Der Stick soll ausgehängt werden und das Programm weiterlaufen. Die erste Exception wird aber schon durch das Aushängen erledigt, also gibts dann logischerweise eine zweite die aus dem Fehlen des Sticks erzeugt wird.
Selbst wenn ich beides irgendwie abfange, geht das so nicht weiter, denn dieses Teil hier: context = pyudev.Context() wird ja nicht mehr ausgeführt.
Das ist das was ich immer meine mit "das Programm bleibt stehen.
Durch das, dass ich das Ding aus main() übergebe, ist es ja, wenn ich main nicht noch mal starte nicht da.
Meine Idee dazu: Ich mache das Ding global. Dann ist es immer da, wie es ja auch sein soll.
Schlechte Idee?
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

Es zeigt sich hier, dass keine gute Idee ist, wenn eine Datei nicht gefunden wurde, zu vermuten, dass es dann sinnvoll sein kann, umount aufzurufen.
Natürlich kannst Du einfach check=False setzen, dann ignorierst Du den nächsten Fehler, bis wieder etwas passiert, was Du nicht verstehst, und dann ignorierst Du das wieder, bis Du ein Programm hast, das nur deshalb „funktioniert“, weil Du einen Fehler nach dem anderen ignorierst.
theoS
User
Beiträge: 108
Registriert: Dienstag 5. November 2019, 21:44

Es zeigt sich hier, dass keine gute Idee ist, wenn eine Datei nicht gefunden wurde, zu vermuten, dass es dann sinnvoll sein kann, umount aufzurufen.
Das ist jetzt schön einfach dahingesagt. Was hast du denn alternativ für eine Idee?
Wenn eine der Dateien nicht drauf ist, soll das Programm eigentlich nichts anderes mehr tun als:
1. Den Stick auszuwerfen
2. Den Rest, insbesondere das darauf Warten, dass die neuen Dateien kommen, weiter auszuführen.

Das Programm kopiert frisch und fröhlich die Dateien die da sind - soll es eigentlich auch schon nicht, aber ist egal - und bei der Ausnahme die entsteht weil eine Datei nicht da ist, bricht es, wenn ich die so abfange wie vorgeschlagen die weitere Ausführung komplett ab.
Mir fehlt da jetzt die Phantasie, das noch irgendwie auszuwerten und dann von Fehler zu Fehler zu kommen den ich dann doch nicht vorhersehen kann um dann festzustellen: Ich als armes Programm hab jetzt tausend Sachen probiert, kann leider nicht alles tun, also werfe ich den Stick aus.
Da war meine Überlegung: Fehlt was, passiert (außer einer Meldung die noch zu machen ist) nichts anderes als dass der Stick ausgeworfen wird. Das Andere läuft inzwischen weiter, und zwar auch dann, wenn die Dateien da sind.
Wie soll ich das veranstalten?
Antworten