2008-10-28 16 views
145

Diese Frage habe ich mir schon länger gestellt, aber ich habe noch nie eine passende Lösung gefunden. Wenn ich ein Skript ausführe und mir einen IndexError übergebe, gibt python die Zeile, den Ort und die schnelle Beschreibung des Fehlers aus und wird beendet. Ist es möglich, pdb automatisch zu starten, wenn ein Fehler auftritt? Ich bin nicht dagegen, am Anfang der Datei eine zusätzliche Importanweisung zu haben, noch ein paar zusätzliche Zeilen Code. DieseAutomatisches Starten des Python-Debuggers bei Fehler

+3

Haben Sie überlegt, die Antwort zu ändern, die akzeptiert wird? – Joost

Antwort

88

Sie können traceback.print_exc verwenden, um den Traceback der Ausnahmen zu drucken. Dann sys.exc_info verwenden, um die Rückverfolgung zu extrahieren und schließlich rufen pdb.post_mortem mit dem Zurückverfolgungs

import pdb, traceback, sys 

def bombs(): 
    a = [] 
    print a[0] 

if __name__ == '__main__': 
    try: 
     bombs() 
    except: 
     type, value, tb = sys.exc_info() 
     traceback.print_exc() 
     pdb.post_mortem(tb) 

Wenn Sie eine interaktive Kommandozeile mit code.interact mit den Einheimischen des Rahmens beginnen soll, wo die Ausnahme stammen die Sie tun können

import traceback, sys, code 

def bombs(): 
    a = [] 
    print a[0] 

if __name__ == '__main__': 
    try: 
     bombs() 
    except: 
     type, value, tb = sys.exc_info() 
     traceback.print_exc() 
     last_frame = lambda tb=tb: last_frame(tb.tb_next) if tb.tb_next else tb 
     frame = last_frame().tb_frame 
     ns = dict(frame.f_globals) 
     ns.update(frame.f_locals) 
     code.interact(local=ns) 
+0

Die erste Lösung wird im [Python-Kochbuch] (http://code.activestate.com/recipes/65287-automatisch-start-the-debugger-on-an-exception/) weiter diskutiert. – dirkjot

+3

Warum sollte jemand Code bevorzugen? 'über' pdb', da letzteres auf ersteren auszudehnen scheint? –

+0

Ich habe die gleiche Frage? Warum würdest du "Code" bevorzugen? – ARH

29

ist nicht der Debugger, aber wahrscheinlich genauso nützlich (?)

Ich weiß, ich hörte Guido dies irgendwo in einer Rede erwähnen.

Ich habe gerade Python -? Überprüft, und wenn Sie den Befehl -i verwenden, können Sie interagieren, wo Ihr Skript gestoppt wurde.

So dieses Skript gegeben:

testlist = [1,2,3,4,5, 0] 

prev_i = None 
for i in testlist: 
    if not prev_i: 
     prev_i = i 
    else: 
     result = prev_i/i 

Sie diese Ausgabe erhalten können!

PS D:\> python -i debugtest.py 
Traceback (most recent call last): 
    File "debugtest.py", line 10, in <module> 
    result = prev_i/i 
ZeroDivisionError: integer division or modulo by zero 
>>> 
>>> 
>>> prev_i 
1 
>>> i 
0 
>>> 

Um ehrlich zu sein habe ich das nicht verwendet, aber ich sollte, scheint sehr nützlich.

+0

Leicht, aber oft genau das, was benötigt wird – Casebash

+2

Nicht annähernd so nützlich, startet in den globalen Anwendungsbereich. Kann nicht herumstochern in welcher Funktion auch immer abgestürzt ist. – pixelpax

50

Verwenden sie das folgende Modul:

import sys 

def info(type, value, tb): 
    if hasattr(sys, 'ps1') or not sys.stderr.isatty(): 
    # we are in interactive mode or we don't have a tty-like 
    # device, so we call the default hook 
     sys.__excepthook__(type, value, tb) 
    else: 
     import traceback, pdb 
     # we are NOT in interactive mode, print the exception... 
     traceback.print_exception(type, value, tb) 
     print 
     # ...then start the debugger in post-mortem mode. 
     # pdb.pm() # deprecated 
     pdb.post_mortem(tb) # more "modern" 

sys.excepthook = info 

Name it debug (oder was auch immer Sie mögen) und legen Sie es irgendwo in Ihrem Python-Pfad.

Fügen Sie jetzt am Anfang Ihres Skripts einfach import debug hinzu.

+0

Dies sollte die akzeptierte Antwort sein - es erfordert keine Änderung des bestehenden Codes oder alles in einem "try-catch", was nur hässlich IMO ist. – cyphar

266
python -m pdb -c continue myscript.py 

Wenn Sie die -c continue Flagge nicht bieten dann werden Sie brauchen ‚c‘ (für weiter) einzugeben, wenn die Ausführung beginnt. Dann wird es bis zum Fehlerpunkt laufen und dir Kontrolle geben. Als mentioned by eqzx ist dieses Flag eine neue Ergänzung in Python 3.2, daher ist die Eingabe von 'c' für frühere Python-Versionen erforderlich (siehe https://docs.python.org/3/library/pdb.html).

+1

Wow, danke! Wenn jetzt dieser erste Aufruf von PDB auch vermieden werden könnte, wären die Dinge perfekt. Irgendwelche Ideen? – flonk

+3

Danke für die Erwähnung der "_enter 'c'_" - ich normalerweise verwendet, um' r 'einzugeben (für "run"), gewöhnt man es von 'gdb'; und wenn Sie "r" in "pdb" eingeben, wird zwar ein Programm ausgeführt, es wird jedoch bei einem Fehler NICHT gestoppt (oder es wird kein backtrace generiert). habe mich verwirrt, bis ich das gelesen habe. Prost! – sdaau

+1

Ich habe deine Methode ausprobiert. Aber es scheint keine wirkliche Kontrolle wie die Überprüfung von Variablen zum Zeitpunkt des Fehlers zu bieten. Die einzige Option, die es zu bieten scheint, besteht darin, die Ausführung neu zu starten. –

5

Sie können diese Zeile im Code setzen:

import pdb ; pdb.set_trace() 

Weitere Informationen: Start the python debugger at any line

+3

Dies stoppt den Code und startet einen Debugger in der Zeile, in die Sie diesen Befehl setzen, nicht in der Zeile, in der eine Ausnahme aufgetreten ist. – dangonfast

28

IPython hat einen Befehl dieses Verhalten für Makeln: % pdb. Es tut genau das, was Sie beschrieben haben, vielleicht sogar ein bisschen mehr (Sie erhalten mehr informative Backtraces mit Syntax-Highlighting und Code-Vervollständigung). Es ist definitiv einen Versuch wert!

+0

Und das ist die einzig vernünftige Antwort darauf. – Michael

+3

Dokumentiert unter http://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-pdb – matthiash

+2

Beachten Sie, dass - wie auch in der verknüpften Dokumentation @matthiash vermerkt - '% debug 'das Öffnen erlaubt der Debugger _nach_ einem Fehler auftritt. Ich bevorzuge das oft über '% pdb'. (Der Kompromiss besteht darin, jedes Mal, wenn Sie nicht versuchen, einen Fehler zu debuggen oder '% debug ', jedes Mal, wenn Sie einen Fehler debuggen wollen,' q' einzugeben.) –

0

Setzen Sie einen Haltepunkt innerhalb des Konstruktors der obersten Ausnahmeklasse in der Hierarchie, und die meisten Male sehen Sie, wo der Fehler ausgelöst wurde.

ein Unterbrechungsmittel Putting was auch immer Sie es bedeuten soll: Sie eine IDE verwenden können, oder pdb.set_trace, oder was auch immer

3

Um es laufen, ohne c am Anfang Verwendung eingeben zu müssen:

python -m pdb -c c <script name> 

Pdb hat seine eigenen Befehlszeilenargumente: -cc führt beim Start der Ausführung den Befehl c (ontinue) aus, und das Programm läuft bis zum Fehler ununterbrochen.

14

IPython macht diese einfache auf der Kommandozeile:

python myscript.py arg1 arg2 

kann

ipython --pdb myscript.py -- arg1 arg2 

Oder ähnlich

neu geschrieben werden, wenn ein Modul anrufen:

python -m mymodule arg1 arg2 

kann neu geschrieben werden zu

ipython --pdb -m mymodule -- arg1 arg2 

Beachten Sie die --, um zu verhindern, dass IPython die Argumente des Skripts als seine eigenen liest.

Dies hat auch den Vorteil, den erweiterten IPython-Debugger (ipdb) anstelle von pdb aufzurufen.

0

Wenn Sie ein Modul ausgeführt werden:

python -m mymodule 

Und jetzt wollen Sie pdb eingeben, wenn eine Ausnahme auftritt, dies tun:

PYTHONPATH="." python -m pdb -c c mymodule/__main__.py 

(oder verlängern Ihre PYTHONPATH). Die PYTHONPATH wird benötigt, damit das Modul im Pfad gefunden wird, da Sie jetzt das Modul pdb ausführen.

2

Wenn Sie die IPython-Umgebung verwenden, können Sie einfach das% debug verwenden und die Shell bringt Sie zurück zur problematischen Zeile mit der ipdb-Umgebung für Inspektionen usw. Eine weitere Option ist die Verwendung des iPython magic% pdb, das macht das selbe.

2

python -m pdb script.py in python2.7 drücken Sie weiter, um zu starten und es wird auf den Fehler ausgeführt werden und brechen Sie dort zum debug.

Verwandte Themen