Skip to content

bdb

The Python bdb module provides a generic debugger framework for tracing and controlling Python program execution at the source-code level. It supplies the low-level machinery for setting breakpoints, stepping through code, and managing trace events so that higher-level tools like pdb can focus on user interaction.

Here’s a minimal custom debugger built on bdb:

Language: Python Filename: line_tracer.py
import bdb

class LineTracer(bdb.Bdb):
    def user_line(self, frame):
        print(f"line {frame.f_lineno}: {frame.f_code.co_name}")

tracer = LineTracer()
tracer.run("x = 1 + 1\ny = x * 3")

Run it on the command line:

Language: Shell
$ python line_tracer.py
line 1: <module>
line 2: <module>

The tracer calls .user_line() each time execution moves to a new source line.

Key Features

  • Provides a Bdb base class to subclass when building custom debuggers
  • Runs Python statements, callables, and expressions under full debugger control via Bdb.run(), Bdb.runcall(), and Bdb.runeval()
  • Manages breakpoints through the Breakpoint class, with support for temporary, conditional, and function-specific breakpoints
  • Supports two tracing backends: settrace (default) and monitoring (Python 3.14+), where the monitoring backend adds Bdb.disable_current_event() and Bdb.restart_events() to skip uninteresting events for lower overhead
  • Allows module-level skip patterns to avoid stepping into third-party or standard-library code
  • Raises BdbQuit to signal a clean exit from the debugging session

Frequently Used Classes and Functions

Object Type Description
bdb.Bdb Class Serves as the generic debugger base class
bdb.Breakpoint Class Represents a single breakpoint with hit counts, conditions, and enable/disable support
bdb.BdbQuit Exception Signals a clean exit from the debugging session when raised
bdb.Bdb.run() Method Runs a string of Python statements under debugger control
bdb.Bdb.runcall() Method Calls a function with arguments under debugger control
bdb.Bdb.set_break() Method Sets a breakpoint at a given filename and line number
bdb.Bdb.set_step() Method Steps into the next statement, including any function calls
bdb.Bdb.set_continue() Method Continues execution until the next breakpoint is hit
bdb.set_trace() Function Starts debugging from the caller’s frame using a default Bdb instance

Examples

Tracing return values from function calls:

Language: Python Filename: return_demo.py
import bdb

class ReturnTracer(bdb.Bdb):
    def user_return(self, frame, return_value):
        if frame.f_code.co_name != "<module>":
            print(
                f"{frame.f_code.co_name} returned {return_value!r}"
            )

tracer = ReturnTracer()
tracer.run("def double(n):\n    return n * 2\ndouble(5)")

Run it on the command line:

Language: Shell
$ python return_demo.py
double returned 10

user_return() intercepts every return event, making it straightforward to log or inspect return values without modifying the code under test.

Common Use Cases

The most common tasks for bdb include:

  • Building custom debuggers by subclassing Bdb and implementing user_line(), user_call(), user_return(), and user_exception()
  • Running a specific function, expression, or code string under full debugger control with Bdb.runcall(), Bdb.runeval(), or Bdb.run()
  • Setting temporary breakpoints that are removed automatically after being hit once
  • Applying conditional breakpoints that only pause execution when a given expression is true
  • Skipping standard library or third-party modules during a debugging session
  • Tracing program execution to record call graphs or gather profiling data

Real-World Example

The following example creates a call tracer that logs every function entry and return value during a debugging run:

Language: Python Filename: call_tracer.py
import bdb

class CallTracer(bdb.Bdb):
    def user_call(self, frame, argument_list):
        name = frame.f_code.co_name
        file = frame.f_code.co_filename
        print(f"Calling: {name} in {file}")
        self.set_step()

    def user_return(self, frame, return_value):
        name = frame.f_code.co_name
        print(f"Returning: {name} -> {return_value!r}")
        self.set_step()

def add(a, b):
    return a + b

tracer = CallTracer()
tracer.runcall(add, 3, 4)

Run it on the command line:

Language: Shell
$ python call_tracer.py
Returning: add -> 7

bdb.Bdb.runcall() runs the target function under debugger control and intercepts return events without modifying the original code. Note that user_call() fires for functions called within the target, not for the direct target itself.

Python Debugging With Pdb (Guide)

Tutorial

Python Debugging With Pdb

Learn the basics of Python pdb, the interactive source-code debugger, and use it to track down hard-to-find bugs in your programs.

intermediate stdlib tools

For additional information on related topics, take a look at the following resources:

Have a question about this? Mentor AI can show you examples, compare related terms, and point you to tutorials.


By Leodanis Pozo Ramos • Updated Sept. 5, 2026