2016-07-18 9 views
3

Ich möchte auf die Traceback eines Python-Programms in einem Subprozess zugreifen.Subprozess Kind Traceback

The documentation sagt:

Exceptions raised in the child process, before the new program has started to execute, will be re-raised in the parent. Additionally, the exception object will have one extra attribute called child_traceback, which is a string containing traceback information from the child’s point of view.

Inhalt von my_sub_program.py:

raise Exception("I am raised!") 

Inhalt von my_main_program.py:

import sys 
import subprocess 
try: 
    subprocess.check_output([sys.executable, "my_sub_program.py"]) 
except Exception as e: 
    print e.child_traceback 

Wenn ich my_main_program.py laufen, ich folgende Fehlermeldung erhalten:

Traceback (most recent call last): 
    File "my_main_program.py", line 6, in <module> 
    print e.child_traceback 
AttributeError: 'CalledProcessError' object has no attribute 'child_traceback' 

Wie kann ich auf die Traceback des Subprozesses zugreifen, ohne den Subprozess-Programmcode zu ändern? Das bedeutet, ich möchte vermeiden, dass eine große try/except Klausel um meinen gesamten Unterprogrammcode hinzugefügt wird, sondern vielmehr die Fehlerprotokollierung von meinem Hauptprogramm aus.

Edit:sys.executable sollte durch einen Interpreter ersetzt werden, der sich von dem unterscheidet, der das Hauptprogramm ausführt.

+0

Doc sagt "bevor das neue Programm gestartet wurde", in Ihrem Fall wurde die Ausnahme ausgelöst, während das neue Programm ausgeführt wurde, daher kein 'child_traceback'. Sobald das neue Programm ausgeführt wird, müssen Sie die "CalledProcessError" -Ausnahme abfangen und wie folgt vorgehen: http://StackOverflow.com/questions/24849998/how-to-catch-exception-output-from-python-subprocess-check -output using 'CalledProcessError.output' – mguijarr

+0

In meinem Beispiel hat 'CalledProcessError.output' nur die Standardausgabe erfasst, aber nicht die Rückverfolgung der Ausnahme. – schreon

+0

Dies liegt wahrscheinlich daran, dass die Ausgabe an 'stderr' gesendet wird. Sehen Sie sich die Antworten aus der Frage an, für die ich Ihnen den obigen Link gesendet habe, um weitere Informationen zu erhalten. – mguijarr

Antwort

0

Wenn Sie einen anderen Python-Prozess starten, können Sie auch versuchen, das multiprocessing Python-Modul zu verwenden; von Nebenklassen der Klasse Process es ganz einfach ist, Ausnahmen von der Zielfunktion zu erhalten:

from multiprocessing import Process, Pipe 
import traceback 
import functools 

class MyProcess(Process): 
    def __init__(self, *args, **kwargs): 
     Process.__init__(self, *args, **kwargs) 
     self._pconn, self._cconn = Pipe() 
     self._exception = None 

    def run(self): 
     try: 
      Process.run(self) 
      self._cconn.send(None) 
     except Exception as e: 
      tb = traceback.format_exc() 
      self._cconn.send((e, tb)) 
      # raise e # You can still rise this exception if you need to 

    @property 
    def exception(self): 
     if self._pconn.poll(): 
      self._exception = self._pconn.recv() 
     return self._exception 


p = MyProcess(target=functools.partial(execfile, "my_sub_program.py")) 
p.start() 
p.join() #wait for sub-process to end 

if p.exception: 
    error, traceback = p.exception 
    print 'you got', traceback 

Der Trick besteht darin, die Zielfunktion die Ausführung des Python Unterprogramm zu haben, wird dies durch den Einsatz functools.partial getan.

+0

Ermöglicht diese Lösung, dass der Unterprozess in einem anderen Interpreter als dem Hauptprogramm ausgeführt wird? Wie ich Ihren Vorschlag sehe, stelle ich fest, dass es irreführend war, 'sys.executable' in meinem Beispiel zu verwenden. Im Zusammenhang mit meiner Frage muss ich jedoch Skripts in einer anderen virtuellen Umgebung als dem Hauptprozess starten. (Der Hauptprozess wird eine Art Scheduler sein) – schreon

+0

Eigentlich 'Multiprocessing' macht' os.fork' auf POSIX-Plattformen, also ist es keine neue virtuelle Umgebung; Sie können jedoch die Anzahl der geteilten Daten zwischen den Prozessen begrenzen, indem Sie die 'Process'-Objekte frühzeitig starten. Dies ist vielleicht ausreichend für Ihre Bedürfnisse. – mguijarr

+0

Wenn Sie eine Art Scheduler machen, verwenden Sie etwas wie [Sellerie] (http://www.celeryproject.org/) – mguijarr