Skip to article frontmatterSkip to article content
if not input('Load JupyterAI? [Y/n]').lower()=='n':
    %reload_ext jupyter_ai

Motivation

Computer programs can sometimes behave in an unexpected way due to errors or bugs. Finding the errors might be easy for simple programs. However, for programs consisting of many lines of code, finding errors can be very hard.

A debugger allows us to pause the execution of a program at a line of code set as a breakpoint. This allows us to find errors more easily. In this lab, we will learn to use the visual debugger in JupyterLab.

Debugging in JupyterLab

To enter the debug mode, click on the debugger icon 🕷️ in the toolbar. The debugging sidebar should slide open. You can also open/close the sidebar by clicking the debugger icon on the right side bar.

We will use the following code as an example to set a breakpoint. First, execute the code to see the effect.

msg = "Hello, World!"
print(msg)

Code cells look different in debug mode: Each line of the code cell has a line number on the left margin. To set a breakpoint:

  1. Press the dot that appears as you hover to the left of line number 2.
  2. Run the cell and observe that only line 1 is executed but not line 2.

Sometimes, it is helpful to run temporary code that shares the same context as the notebook, but without modifying the notebook. Normally, this can be done using a console:

  • Right click anywhere on a notebook and choose New Console for Notebook:
  • Type some code such as msg into the console input and run it with Shift-Enter:

However, if you need to run temporary code while debugging a code cell, the console above won’t work because a breakpoint also pauses the execution of the console. We need a special console called the debug console:

Set a breakpoint at Line 2 of the above code and run it in debug mode.

  1. Click the icon in the callstack panel to open a debug console. Enter the code print(msg) and click Evaluate. Explain what gets printed to the cell output.
  2. Repeat the last step but evaluate the code msg="Message modified!" in the debug console instead. Observe the value of msg from the Variables panel.

Finally, to resume/terminate the execution, use the following flow control buttons at the top of the callstack panel:

  • Next/Step-over button continues the execution of program to the next line of code to be executed.
  • Continue button continues the execution and pause again if it hits a breakpoint.
  • Terminate button stops the execution.

Let try debugging the following program, which attempts to implements the Knuth’s up arrow

ak=aaaka\uparrow\uparrow k = \underbrace{a^{a^{\cdot^{\cdot^{\cdot^{a}}}}}}_{k}

for n>0n>0.

def kua(a, k):
    if k > 1:
        return kua(a, k-1) ** a
    return a
def kua(a, k):
    # YOUR CODE HERE
    raise NotImplementedError
# tests
assert kua(2, 0) == 1
assert kua(2, 1) == 2
assert kua(2, 2) == 2**2
assert kua(2, 3) == 2**2**2
assert kua(2, 4) == 2**2**2**2
assert kua(3, 0) == 1
assert kua(3, 1) == 3
assert kua(3, 2) == 3**3
assert kua(3, 3) == 3**3**3

Other Debuggers

Seeing is believing. You can also debug your code by visualizing the code execution.

First, load the divewidgets using a line magic:

%reload_ext divewidgets

Then, create a cell magic with the Python code you want to visualize:

%%optlite --height 500
def kua(a, k):
    if k > 1:
        return kua(a, k-1) ** a
    return a

assert kua(2, 4) == 2**2**2**2

Try the following:

  • Drag the slider to time-travel the code execution.
  • Click any lines with code to toggle breakpoints, and click Next > (< Prev) to go the the next (previous) breakpoint.
  • Click the Edit the code link to edit the code.
  • Click the Permalink button to generate a url of the code, and copy and paste the url to a new browser window to run the visualization there.
  • Click the Live Edit button to live edit the code in a new browser window, where your changes to the code are immediately visualized. You can also time-travel and generate a permalink there.

Run the following cell to see additional options available to the cell magic.

%%optlite?

VSCode offers a more powerful debugging that allows programmers to debug both jupyter notebooks or python scripts with conditional breakpoints:

from importlib import reload
import utils

reload(utils)  # to reload updates to utils.py without restarting kernel
utils.is_perfect_square((10**23) ** 2)

Glossary

breakpoint
A designated point in a program’s code where execution will pause, allowing the programmer to examine the program’s state and behavior at that point. Breakpoints are often used in conjunction with a debugger to help identify and resolve errors or bugs in a program.
bug
An error or defect in a software program that causes it to behave unexpectedly or not according to its intended purpose. Bugs can range from minor issues to major problems that can cause crashes or data loss.
callstack
A data structure that keeps track of the functions or procedures that have been called in a program, along with their parameters and return values. The callstack is used by the program to keep track of where it is in the execution process and to manage memory usage.
console
A command-line interface or text-based window used for interacting with a program or operating system. The console allows users to enter commands and view output from the system or program.
debugger
A tool or program used to identify and resolve errors or bugs in software code. Debuggers can be used to step through code, examine variables and data structures, and identify the source of errors in a program.
flow control
The process of controlling the order in which a program executes its instructions. Flow control can be achieved through conditional statements, loops, and other control structures that allow the program to make decisions and repeat actions based on certain conditions.
Footnotes
  1. The path should be in lower case even though the debugger shows it in upper case.