web-dev-qa-db-fra.com

Python débogueur: entrer dans une fonction que vous avez appelée interactive

Python est assez cool, mais malheureusement, son débogueur n'est pas aussi bon que Perl -D.

Une chose que je fais très généralement lors de l'expérimentation du code consiste à appeler une fonction du débogueur et à entrer dans cette fonction, comme le cas échéant:

# NOTE THAT THIS PROGRAM EXITS IMMEDIATELY WITHOUT CALLING FOO()
~> cat -n /tmp/show_Perl.pl
1  #!/usr/local/bin/Perl
2
3  sub foo {
4      print "hi\n";
5      print "bye\n";
6  }
7
8  exit 0;

~> Perl -d /tmp/show_Perl.pl

Loading DB routines from Perl5db.pl version 1.28
Editor support available.

Enter h or `h h' for help, or `man perldebug' for more help.

main::(/tmp/show_Perl.pl:8):    exit 0;

# MAGIC HAPPENS HERE -- I AM STEPPING INTO A FUNCTION THAT I AM CALLING INTERACTIVELY
  DB<1> s foo() 
main::((eval 6)[/usr/local/lib/Perl5/5.8.6/Perl5db.pl:628]:3):
3:      foo();


  DB<<2>> s
main::foo(/tmp/show_Perl.pl:4):     print "hi\n";


  DB<<2>> n
hi
main::foo(/tmp/show_Perl.pl:5):     print "bye\n";


  DB<<2>> n
bye


  DB<2> n
Debugged program terminated.  Use q to quit or R to restart,
  use O inhibit_exit to avoid stopping after program termination,
  h q, h R or h O to get additional info.  

  DB<2> q

Ceci est incroyablement utile lorsque vous essayez de passer à travers une fonction de fonctionnement de diverses entrées différentes pour comprendre pourquoi elle échoue. Cependant, il ne semble pas fonctionner dans la PDB ou le PYDB (je montrerais un équivalent python exemple à celui ci-dessus, mais il en résulte une grande empreinte de pile).

Donc, ma question est double:

  1. Est-ce que je manque quelque chose?
  2. Y a-t-il un python débogueur qui me laisserait effectivement faire cela?

De toute évidence, je pourrais mettre les appels dans le code moi-même, mais j'adore travailler de manière interactive, par exemple. Ne pas avoir à commencer à partir de zéro lorsque je veux essayer d'appeler avec un ensemble d'arguments légèrement différent.

49
yga

Et j'ai répondu à ma propre question! C'est la commande "debug" dans la PYDB:

~> cat -n /tmp/test_python.py
     1  #!/usr/local/bin/python
     2
     3  def foo():
     4      print "hi"
     5      print "bye"
     6
     7  exit(0)
     8

~> pydb /tmp/test_python.py
(/tmp/test_python.py:7):  <module>
7 exit(0)


(Pydb) debug foo()
ENTERING RECURSIVE DEBUGGER
------------------------Call level 11
(/tmp/test_python.py:3):  foo
3 def foo():

((Pydb)) s
(/tmp/test_python.py:4):  foo
4     print "hi"

((Pydb)) s
hi
(/tmp/test_python.py:5):  foo
5     print "bye"


((Pydb)) s
bye
------------------------Return from level 11 (<type 'NoneType'>)
----------------------Return from level 10 (<type 'NoneType'>)
LEAVING RECURSIVE DEBUGGER
(/tmp/test_python.py:7):  <module>
40
yga

Vous pouvez également déboguer de manière interactive une fonction avec PDB, à condition que le script que vous souhaitez déboguer ne quitte pas () à la fin:

$ cat test.py
#!/usr/bin/python

def foo(f, g):
        h = f+g
        print h
        return 2*f

Pour déboguer, démarrez un interactif python session et import PDB:

$ python
Python 2.5.1 (r251:54869, Apr 18 2007, 22:08:04) 
[GCC 4.0.1 (Apple Computer, Inc. build 5367)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pdb
>>> import test
>>> pdb.runcall(test.foo, 1, 2)
> /Users/simon/Desktop/test.py(4)foo()
-> h = f+g
(Pdb) n
> /Users/simon/Desktop/test.py(5)foo()
-> print h
(Pdb) 

Le module PDB est livré avec python et est documenté dans les modules Documents à http://docs.python.org/modindex.html

20
Simon

Il y a un python débogueur qui fait partie de la distribution de base de python appelé "PDB". Je l'utilise rarement moi-même, mais trouvez-le parfois utile.

Compte tenu de ce programme:

def foo():
    a = 0
    print "hi"

    a += 1

    print "bye"

foo()

Voici une session le débogage:

$ python /usr/lib/python2.5/pdb.py /var/tmp/pdbtest.py         ~
> /var/tmp/pdbtest.py(2)<module>()
-> def foo():
(Pdb) s
> /var/tmp/pdbtest.py(10)<module>()
-> foo()
(Pdb) s
--Call--
> /var/tmp/pdbtest.py(2)foo()
-> def foo():
(Pdb) s
> /var/tmp/pdbtest.py(3)foo()
-> a = 0
(Pdb) s
> /var/tmp/pdbtest.py(4)foo()
-> print "hi"
(Pdb) print a
0
(Pdb) s
hi
> /var/tmp/pdbtest.py(6)foo()
-> a += 1
(Pdb) s
> /var/tmp/pdbtest.py(8)foo()
-> print "bye"
(Pdb) print a
1
(Pdb) s
bye
--Return--
> /var/tmp/pdbtest.py(8)foo()->None
-> print "bye"
(Pdb) s
--Return--
> /var/tmp/pdbtest.py(10)<module>()->None
-> foo()
(Pdb) s
4
Jerub

Si vous êtes plus familier avec un débogueur d'interface graphique, WinPDB ("victoire" dans ce cas ne fait pas référence à Windows). Je l'utilise en fait sur Linux.

Sur Debian/Ubuntu:

Sudo aptitude install winpdb

Ensuite, il suffit de mettre cela dans votre code où vous voulez qu'il casse:

import rpdb2; rpdb2.start_embedded_debugger_interactive_password()

Ensuite, démarrez WinPDB et joignez-vous à votre script en cours d'exécution.

3
Jeremy Cantrell

Pour des travaux interactifs sur le code que je développe, je trouve généralement plus efficace de définir un "point de rupture" programmatique dans le code lui-même avec pdb.set_trace. Cela facilite la rupture de l'état du programme au fond d'une boucle, aussi: if <state>: pdb.set_trace()

2
Alex Coventry