web-dev-qa-db-fra.com

Démarrage automatique du débogueur python en cas d'erreur

C’est une question à laquelle je me pose des questions depuis un certain temps, mais je n’ai jamais trouvé de solution adéquate. Si je lance un script et que je rencontre, par exemple, une erreur IndexError, python imprime la ligne, l'emplacement et la description rapide de l'erreur, puis se termine. Est-il possible de démarrer automatiquement pdb lorsqu'une erreur est rencontrée? Je ne suis pas contre le fait d'avoir une déclaration d'importation supplémentaire en haut du fichier, ni quelques lignes de code supplémentaires.

166
jeremy

Vous pouvez utiliser traceback.print_exc pour imprimer le suivi des exceptions. Ensuite, utilisez sys.exc_info pour extraire la trace et enfin appeler pdb.post_mortem avec cette trace

import pdb, traceback, sys

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

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

Si vous souhaitez démarrer une ligne de commande interactive avec code.interact en utilisant les paramètres locaux du cadre d'où provient l'exception, vous pouvez le faire.

import traceback, sys, code

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

if __== '__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)
102
Florian Bösch
python -m pdb -c continue myscript.py

Si vous ne fournissez pas l'indicateur -c continue, vous devrez entrer «c» (pour continuer) au début de l'exécution. Ensuite, il fonctionnera jusqu'au point d'erreur et vous donnera le contrôle là-bas. Comme mentionné par eqzx , ce drapeau est un nouvel ajout dans python 3.2, il est donc nécessaire de saisir 'c' pour les versions antérieures de Python (voir https://docs.python.org/3/library/pdb.html ).

342
Catherine Devlin

Utilisez le module suivant:

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

Nommez-le debug (ou ce que vous préférez) et mettez-le quelque part dans votre chemin python.

Maintenant, au début de votre script, ajoutez simplement un import debug.

58
tzot

Ipython a une commande permettant de basculer ce comportement:% pdb . Il fait exactement ce que vous avez décrit, peut-être même un peu plus (en vous donnant des traces plus informatives avec la coloration syntaxique et l’achèvement du code). Cela vaut vraiment la peine d'essayer!

33
Latanius

Ce n'est pas le débogueur, mais probablement tout aussi utile (?)

Je sais que j'ai entendu Guido en parler dans un discours quelque part.

Je viens de vérifier python - ?, et si vous utilisez la commande -i, vous pouvez interagir là où votre script s’est arrêté.

Donc, étant donné ce 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

Vous pouvez obtenir cette sortie!

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

Pour être honnête, je ne l'ai pas utilisé, mais je devrais l'être, semble très utile.

31
monkut

IPython rend cela simple en ligne de commande:

python myscript.py arg1 arg2

peut être réécrit pour

ipython --pdb myscript.py -- arg1 arg2

Ou, de la même manière, si vous appelez un module:

python -m mymodule arg1 arg2

peut être réécrit pour

ipython --pdb -m mymodule -- arg1 arg2

Notez le -- pour empêcher IPython de lire les arguments du script comme étant les siens.

Cela présente également l’avantage d’appeler le débogueur IPython amélioré (ipdb) au lieu de pdb.

16
wodow

Vous pouvez mettre cette ligne dans votre code:

import pdb ; pdb.set_trace()

Plus d'infos: Démarrer le débogueur python à n’importe quelle ligne

5
Rory

Si vous utilisez l'environnement IPython, vous pouvez simplement utiliser% debug et le shell vous ramènera à la ligne incriminée avec l'environnement ipdb pour les inspections, etc. le même.

5
Jehandad

Pour le faire fonctionner sans avoir à taper c au début, utilisez:

python -m pdb -c c <script name>

Pdb a ses propres arguments en ligne de commande: -c c exécutera la commande c(ontinue) au début de l'exécution et le programme s'exécutera sans interruption jusqu'à l'erreur.

3
Zlatko Karakaš

Si vous utilisez ipython, après avoir lancé %pdb

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

python -m pdb script.py dans python2.7 appuyez sur continuer pour démarrer et l'erreur sera exécutée pour pouvoir déboguer.

2
Hannah

Si vous utilisez un module:

python -m mymodule

Et maintenant, vous voulez entrer pdb lorsqu'une exception se produit, procédez comme suit:

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

(ou expand your PYTHONPATH). La PYTHONPATH est nécessaire pour que le module soit trouvé dans le chemin, puisque vous exécutez maintenant le module pdb.

0
dangonfast

Placez un point d'arrêt à l'intérieur du constructeur de la classe d'exception la plus haute de la hiérarchie et la plupart du temps, vous verrez où l'erreur a été générée.

Mettre un point d'arrêt signifie ce que vous voulez dire: vous pouvez utiliser un IDE, un pdb.set_trace ou autre chose

0
vlad-ardelean