Code always eventually breaks. Let’s look at some broken code:
from typing import Tuple
import sysdef broken() -> None:
1 / 0def my_broken_function() -> Tuple[int, int]:
x = 6
y = 4
x += 2
y *= 2
x -= y
y /= x
return x, ymy_broken_function()---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
Cell In[5], line 1
----> 1 my_broken_function()
Cell In[4], line 7, in my_broken_function()
5 y *= 2
6 x -= y
----> 7 y /= x
8 return x, y
ZeroDivisionError: division by zeroIPython debugger¶
Try writing %debug into the cell below! (you can even skip the %)
%debugThe mini-language here is pdb, and is similar to gdb and many other debuggers. You can step forward, up, etc. You can set breakpoints, or you can just write breakpoint() anywhere, and the “current” debugger will pick up there!
Rich tracebacks¶
Another trick comes from the Rich library. You can install a nicer traceback handler. Never do this in a library, but only in applications and user code.
import rich.traceback
rich.traceback.install(show_locals=True)<bound method InteractiveShell.excepthook of <ipykernel.zmqshell.ZMQInteractiveShell object at 0x7f97708a0d70>>This needs to be in a file (normally it will be) for the traceback to show up nicely:
%%writefile tmp_rich.py
def my_broken_function():
x = 6
y = 4
x += 2
y *= 2
x -= y
y /= x
return x, yWriting tmp_rich.py
import tmp_rich
tmp_rich.my_broken_function()Debugging in Jupyter Lab¶
This used to require the Xeus Python kernel instead of IPython, but IPyKernel 6+ now supports the visual debugger protocol directly.
Turn on the debugger with the switch on the top right. Click on the line numbers to set a breakpoint. Then run.
def my_broken_function():
# breakpoint()
x = 6
y = 4
x += 2
y *= 2
x -= y
y /= x
return x, ymy_broken_function()