The functionality we are about to explore here has quickly become my all time favorite.
These commands are not only great for debugging but also for hands on experimentation and learning.
Just a cautionary note - you will not be able to do 'Cell > run all'. Also, if you don't properly exit out from the debugger, you might need to restart the kernel.
def full_speed_ahead(engine_power=50):
if engine_power > 100: raise ValueError(
'Oh no, you set the engine_power to above 100! Things will start to fall apart!'
)
full_speed_ahead(125)
%debug
The %debug magic opens an interactive debugger and takes you to where the exception occured.
You can take a look around and interact with variables that are in scope. You can also navigate up and down the stack using the up
and down
commands.
To access a list of available commands type help
or h
(its enough to enter only the first letter).
To exit the debugger, execute exit
or just e
.
from IPython.core.debugger import set_trace
You can now open an interactive debugger from a point of your choosing in your code!
All you have to do is add the set_trace()
call.
Important: you can also add this to code that lives outside of your notebook. Say a utils.py
module you are importing.
def full_speed_ahead_without_breaks(engine_power=50):
if engine_power > 100: set_trace() # let's see what happens if we go that fast
full_speed_ahead_without_breaks()
full_speed_ahead_without_breaks(125)
It's easier to figure out how to use something if you can experiment with it.
But how can we do so with things hidden multiple layers below the the API?
For instance, can we take a look at what functions that we pass to other functions receive?
d = [(1, 2), (3, 4)]
sorted(d, key=lambda itm: set_trace())
But maybe that is too trivial. Let's try a more real world scenario.
import pandas as pd
df = pd.DataFrame(data=pd.np.random.randn(4, 2), columns=['a', 'b'])
What does the function passed to apply
receive?
df
df.apply(lambda smth: set_trace())