Avvio del debugger python automaticamente in caso di errore


217

Questa è una domanda che mi chiedevo da un po 'di tempo, eppure non ho mai trovato una soluzione adatta. Se eseguo uno script e mi imbatto in, diciamo un IndexError, Python stampa la riga, la posizione e la rapida descrizione dell'errore ed esce. È possibile avviare automaticamente pdb quando si verifica un errore? Non sono contrario ad avere un'istruzione di importazione aggiuntiva nella parte superiore del file, né alcune righe di codice aggiuntive.


12
Hai pensato di cambiare la risposta accettata?
Joost,

Risposte:


127

È possibile utilizzare traceback.print_exc per stampare il traceback delle eccezioni. Quindi utilizzare sys.exc_info per estrarre il traceback e infine chiamare pdb.post_mortem con quel traceback

import pdb, traceback, sys

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

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

Se si desidera avviare una riga di comando interattiva con code.interact utilizzando i locali del frame in cui è stata generata l'eccezione, è possibile eseguire

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)

la prima soluzione è ulteriormente discussa nel ricettario di Python
dirkjot,

3
perché qualcuno dovrebbe preferire coderispetto a pdbquando il secondo sembra espandersi sul primo?
K3 --- rnc,

Ho la stessa domanda? Perché preferiresti code?
ARH,

2
Quindi utilizzare sys.exc_infoper estrarre il traceback e infine chiamare pdb.post_mortemcon quel traceback . Non è necessario passare l'oggetto traceback a pdb.post_mortem. Dai documenti : se non viene fornito alcun traceback, utilizza quella dell'eccezione attualmente gestita (se si utilizza il valore predefinito è necessario gestire un'eccezione).
Piotr Dobrogost,

2
@PiotrDobrogost Un buon punto. Penso che sia più utile sapere che puoi passare un oggetto tb in, poiché dimostra meglio l'API. Buono a sapersi che entrambe le opzioni esistono.
davidA

456
python -m pdb -c continue myscript.py

Se non fornisci il -c continueflag, dovrai inserire 'c' (per Continua) quando inizia l'esecuzione. Quindi verrà eseguito al punto di errore e ti darà il controllo lì. Come menzionato da eqzx , questo flag è una nuova aggiunta in Python 3.2, pertanto è necessario inserire 'c' per le versioni precedenti di Python (consultare https://docs.python.org/3/library/pdb.html ).


5
Grazie per aver menzionato " enter 'c' " - In genere inserivo 'r' (per "run"), essendo stato usato da esso gdb; e quando si inserisce 'r' in pdb, il programma viene effettivamente eseguito, ma NON si arresta (né genera backtrace) in caso di errore; mi ha lasciato perplesso fino a quando non ho letto questo. Saluti!
sdaau,

3
Vineet, ti avvierà con il debugger attivo, quindi inserisci "cont" e funzionerà fino a quando non si verifica l'errore. Da lì puoi controllare le variabili, ecc. Come in qualsiasi altra sessione pdb.
Catherine Devlin,

40
Si prega di OP, accettarlo come risposta. Questo è il più utile e ho perso 5 minuti a leggere gli altri fino a quando non ho colpito questo ... questo dovrebbe essere il primo!
jhegedus,

4
Questo funziona anche con ipdb; e ovviamente gli argomenti possono essere aggiunti dopo lo script!
tutuDajuju,

20
Questo non funziona con Python 2.7. docs.python.org/3/library/pdb.html : "Novità nella versione 3.2: pdb.py ora accetta un'opzione -c che esegue i comandi"
eqzx

68

Utilizzare il seguente modulo:

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

Dagli un nome debug(o come preferisci) e mettilo da qualche parte nel tuo percorso Python.

Ora, all'inizio del tuo script, aggiungi semplicemente un import debug.


2
Questa dovrebbe essere la risposta accettata: non richiede alcuna modifica del codice esistente o il wrapping di tutto in un try-catchIMO semplicemente brutto.
cipriota,

Mi piace questa risposta piuttosto di frequente, ma preferisco pudbsopra pdb. Continua a tornare a copiare e incollare, che sicuramente dice qualcosa sulla mancanza di ordine nella mia vita.
Stabledog,

47

Ipython ha un comando per attivare questo comportamento: % pdb . Fa esattamente quello che hai descritto, forse anche un po 'di più (dandoti backtrace più informativi con evidenziazione della sintassi e completamento del codice). Vale sicuramente la pena provare!


3
E questa è l'unica risposta ragionevole a questo.
Michael


4
Si noti che - come indicato anche nei documenti @matthiash collegati - %debugconsente di aprire il debugger dopo aver riscontrato un errore. Preferisco spesso questo %pdb. (Il compromesso sta semplicemente digitando qogni volta che non si desidera eseguire il debug di un errore anziché digitando %debugogni volta che si desidera eseguire il debug di un errore.)
Braham Snyder,

1
Nota anche che l'impostazione c.InteractiveShell.pdb = Truesi ipython_config.pyaccende %pdbautomaticamente per ogni sessione.
Braham Snyder,

33

Questo non è il debugger, ma probabilmente altrettanto utile (?)

So di aver sentito Guido menzionarlo in un discorso da qualche parte.

Ho appena controllato Python - ?, e se usi il comando -i puoi interagire dove il tuo script si è fermato.

Quindi dato questo script:

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

Puoi ottenere questo risultato!

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
>>>

Ad essere sincero non l'ho usato, ma dovrei esserlo, mi sembra molto utile.


Leggero, ma spesso proprio quello che serve
Casebash,

8
Non altrettanto utile, si lancia in ambito globale. Non riesco a curiosare in qualunque funzione si sia schiantata.
pixelpax,

21

IPython lo rende semplice sulla riga di comando:

python myscript.py arg1 arg2

può essere riscritto in

ipython --pdb myscript.py -- arg1 arg2

O, allo stesso modo, se si chiama un modulo:

python -m mymodule arg1 arg2

può essere riscritto in

ipython --pdb -m mymodule -- arg1 arg2

Notare che --per impedire a IPython di leggere gli argomenti dello script come propri.

Ciò ha anche il vantaggio di invocare il debugger IPython avanzato (ipdb) anziché pdb.


10

Se si sta utilizzando ipython, dopo aver avviato il tipo%pdb

In [1]: %pdb
Automatic pdb calling has been turned ON

Giove per esempio
Blaztix,

6

Se stai usando l'ambiente IPython, puoi semplicemente usare% debug e la shell ti riporterà alla linea offensiva con l'ambiente ipdb per le ispezioni ecc. Un'altra opzione come indicato sopra è usare iPython magic% pdb che effettivamente fa lo stesso.


Si noti che se l'errore si è verificato in una funzione del modulo, è possibile navigare attraverso i frame upe i downcomandi per tornare alla riga del codice che ha generato l'errore.
Jean Paul,


3

Per farlo funzionare senza dover digitare c all'inizio usare:

python -m pdb -c c <script name>

Pdb ha i suoi argomenti da riga di comando: -cc eseguirà il comando c (ontinue) all'inizio dell'esecuzione e il programma verrà eseguito ininterrottamente fino all'errore.


3

python -m pdb script.py in python2.7 premere continua per iniziare e verrà eseguito per l'errore e vi si romperà per il debug.


1

Se stai eseguendo un modulo:

python -m mymodule

E ora vuoi inserire pdbquando si verifica un'eccezione, fai come segue:

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

(o estendi il tuo PYTHONPATH). Il PYTHONPATHè necessario in modo che il modulo si trova nel percorso, dal momento che si sta eseguendo il pdbmodulo di ora.


0

Inserisci un punto di interruzione all'interno del costruttore della classe di eccezione più in alto nella gerarchia e la maggior parte delle volte vedrai dove è stato generato l'errore.

Inserire un breakpoint significa qualunque cosa tu voglia che significhi: puoi usare un IDE, o pdb.set_trace, o qualunque altra cosa

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.