Popen und stderr

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.
Antworten
FrankM
User
Beiträge: 26
Registriert: Dienstag 20. Juli 2021, 08:51

Mal wieder ein Problem, was mich fordert. Extrem fordert, da ich es vermutlich nicht verstehe... :x

Ich bastel an einem UI für Restic und setze dafür oft subprocess.run ein. Ein Beispiel

Code: Alles auswählen

                    process = subprocess.run(['ls',
                                            '-lha',
                                            mount_path],
                                            check=False,
                                            stdout=subprocess.PIPE,
                                            universal_newlines=True)

                    output = process.stdout
                    mainWin.widget.setPlainText(output)

                    self.statusBar().showMessage(mount_path)
Ok, das funktioniert sehr gut und man kann auch prima mit

Code: Alles auswählen

process.check.returncode()
den Fehlercode ausgeben usw. Nun habe ich eine Aufgabe, das Mounten einer Datensicherung, wo das mit subprocess.run nicht geht, da der Prozeß nicht beendet wird, sondern weiter läuft bis man ihn beendet.
Auch hier wieder mein Beispielcode

Code: Alles auswählen

                       # Create cmd
                        cmd = ['restic',
                            '-r',
                            backup_data[row].repository,
                            'mount',
                            mount_path]

                        pwd = backup_data[row].password.encode()

                        # We create the object, here with stdin and open the asynchronous subprocess
                        p1 = subprocess.Popen(cmd,stdin=subprocess.PIPE,stderr=subprocess.PIPE)
                        p1.stdin.write(pwd)
                        p1.stdin.close()
Man sieht, das ich ein abgefragtes PW mittels p1.stdin.wrtite(pwd) übergebe. Das funktioniert so weit alles, wie ich das brauche.
Aber, wenn man nun das Passwort falsch eingibt, möchte ich das bitte abfangen. Auf der Konsole taucht das hier auf

Code: Alles auswählen

Fatal: wrong password or no key found
Das wollte ich jetzt mit stderr irgendwie abfangen. Nach mehreren Stunden try & error, komme ich zu dem Schluss, ich bin da irgendwie auf dem Holzweg.
Ich vermute, da es sich um einen asynchronen(?) Prozess handelt, kann man so nicht auf die Daten zugreifen (reine Spekulation)

Ich würde mich freuen, wenn mir jemand einen Tipp geben könnte wie man das "richtig" löst.
FrankM
User
Beiträge: 26
Registriert: Dienstag 20. Juli 2021, 08:51

Manche Probleme muss man mal an die Seite legen und nach ein paar Tagen wieder ran ans Werk. Problem gelöst!

Für die interessierten Mitleser hier die Lösung.

Code: Alles auswählen

                        ## Create cmd
                        cmd = ['restic',
                            '-r',
                            backup_data[row].repository,
                            'mount',
                            mount_path]

                        # We create the object, here with stdin and open the asynchronous subprocess
                        p1 = subprocess.Popen(cmd,stdin=subprocess.PIPE, stderr=subprocess.PIPE)
                        
                        out, err = p1.communicate()

                        if err:
                            print("standard error of subprocess:")
                            print(err)
  
                        p1.stdin.write(pwd[0].encode())
                        p1.stdin.close()
Meine Erklärung ist folgende. Wenn ich mit p1.stdin.write das Passwort sende, wird der Prozess danach beendet und ich konnte die Fehlermeldungen gar nicht mehr abfangen.
Wenn ich das Passwort zum Schluss sende, dann geht es und ich kann die Fehlermeldung ordentlich verarbeiten und ausgeben. Ich denke, das das p1.stdin.close() eigentlich überflüssig ist.

Es würde mich freuen, wenn einer der Experten, meine Vermutung mit Wissen unterbauen würde. :wink:
FrankM
User
Beiträge: 26
Registriert: Dienstag 20. Juli 2021, 08:51

Da ich nicht editieren kann, kann bitte jemand den 2. Beitrag von mir löschen. Das ist falsch, mein Problem besteht immer noch.
Ist mir erst sehr spät gestern Abend aufgefallen. Danke!
FrankM
User
Beiträge: 26
Registriert: Dienstag 20. Juli 2021, 08:51

Ich habe jetzt eine Lösung gefunden und möchte das hier hinzufügen, falls es noch jemanden anderen interessiert.

Das ich die exakte Fehlermeldung abfangen kann, geht meiner Meinung nach nicht. Der Prozess läuft ja, er wird nicht beendet. Aber, man kann den Status des Prozesses abfragen.

Code: Alles auswählen

p.poll()
bekommt man ein None (Prozess läuft) oder 1 (Prozess ist abgebrochen worden, z.B. falsches Passwort). Und man muss noch etwas warten, da es auch ein Zeitproblem ist.
Problem gelöst.
Benutzeravatar
__blackjack__
User
Beiträge: 13241
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@FrankM: Kann es sein, dass Du eher `wait()` statt `poll()` verwenden willst‽
Please call it what it is: copyright infringement, not piracy. Piracy takes place in international waters, and involves one or more of theft, murder, rape and kidnapping. Making an unauthorized copy of a piece of software is not piracy, it is an infringement of a government-granted monopoly.
FrankM
User
Beiträge: 26
Registriert: Dienstag 20. Juli 2021, 08:51

Nein, das habe ich ausprobiert. Das blockiert mir den ganzen Prozess.

Aus der Doku
Popen.wait(timeout=None)

Wait for child process to terminate. Set and return returncode attribute.
Somit war der Weg über p.poll() der einzige, der in meinem Fall funktionierte. Der Prozess läuft in meinem Fall weiter, er wird nicht automatisch beendet. Erst später, wenn der User das möchte..
Antworten