2017-01-04 4 views
0

Ich verwende Gphoto2, um Bilder auf einer DSLR zu machen. Basiert auf Bash-Befehle, habe ich versucht, subprocess.communicate zu verwenden, aber es friert ein, nachdem die Kamera ein Foto macht.Python Subprozess kommunizieren friert beim Lesen der Ausgabe

Wenn ich die gphoto2 --capture-image-and-download im Terminal versuche, dauert es weniger als 2 Sekunden. Ich arbeite an einem Raspberry Pi.

Code:

import subprocess 

class Wrapper(object): 

    def __init__(self, subprocess): 
     self._subprocess = subprocess 

    def call(self,cmd): 
     p = self._subprocess.Popen(cmd, shell=True, stdout=self._subprocess.PIPE, stderr=self._subprocess.PIPE) 
     out, err = p.communicate() 
     return p.returncode, out.rstrip(), err.rstrip() 


class Gphoto(Wrapper): 
    def __init__(self, subprocess): 
     Wrapper.__init__(self,subprocess) 
     self._CMD = 'gphoto2' 

    def captureImageAndDownload(self): 
     code, out, err = self.call(self._CMD + " --capture-image-and-download") 
     if code != 0: 
      raise Exception(err) 
     filename = None 
     for line in out.split('\n'): 
      if line.startswith('Saving file as '): 
       filename = line.split('Saving file as ')[1] 
     return filename 


def main(): 
    camera = Gphoto(subprocess) 

    filename = camera.captureImageAndDownload() 
    print(filname) 

if __name__ == "__main__": 
    main() 

Wenn ich beende ich diese:

Traceback (most recent call last): 
    File "test.py", line 39, in <module> 
    main() 
    File "test.py", line 35, in main 
    filename = camera.captureImageAndDownload() 
    File "test.py", line 22, in captureImageAndDownload 
    code, out, err = self.call(self._CMD + " --capture-image-and-download") 
    File "test.py", line 11, in call 
    out, err = p.communicate() 
    File "/usr/lib/python2.7/subprocess.py", line 799, in communicate 
    return self._communicate(input) 
    File "/usr/lib/python2.7/subprocess.py", line 1409, in _communicate 
    stdout, stderr = self._communicate_with_poll(input) 
    File "/usr/lib/python2.7/subprocess.py", line 1463, in _communicate_with_poll 
    ready = poller.poll() 
KeyboardInterrupt 

Irgendwelche Ideen?

+1

Zitat „Lesen von Daten von stdout und stderr, bis zum Ende -of-file ist erreicht. " - Wenn der Prozess nicht beendet wurde, bleibt er hängen und wartet auf die Eingabe. Sind Sie sicher, dass Ihr Prozess abgeschlossen ist? – Torxed

+0

Ich bin mir ziemlich sicher. Ich höre den Verschluss der Kamera und eine Datei wird erzeugt. Sobald ich es für mindestens 5 Minuten sitzen lasse aber immer noch einfriere ... Ich habe den Prozess in Terminal getestet und es funktioniert ohne weitere Eingabe. – Dennis

+0

Versuchen Sie etwas ähnliches stattdessen: https://gist.github.com/anonymous/0811f71ca0b290f2625c9ba768bd45fd – Torxed

Antwort

0

Basierend auf den obigen Ausführungen, hier ist, was wir uns ausgedacht haben. Der Anruf .communicate() hing das Programm, und zu meinem Verdacht war es, weil der ausgeführte Befehl nicht ordnungsgemäß beendet wurde.

Eine Sache, die Sie verwenden können, um dies zu umgehen, ist, den Prozess manuell abzufragen, wenn es fertig ist und die Ausgabe zu drucken, während Sie fortfahren.
Nun wurde der obige Text auf dem Telefon geschrieben, damit es nicht richtig formatiert wurde, aber hier ist ein Beispielcode, mit dem Sie die Ausgabe abfangen können, während Sie den Befehl manuell abfragen.

import subprocess 
from time import time 
class Wrapper(): 
    def call(self, cmd): 
     p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
     O = '' 
     E = '' 
     last = time() 
     while p.poll() is None: 
      if time() - last > 5: 
       print('Process is still running') 
       last = time() 
      tmp = p.stdout.read(1) 
      if tmp: 
       O += tmp 
      tmp = p.stderr.read(1) 
      if tmp: 
       E += tmp 
     ret = p.poll(), O+p.stdout.read(), E+p.stderr.read() # Catch remaining output 
     p.stdout.close() # Always close your file handles, or your OS might be pissed 
     p.stderr.close() 
     return ret 

Drei wichtige Dinge zu bemerken, shell=True mit möglicherweise schlecht, unsicher und schwierig sein.
Ich persönlich bevorzuge es, weil ich selten Benutzereingaben oder "unbekannte Variablen" handle, wenn ich Sachen ausführe. Aber ein paar Worte der Vorsicht - Niemals benutzen!

Zweitens ist, wenn Sie nicht brauchen, um Fehler und regelmäßige Ausgabe zu trennen, können Sie auch tun:

Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 

Es wird Ihnen eine weniger Datei-Handle zu kümmern.

Schließlich, IMMER leeren Sie die stdout/stderr Puffer, und schließen Sie sie immer. Diese zwei Dinge sind wichtig.
Wenn Sie sie nicht leeren, können sie selbst die Anwendung hängen, weil sie voll sind und Popen kann nicht mehr Daten in sie legen, so wird es auf Sie warten (im besten Fall), sie zu leeren.
Zweitens werden diese Dateizugriffsnummern nicht geschlossen, wodurch Ihr Betriebssystem möglicherweise keine Dateizugriffsnummern mehr öffnen kann (es gibt nur eine bestimmte Menge an gemeinsamen Dateizugriffsnummern, die ein Betriebssystem zu jeder Zeit geöffnet haben kann dein Betriebssystem für ein bisschen nutzlos).

(Anmerkung: Je nachdem, ob Sie verwenden Python2 oder 3, p.stdout.read() Sie geben könnte Bytes Daten zurück, O = '' sollte O = b'' statt etc sein meaning)

Verwandte Themen