le debugger Python : pdb

Licence CC BY-NC-ND, Thierry Parmentelat & Arnaud Legout

from IPython.display import HTML
HTML(filename="_static/style.html")

le debugger Python : pdb#

breakpoint()#

pour mettre un point d’arrêt dans un programme on peut utiliser breakpoint()

def fact(n):
    if n<=1:
        breakpoint()
        return 1
    else:
        return n * fact(n-1)

raccourcis

clavier

quoi

l (lowercase L)

list source

w

show stack

n

next statement (stay in same function)

s

step into (dive into function call)

c

continue

p

print

# si on exécute, le programme s'arrête 
# et on peut ensuite exécuter pas à pas, 
# inspecter la pile et les variables, ...
# fact(3)

pdb.run()#

  • le module pdb permet de debugger facilement un programme Python

import pdb 
import mymodule 
pdb.run('mymodule.test()') 
  • lance le debugger depuis la console sur la fonction test()

pdb.pm() - post-mortem#

import pdb 
import mymodule 
mymodule.test() 
Traceback (most recent call last): 
	File "<stdin>", line 1, in ? 
	File "./mymodule.py", line 4, in test 
		test2() 
	
pdb.pm()
  • lance le debugger en post-mortem

sous IPython#

dans ipython (ou dans un notebook), vous pouvez utiliser la magic %%debug

magic de cellule

rappelez-vous que avec un seul % on a affaire à une magic de ligne
et avec deux pourcents %% c’est une magique de cellule

donc nous ici on utilise presque toujours le double pourcent

def fact(n):
    print(f"in fact with {n=}")
    if n <= 1:
        return 1
    else:
        return n * fact(n-1)
%%debug
fact(3)
NOTE: Enter 'c' at the ipdb>  prompt to continue execution.
> <string>(2)<module>()
---------------------------------------------------------------------------
StdinNotImplementedError                  Traceback (most recent call last)
File ~/.asdf/installs/python/3.12.7/lib/python3.12/bdb.py:90, in Bdb.trace_dispatch(self, frame, event, arg)
     88     return # None
     89 if event == 'line':
---> 90     return self.dispatch_line(frame)
     91 if event == 'call':
     92     return self.dispatch_call(frame, arg)

File ~/.asdf/installs/python/3.12.7/lib/python3.12/bdb.py:114, in Bdb.dispatch_line(self, frame)
    107 """Invoke user function and return trace function for line event.
    108 
    109 If the debugger stops on the current line, invoke
    110 self.user_line(). Raise BdbQuit if self.quitting is set.
    111 Return self.trace_dispatch to continue tracing in this scope.
    112 """
    113 if self.stop_here(frame) or self.break_here(frame):
--> 114     self.user_line(frame)
    115     if self.quitting: raise BdbQuit
    116 return self.trace_dispatch

File ~/.asdf/installs/python/3.12.7/lib/python3.12/pdb.py:329, in Pdb.user_line(self, frame)
    327     self._wait_for_mainpyfile = False
    328 if self.bp_commands(frame):
--> 329     self.interaction(frame, None)

File ~/checkouts/readthedocs.org/user_builds/ue12-p24-python/envs/p24/lib/python3.12/site-packages/IPython/core/debugger.py:464, in Pdb.interaction(self, frame, tb_or_exc)
    462         assert tb is not None, "main exception must have a traceback"
    463     with self._hold_exceptions(_chained_exceptions):
--> 464         OldPdb.interaction(self, frame, tb)
    465 else:
    466     OldPdb.interaction(self, frame, tb_or_exc)

File ~/.asdf/installs/python/3.12.7/lib/python3.12/pdb.py:428, in Pdb.interaction(self, frame, traceback)
    422 # We should print the stack entry if and only if the user input
    423 # is expected, and we should print it right before the user input.
    424 # We achieve this by appending _pdbcmd_print_frame_status to the
    425 # command queue. If cmdqueue is not exausted, the user input is
    426 # not expected and we will not print the stack entry.
    427 self.cmdqueue.append('_pdbcmd_print_frame_status')
--> 428 self._cmdloop()
    429 # If _pdbcmd_print_frame_status is not used, pop it out
    430 if self.cmdqueue and self.cmdqueue[-1] == '_pdbcmd_print_frame_status':

File ~/checkouts/readthedocs.org/user_builds/ue12-p24-python/envs/p24/lib/python3.12/site-packages/IPython/core/debugger.py:1119, in InterruptiblePdb._cmdloop(self)
   1115 try:
   1116     # keyboard interrupts allow for an easy way to cancel
   1117     # the current command, so allow them during interactive input
   1118     self.allow_kbdint = True
-> 1119     self.cmdloop()
   1120     self.allow_kbdint = False
   1121     break

File ~/checkouts/readthedocs.org/user_builds/ue12-p24-python/envs/p24/lib/python3.12/site-packages/IPython/core/debugger.py:1105, in InterruptiblePdb.cmdloop(self, intro)
   1103 """Wrap cmdloop() such that KeyboardInterrupt stops the debugger."""
   1104 try:
-> 1105     return OldPdb.cmdloop(self, intro=intro)
   1106 except KeyboardInterrupt:
   1107     self.stop_here = lambda frame: False

File ~/.asdf/installs/python/3.12.7/lib/python3.12/cmd.py:126, in Cmd.cmdloop(self, intro)
    124 if self.use_rawinput:
    125     try:
--> 126         line = input(self.prompt)
    127     except EOFError:
    128         line = 'EOF'

File ~/checkouts/readthedocs.org/user_builds/ue12-p24-python/envs/p24/lib/python3.12/site-packages/ipykernel/kernelbase.py:1281, in Kernel.raw_input(self, prompt)
   1279 if not self._allow_stdin:
   1280     msg = "raw_input was called, but this frontend does not support input requests."
-> 1281     raise StdinNotImplementedError(msg)
   1282 return self._input_request(
   1283     str(prompt),
   1284     self._parent_ident["shell"],
   1285     self.get_parent("shell"),
   1286     password=False,
   1287 )

StdinNotImplementedError: raw_input was called, but this frontend does not support input requests.