Debug Python Programs in VS Code

Learn how to use VS Code's built-in Python debugger to set breakpoints, step through code, inspect variables, and debug tests visually.

7 min read

The command-line debugger pdb is powerful, but remembering commands while you are trying to understand a bug adds cognitive load. VS Code's Python debugger gives you the same capabilities with a visual interface. You click to set breakpoints, hover over variables to see their values, and step through code with keyboard shortcuts you already know.

This article assumes you have VS Code and the Python extension installed. If you have not set those up yet, the article on setting up your Python workspace walks through the installation. The skills here build on debugging Python code with pdb; the concepts are the same, and the interface is the difference.

Setting a breakpoint

A breakpoint tells the debugger to pause execution at a specific line. In VS Code, click in the left margin next to the line number where you want execution to stop. A red dot appears. That is your breakpoint.

pythonpython
TIER_DISCOUNTS = {"gold": 0.8, "silver": 0.9}
 
def calculate_discount(price, customer_tier):
    multiplier = TIER_DISCOUNTS.get(customer_tier, 1.0)
    discounted = price * multiplier    # Click in the margin next to this line
    return round(discounted, 2)

When the debugger reaches that line, it pauses before executing it. The line is highlighted in yellow. At this moment, multiplier has been assigned but discounted has not. You can inspect the value of multiplier before the multiplication happens.

You can set as many breakpoints as you need. Click an existing red dot to remove it. Right-click a breakpoint to add a condition, so it only triggers when a variable has a specific value. Right-click and choose Edit Breakpoint to set a hit count, so it triggers only on every Nth pass through a loop.

Starting the debugger

The simplest way to start debugging is to open the Python file you want to debug and press F5. VS Code runs the file with the debugger attached and pauses at the first breakpoint it encounters.

If you need to pass arguments or set environment variables, create a launch configuration. Open the Run and Debug view from the left sidebar (Ctrl+Shift+D), click "create a launch.json file", and select Python File. VS Code generates a configuration you can customize:

jsonjson
{
    "name": "Python: Current File",
    "type": "debugpy",
    "request": "launch",
    "program": "${file}",
    "args": ["--verbose"],
    "env": {"DEBUG": "true"}
}

The program field is set to ${file}, which means it debugs whichever file you have open. Add arguments in the args list and environment variables in the env object. Save the file and press F5 to debug with this configuration.

Stepping through code

Once execution is paused at a breakpoint, a toolbar appears at the top of the editor with step controls. You can also use keyboard shortcuts.

Press F10 to Step Over. The debugger executes the current line and pauses at the next line in the same function. If the current line calls another function, that function runs completely and the debugger pauses after it returns. Use Step Over when you trust the function being called and only care about the result.

Press F11 to Step Into. If the current line calls a function, the debugger moves inside that function and pauses at its first line. Use Step Into when you suspect the bug is inside the called function and you need to follow the execution path.

Press Shift+F11 to Step Out. The debugger runs the rest of the current function and pauses at the line that called it. Use Step Out when you stepped into a function but realized the bug is not there and you want to return to the caller.

Press F5 to Continue. The debugger runs until the next breakpoint or until the program ends. Use Continue when you have seen enough of the current section.

Inspecting variables

While execution is paused, the Variables panel on the left shows every local and global variable in the current scope. Each variable is listed with its name, type, and current value. Complex objects like lists and dictionaries can be expanded to see their contents.

Hover over any variable in the editor to see its value in a popup. This is faster than scanning the Variables panel when you only need to check one or two values.

The Watch panel lets you track specific expressions across steps. Type an expression like len(results) or user.name into the Watch panel, and VS Code evaluates it at every step. This is useful when the value you care about is computed from multiple variables rather than stored in a single one.

The Debug Console at the bottom of the screen lets you type arbitrary Python expressions and see the results evaluated in the current stack frame. Type type(variable) to check its type, dir(object) to list its attributes, or call a helper function to test a hypothesis:

pythonpython
# Type this in the Debug Console while paused
>>> sum(data) / len(data)

The expression runs in the context of the paused program, so it has access to all the variables currently in scope.

Debugging tests

You can debug a failing test the same way you debug any Python code. Open the test file, set a breakpoint inside the test method or in the code the test calls, and start the debugger.

VS Code also shows Debug icons above each test function when you have the Python extension's testing feature enabled. Click the Debug icon next to a specific test to run only that test under the debugger with your breakpoints active. This is faster than running the entire suite when you are diagnosing a single failure.

To debug tests from the command line, create a launch configuration that runs pytest or unittest:

jsonjson
{
    "name": "Debug Tests",
    "type": "debugpy",
    "request": "launch",
    "module": "pytest",
    "args": ["tests/", "-x", "-k", "test_login"]
}

The module field tells VS Code to run python -m pytest instead of a script file. The args field passes arguments to pytest: run tests in the tests directory, stop after the first failure, and only run tests whose names contain "test_login".

Debugging a running process

If a program is stuck or behaving strangely and you did not start it with the debugger, you can attach to it. In the Run and Debug view, select "Python: Attach using Process ID" from the dropdown and enter the process ID. VS Code attaches the debugger and pauses the program at its current point.

This is an advanced feature that requires the program to have been started with debugpy enabled or to have the debugpy package importable. For scripts you write, it is usually simpler to restart them under the debugger. For long-running services where restart is not practical, process attachment is the right tool.

From debugging to fixing

The debugger tells you what is wrong. Fixing it is still your job. After you identify the bug, stop the debugger (Shift+F5), edit the code, set a breakpoint one line before the fix to verify it, and run the debugger again. This feedback loop of "find the bug, fix it, verify the fix" is the core debugging workflow.

The next article covers reading and understanding Python tracebacks, which is what you use to start diagnosing a crash before you even open the debugger.

Rune AI

Rune AI

Key Insights

  • Click in the left gutter next to a line number to set a breakpoint; a red dot appears, and execution pauses there.
  • Press F5 to start debugging the current file; press Shift+F5 to stop the debugger.
  • F10 steps over the current line; F11 steps into function calls; Shift+F11 steps out of the current function.
  • The Variables panel shows all local and global variables with their current values, updated at each step.
  • The Debug Console at the bottom lets you type Python expressions and see results in the current stack frame context.
RunePowered by Rune AI

Frequently Asked Questions

Do I need to install anything to debug Python in VS Code?

You need the Python extension for VS Code, which includes the debugger. Install it from the Extensions view by searching for 'Python' from Microsoft. The extension bundles debugpy, the debug adapter that connects VS Code to your Python process. No additional pip packages are required.

How do I debug a Python script that requires command-line arguments?

Open the Run and Debug view, click 'create a launch.json file', and select Python File. Edit the generated configuration to add an args field: "args": ["--input", "data.csv", "--verbose"]. When you start debugging, VS Code passes these arguments to your script exactly as if you typed them on the command line.

Can I debug unit tests in VS Code?

Yes. Open a test file, and you will see small Run and Debug icons above each test function and class. Click the Debug icon to run that specific test under the debugger with breakpoints active. You can also configure a test launch configuration in launch.json to debug your entire test suite with a single click.

Conclusion

VS Code's Python debugger gives you the same control as pdb with a visual interface that removes the memorization burden. Click to set breakpoints, hover to see variable values, and step through code with keyboard shortcuts. Once you debug visually, you will not go back to print statements.