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


216

C'est une question que je me pose depuis longtemps, mais je n'ai jamais trouvé de solution appropriée. Si j'exécute un script et que je tombe sur, disons une IndexError, python affiche la ligne, l'emplacement et une description rapide de l'erreur et quitte. Est-il possible de démarrer automatiquement pdb en cas d'erreur? Je ne suis pas contre avoir une déclaration d'importation supplémentaire en haut du fichier, ni quelques lignes de code supplémentaires.


12
Avez-vous envisagé de changer la réponse acceptée?
Joost

Réponses:


127

Vous pouvez utiliser traceback.print_exc pour imprimer les exceptions traceback. Utilisez ensuite sys.exc_info pour extraire le traceback et enfin appeler pdb.post_mortem avec ce 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)

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

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 première solution est discutée plus en détail dans le livre de recettes python
dirkjot

3
pourquoi quelqu'un préfère codeplus pdbpuisque ce dernier semble se développer sur l'ancien?
K3 --- rnc

J'ai la même question? Pourquoi préférez-vous code?
ARH

2
Ensuite, utilisez sys.exc_infopour extraire le traçage et enfin appeler pdb.post_mortemavec ce traçage . Vous n'avez pas besoin de passer l'objet traceback à pdb.post_mortem. À partir des documents : si aucun traceback n'est fourni, il utilise celui de l'exception qui est actuellement gérée (une exception doit être gérée si la valeur par défaut doit être utilisée).
Piotr Dobrogost

2
@PiotrDobrogost Bon point. Je pense qu'il est plus utile de savoir que vous pouvez passer un objet tb, car cela démontre mieux l'API. Bon à savoir que les deux options existent.
davidA

453
python -m pdb -c continue myscript.py

Si vous ne fournissez pas l' -c continueindicateur, vous devrez entrer «c» (pour Continuer) lorsque l'exécution commencera. Ensuite, il s'exécutera au point d'erreur et vous donnera le contrôle. Comme mentionné par eqzx , cet indicateur est un nouvel ajout en python 3.2, donc la saisie de «c» est requise pour les versions antérieures de Python (voir https://docs.python.org/3/library/pdb.html ).


5
Merci d'avoir mentionné le " enter 'c' " - J'avais l'habitude de saisir 'r' (pour "run"), étant habitué à lui depuis gdb; et lorsque vous entrez «r» dans pdb, le programme s'exécute en effet, mais ne s'arrête pas (ni ne génère de trace) en cas d'erreur; m'a laissé perplexe jusqu'à ce que je lise ceci. À votre santé!
sdaau

3
Vineet, il vous démarrera avec le débogueur, donc entrez "cont" et il fonctionnera jusqu'à ce que l'erreur soit rencontrée. De là, vous pouvez inspecter les variables, etc. comme dans n'importe quelle autre session pdb.
Catherine Devlin

40
Veuillez OP, acceptez cela comme une réponse. C'est le plus utile et j'ai perdu 5 minutes à lire les autres jusqu'à ce que je frappe celui-ci ... ça devrait être le premier!
jhegedus

4
Cela fonctionne également avec ipdb; et bien sûr, des arguments peuvent être ajoutés après le script!
tutuDajuju

20
Cela ne fonctionne pas avec Python 2.7. docs.python.org/3/library/pdb.html : "Nouveau dans la version 3.2: pdb.py accepte désormais une option -c qui exécute les commandes"
eqzx

68

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 voulez) et placez-le quelque part dans votre chemin python.

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


2
Cela devrait être la réponse acceptée - cela ne nécessite aucune modification du code existant ou tout envelopper dans un try-catchqui est juste laid IMO.
cyphar

J'adore cette réponse assez souvent, mais préfère pudbplus pdb. Continuez à revenir au copier-coller, ce qui en dit sûrement quelque chose sur le manque d'ordre dans ma vie.
Stabledog

47

Ipython a une commande pour basculer ce comportement: % pdb . Il fait exactement ce que vous avez décrit, peut-être même un peu plus (vous donnant des tracés plus informatifs avec mise en évidence de la syntaxe et complétion du code). Cela vaut vraiment la peine d'essayer!


3
Et c'est la seule réponse raisonnable à cela.
Michael


4
Notez que - comme également noté dans la documentation @matthiash linked - %debugpermet d'ouvrir le débogueur après avoir rencontré une erreur. Je préfère souvent cela %pdb. (Le compromis est simplement taper qchaque fois que vous ne voulez pas déboguer un rapport d'erreur en tapant %debugchaque fois que vous faites à déboguer une erreur.)
Braham Snyder

1
Notez également que l'activation c.InteractiveShell.pdb = Trueà son ipython_config.pytour s'active %pdbautomatiquement à chaque session.
Braham Snyder

33

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

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

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.


Léger, mais souvent juste ce qu'il faut
Casebash

8
Pas aussi utile, se lance à l'échelle mondiale. Impossible de fouiller dans la fonction qui s'est écrasée.
pixelpax

21

IPython rend cela simple sur la ligne de commande:

python myscript.py arg1 arg2

peut être réécrit en

ipython --pdb myscript.py -- arg1 arg2

Ou, de même, si vous appelez un module:

python -m mymodule arg1 arg2

peut être réécrit en

ipython --pdb -m mymodule -- arg1 arg2

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

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


9

Si vous utilisez ipython, après le lancement du type%pdb

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

Jupyter par exemple
Blaztix

6

Si vous utilisez l'environnement IPython, vous pouvez simplement utiliser le% debug et le shell vous ramènera à la ligne incriminée avec l'environnement ipdb pour les inspections, etc. Une autre option, comme indiqué ci-dessus, consiste à utiliser la magie iPython% pdb qui fait le même.


Notez que si l'erreur s'est produite dans une fonction de module, vous pouvez parcourir les cadres avec upet les downcommandes pour revenir à la ligne de votre code qui a généré l'erreur.
Jean Paul


3

Pour l'exécuter sans avoir à taper c au début, utilisez:

python -m pdb -c c <script name>

Pdb a ses propres arguments de ligne de commande: -cc 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

python -m pdb script.py dans python2.7 appuyez sur continuer pour démarrer et il s'exécutera jusqu'à l'erreur et s'arrêtera là pour le débogage.


1

Si vous exécutez un module:

python -m mymodule

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

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

(ou étendez votre PYTHONPATH). Le PYTHONPATHest nécessaire pour que le module se trouve dans le chemin, puisque vous exécutez le pdbmodule maintenant.


0

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

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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.