PDB++
PDB++ (pdbpp) is a powerful, drop-in replacement for Python's built-in PDB debugger. It exists to make command-line debugging in Python faster, more productive, and more pleasant—without requiring you to learn a new tool or change your workflow. By extending the standard PDB with features like colorful tab completion, syntax highlighting, sticky mode, and smarter navigation, PDB++ helps developers debug complex problems with greater clarity and efficiency.
Unlike many alternatives, PDB++ is designed for seamless adoption: just install it, and your existing import pdb; pdb.set_trace() calls instantly gain new capabilities. Whether you're stepping through tricky bugs, inspecting variables, or navigating deep call stacks, PDB++ provides a modern, ergonomic experience for both beginners and advanced Python developers.
PDB++ is ideal for developers who want to debug Python code interactively in the terminal, with modern conveniences and minimal setup.
Basics
Installation and Setup
Installing PDB++
Install pdb++ using pip:
pip install pdbpp
Important: The package name is pdbpp, but you import and use it as pdb:
import pdb
pdb.set_trace() # This now uses pdb++ automatically
Automatic Replacement
Once installed, pdb++ automatically replaces the standard PDB module. No code changes are required:
# All of these now use pdb++ instead of standard pdb
import pdb; pdb.set_trace()
breakpoint() # Python 3.7+
python -m pdb script.py
pytest --pdb
Verification
To verify pdb++ is installed and working:
import pdb
print(pdb.__file__)
# Should show path containing 'pdbpp' in site-packages
Enhanced Debugging Workflow
Basic Usage
PDB++ maintains full compatibility with standard PDB commands while adding enhancements:
def calculate_average(numbers):
import pdb; pdb.set_trace() # Breakpoint with pdb++
total = 0
count = 0
for num in numbers:
total += num
count += 1
return total / count
# Test the function
numbers = [1, 2, 3, 4, 5]
result = calculate_average(numbers)
print(f"Average: {result}")
When the debugger starts, you'll notice immediate visual improvements:
> /path/to/script.py(3)calculate_average()
-> total = 0
(Pdb++)
Notice the colorful prompt (Pdb++) indicating pdb++ is active.
PDB++ Commands 🔖
# Enhanced pdb++ specific commands
sticky # Toggle sticky mode (visual step-by-step debugging)
longlist / ll # Show entire current function with syntax highlighting
display <expr> # Add expression to display list (auto-monitor variables)
undisplay <num> # Remove from display list
interact # Start interactive Python interpreter in current scope
# Navigation and flow control
n / next # Execute next line (don't step into functions)
s / step # Step into function calls
c / continue # Continue execution until next breakpoint
r / return # Continue until current function returns
f / finish # Continue until current function returns (alias for r)
u / up # Move up one stack frame
d / down # Move down one stack frame
j <line> / jump # Jump to specific line number
until <line> # Continue until line number
unt # Continue until line greater than current
# Breakpoints (enhanced in pdb++)
b # List all breakpoints
b <line> # Set breakpoint at line number in current file
b <file:line> # Set breakpoint at specific file and line
b <function> # Set breakpoint at function entry
b <line>, <condition> # Set conditional breakpoint
tbreak <line> # Set temporary breakpoint (removed after first hit)
cl # Clear all breakpoints
cl <number> # Clear specific breakpoint by number
condition <number> <condition> # Add/change condition for breakpoint
# Information and inspection (enhanced output)
l / list # Show current code (with syntax highlighting)
ll / longlist # Show entire function (enhanced in pdb++)
w / where # Show stack trace (enhanced formatting)
bt # Show stack trace (alias)
p <expr> # Print expression (with highlighting)
pp <expr> # Pretty-print expression (enhanced colors)
a / args # Show function arguments
whatis <expr> # Show type of expression
source <expr> # Show source code of object
rv / retval # Show return value
# Variable commands (enhanced)
!<statement> # Execute Python statement
interact # Start interactive interpreter (pdb++ feature)
alias <name> <command> # Create command alias
unalias <name> # Remove alias
display <expr> # Auto-display expression (enhanced in pdb++)
undisplay <expr> # Stop auto-displaying
# Object and namespace inspection (enhanced output)
locals # Print all local variables (with highlighting)
globals # Print all global variables (with highlighting)
dir() # List names in current namespace
dir(<object>) # List attributes of object
vars() # Show local variables as dictionary
vars(<object>) # Show object's attributes as dictionary
# System commands
q / quit # Quit debugger and terminate program
exit # Same as q
restart # Restart the debugged program
run [args] # Restart program with optional command line arguments
# Hidden frame management (pdb++ feature)
hf_hide # Hide frames marked as hidden
hf_unhide # Show all frames including hidden ones
# Help and information (enhanced formatting)
h # Show help message (enhanced in pdb++)
h <command> # Show help for specific command
? # Same as h
? <command> # Same as h <command>
# Special variables
__return__ # Return value of current function (when at return)
__exception__ # Current exception being handled
__args__ # Arguments passed to current function
# Enhanced features shortcuts
<Tab> # Enhanced tab completion with syntax highlighting
<Enter> # Repeat last command
sticky # Toggle visual step-by-step mode
ll # Show full function context
interact # Enter interactive Python shell
Key Enhanced Features
Enhanced Tab Completion
PDB++ provides intelligent tab completion with syntax highlighting:
# Example debugging session
def process_data(data_dict):
import pdb; pdb.set_trace()
result = {}
for key, value in data_dict.items():
result[key] = value * 2
return result
data = {"a": 1, "b": 2, "c": 3}
process_data(data)
In the debugger:
(Pdb++) data_d<TAB>
# Shows: data_dict with syntax highlighting
(Pdb++) data_dict.<TAB>
# Shows available methods: items(), keys(), values(), etc.
# With colorful syntax highlighting
(Pdb++) data_dict.k<TAB>
# Completes to: data_dict.keys()
Smart Command Parsing
PDB++ intelligently handles commands vs. variable names. Consider this example:
def example_function():
import pdb; pdb.set_trace()
# Variables that conflict with pdb commands
c = "some string" # 'c' is also a pdb command (continue)
r = 42 # 'r' is also a pdb command (return)
l = [1, 2, 3] # 'l' is also a pdb command (list)
return c, r, l
example_function()
In standard PDB, typing c would continue execution. In PDB++:
(Pdb++) c
# Shows the variable value: 'some string'
(Pdb++) !c
# Executes the continue command (explicit command)
(Pdb++) pp c
# Pretty-prints the variable (alternative)
Colorful Output
PDB++ provides syntax highlighting for code listings and variable values:
def complex_function():
import pdb; pdb.set_trace()
data = {
"users": [
{"name": "Alice", "age": 30, "active": True},
{"name": "Bob", "age": 25, "active": False},
],
"settings": {
"theme": "dark",
"notifications": True
}
}
return data
complex_function()
Commands with enhanced output:
(Pdb++) pp data
# Shows pretty-printed data with syntax highlighting
(Pdb++) l
# Shows code listing with syntax highlighting
(Pdb++) data['users'][0]
# Shows dictionary access with highlighted output
Sticky Mode
Sticky mode provides visual step-by-step execution:
def fibonacci(n):
import pdb; pdb.set_trace()
if n <= 1:
return n
a, b = 0, 1
for i in range(2, n + 1):
a, b = b, a + b
return b
fibonacci(10)
In the debugger:
(Pdb++) sticky
# Enables sticky mode - screen repaints on each step
(Pdb++) s
# Step into - screen shows entire function with current line highlighted
(Pdb++) s
# Next step - screen updates to show new position
Longlist Command
The longlist (or ll) command shows the entire current function:
def process_order(order_data):
import pdb; pdb.set_trace()
# Validate order
if not order_data.get('items'):
raise ValueError("Order must contain items")
# Calculate total
total = 0
for item in order_data['items']:
total += item['price'] * item['quantity']
# Apply discount
discount = order_data.get('discount', 0)
total *= (1 - discount)
# Add tax
tax_rate = 0.08
total *= (1 + tax_rate)
return {
'total': total,
'items_count': len(order_data['items']),
'discount_applied': discount > 0
}
order = {
'items': [
{'price': 10.00, 'quantity': 2},
{'price': 15.50, 'quantity': 1}
],
'discount': 0.1
}
process_order(order)
In the debugger:
(Pdb++) ll
# Shows the entire function with syntax highlighting
(Pdb++) l
# Shows only a few lines around current position (standard behavior)
Configuration
Customize your PDB++ debugging experience with advanced configuration options, syntax highlighting, and personalized settings.
Basic Configuration with .pdbrc
Creating a .pdbrc File
Create a .pdbrc file in your home directory or project root:
# ~/.pdbrc - Global configuration
# or
# ./.pdbrc - Project-specific configuration
# Import necessary modules
import pdb
import sys
from pprint import pprint
# Enable automatic sticky mode
pdb.Pdb.do_sticky = lambda self, arg: self.sticky_toggle()
# Custom aliases for common commands
alias pd pp %1 # Pretty print shorthand
alias st sticky # Sticky mode toggle
alias ll longlist # Long list alias
alias i interact # Interactive shell
alias dt display # Display variable
alias ut undisplay # Remove from display
# Auto-import commonly used modules
import os
import json
import datetime as dt
import collections
# Custom pretty printer for complex objects
def pp_custom(obj):
"""Enhanced pretty printer with type information."""
print(f"Type: {type(obj).__name__}")
if hasattr(obj, '__dict__'):
print("Attributes:")
for key, value in obj.__dict__.items():
print(f" {key}: {repr(value)}")
else:
pprint(obj)
# Make it available in debugging sessions
alias ppc pp_custom(%1)
Syntax Highlighting Configuration
Pygments Configuration
Configure syntax highlighting colors and styles:
# ~/.pdbrc - Syntax highlighting configuration
# Configure Pygments for better syntax highlighting
import pygments
from pygments.formatters import TerminalFormatter, Terminal256Formatter
from pygments.styles import get_style_by_name
# Set preferred color scheme
# Available styles: monokai, solarized-dark, solarized-light,
# github, vim, emacs, default, etc.
PREFERRED_STYLE = 'monokai'
try:
# Try to use 256-color terminal if available
import termcolor
formatter = Terminal256Formatter(style=PREFERRED_STYLE)
except ImportError:
# Fallback to basic terminal colors
formatter = TerminalFormatter(style=PREFERRED_STYLE)
# Function to highlight code with custom style
def highlight_code(code, lexer_name='python'):
"""Highlight code with custom styling."""
from pygments import highlight
from pygments.lexers import get_lexer_by_name
lexer = get_lexer_by_name(lexer_name)
return highlight(code, lexer, formatter)
# Make available in debugging sessions
alias hl highlight_code(%1)
Display List Configuration
Automatic Variable Monitoring
Configure automatic display of important variables:
# ~/.pdbrc - Display list configuration
# Function to automatically set up common display variables
def auto_display_setup():
"""Set up common variables for automatic display."""
local_vars = locals()
# Common variable names to auto-display
common_vars = ['self', 'request', 'response', 'data', 'result',
'items', 'user', 'obj', 'instance']
for var_name in common_vars:
if var_name in local_vars:
print(f"Auto-displaying: {var_name}")
# Note: actual display command needs to be run manually
print(f"Run: display {var_name}")
alias autodisp auto_display_setup()
# Function to clear all displays
def clear_displays():
"""Clear all display expressions."""
# This needs to be implemented based on current display list
print("Use 'undisplay' command to clear individual displays")
print("or restart debugger to clear all displays")
alias cleardisp clear_displays()
Environment Variables
Configure PDB++ behavior through environment variables:
# ~/.bashrc or ~/.zshrc
# Enable syntax highlighting by default
export PDBPP_SYNTAX_HIGHLIGHTING=1
# Set default color scheme
export PDBPP_COLOR_SCHEME=monokai
# Configure tab completion
export PDBPP_TAB_COMPLETION=enhanced
# Set sticky mode as default
export PDBPP_STICKY_MODE=1
# Configure history size
export PDBPP_HISTORY_SIZE=10000
# Set custom pdbrc location
export PDBRC_PATH=~/.config/pdb/pdbrc
Complete Development Configuration
A comprehensive .pdbrc for general development:
# ~/.pdbrc - Complete development configuration
import os
import sys
import json
from pprint import pprint
from datetime import datetime
# ============================================================================
# ALIASES - Common command shortcuts
# ============================================================================
# Navigation aliases
alias u up
alias d down
alias st sticky
alias ll longlist
alias i interact
# Display aliases
alias pd pp %1
alias dt display %1
alias ut undisplay %1
# Inspection aliases
alias vars pp(vars())
alias locals pp(locals())
alias globals pp(globals())
alias modules pp(list(sys.modules.keys()))
# Utility aliases
alias time print(datetime.now())
alias pwd print(os.getcwd())
alias env pp(dict(os.environ))
# ============================================================================
# UTILITY FUNCTIONS
# ============================================================================
def inspect_object(obj):
"""Comprehensive object inspection."""
print(f"\n=== Object Inspection ===")
print(f"Type: {type(obj)}")
print(f"Class: {obj.__class__.__name__}")
print(f"Module: {obj.__class__.__module__}")
if hasattr(obj, '__dict__'):
print(f"\nAttributes ({len(obj.__dict__)}):")
for key, value in obj.__dict__.items():
print(f" {key}: {type(value).__name__} = {repr(value)[:50]}")
print(f"\nMethods:")
methods = [method for method in dir(obj) if callable(getattr(obj, method))]
for method in methods[:10]: # Show first 10 methods
print(f" {method}()")
if len(methods) > 10:
print(f" ... and {len(methods) - 10} more methods")
alias inspect inspect_object(%1)
def show_frame_info():
"""Show current frame information."""
frame = sys._getframe(1) # Get caller's frame
print(f"\n=== Frame Information ===")
print(f"Function: {frame.f_code.co_name}")
print(f"File: {frame.f_code.co_filename}")
print(f"Line: {frame.f_lineno}")
print(f"Local variables: {len(frame.f_locals)}")
print(f"Global variables: {len(frame.f_globals)}")
alias frameinfo show_frame_info()
def quick_test():
"""Quick test current function with sample data."""
print("Quick testing functionality:")
print("1. Check current variables")
print("2. Test with simple inputs")
print("3. Verify expected outputs")
print("\nUse 'interact' for interactive testing")
alias qtest quick_test()
# ============================================================================
# STARTUP MESSAGE
# ============================================================================
print("\n" + "="*60)
print("PDB++ Enhanced Debugger - Custom Configuration Loaded")
print("="*60)
print("Available aliases:")
print(" Navigation: u, d, st, ll, i")
print(" Display: pd, dt, ut")
print(" Inspection: inspect, frameinfo, vars, locals, globals")
print(" Utilities: time, pwd, env, qtest")
print("="*60)
Tutorials
Master PDB++ through hands-on tutorials that demonstrate enhanced debugging features with practical, real-world examples.
Tutorial 1: Getting Started with Enhanced Debugging
Learn the fundamental differences between standard PDB and PDB++ through a practical debugging session.
Scenario: Debugging a Data Processing Pipeline
We'll debug a data processing function that has several issues:
# tutorial1_data_processor.py
def process_user_data(users_data):
"""Process user data and calculate statistics."""
import pdb; pdb.set_trace() # PDB++ breakpoint
processed_users = []
total_age = 0
active_users = 0
for user in users_data:
# Process each user
user_info = {
'id': user['id'],
'name': user['name'].title(),
'age': user['age'],
'is_active': user.get('active', False)
}
# Calculate running totals
total_age += user['age']
if user_info['is_active']:
active_users += 1
processed_users.append(user_info)
# Calculate final statistics
average_age = total_age / len(users_data)
activity_rate = active_users / len(users_data) * 100
return {
'users': processed_users,
'statistics': {
'total_users': len(users_data),
'average_age': round(average_age, 2),
'activity_rate': round(activity_rate, 2),
'active_users': active_users
}
}
# Test data with intentional issues
test_users = [
{'id': 1, 'name': 'alice smith', 'age': 25, 'active': True},
{'id': 2, 'name': 'bob jones', 'age': 30}, # Missing 'active' key
{'id': 3, 'name': 'charlie brown', 'age': 35, 'active': False},
{'id': 4, 'name': 'diana prince', 'age': 28, 'active': True}
]
if __name__ == "__main__":
result = process_user_data(test_users)
print("Processing complete!")
print(f"Total users: {result['statistics']['total_users']}")
print(f"Average age: {result['statistics']['average_age']}")
print(f"Activity rate: {result['statistics']['activity_rate']}%")
Debugging Session Walkthrough
Run the script and follow along with the debugging session:
python tutorial1_data_processor.py
Step 1: Initial Breakpoint
> tutorial1_data_processor.py(4)process_user_data()
-> processed_users = []
(Pdb++)
Notice the colorful (Pdb++) prompt indicating enhanced PDB is active.
Step 2: Examine Input Data with Enhanced Tab Completion
(Pdb++) users_data<TAB>
# Shows: users_data (with syntax highlighting)
(Pdb++) pp users_data
# Pretty-printed output with syntax highlighting:
[{'active': True, 'age': 25, 'id': 1, 'name': 'alice smith'},
{'age': 30, 'id': 2, 'name': 'bob jones'},
{'active': False, 'age': 35, 'id': 3, 'name': 'charlie brown'},
{'active': True, 'age': 28, 'id': 4, 'name': 'diana prince'}]
Step 3: Use Enhanced Navigation
(Pdb++) ll
# Shows entire function with syntax highlighting
# Much better than standard 'l' command
(Pdb++) l
# Shows traditional limited view for comparison
Step 4: Smart Command Parsing
(Pdb++) n
# Step to next line
(Pdb++) n
# Step to next line
(Pdb++) n
# Now we're in the for loop
(Pdb++) user
# In standard PDB, this might conflict with commands
# In PDB++, it shows the variable value with highlighting
{'id': 1, 'name': 'alice smith', 'age': 25, 'active': True}
Step 5: Set Up Display List
(Pdb++) display len(processed_users)
display len(processed_users): 0
(Pdb++) display total_age
display total_age: 0
(Pdb++) display active_users
display active_users: 0
(Pdb++) n
# As you step, watch the display values update automatically
Step 6: Interactive Exploration
(Pdb++) interact
# Starts interactive Python shell with current scope
>>> user.get('active', 'MISSING')
True
>>> len(users_data)
4
>>> [u.get('active', 'MISSING') for u in users_data]
[True, 'MISSING', False, True]
>>> exit() # Return to debugger
(Pdb++)
Tutorial 2: Using Sticky Mode for Visual Debugging
Learn to use sticky mode for visual, step-by-step debugging that shows your entire function context.
Scenario: Debugging a Recursive Algorithm
We'll debug a recursive function with a subtle bug:
# tutorial2_fibonacci.py
def fibonacci_with_cache(n, cache=None):
"""Calculate Fibonacci number with memoization."""
import pdb; pdb.set_trace()
# Initialize cache if not provided
if cache is None:
cache = {}
# Base cases
if n <= 1:
return n
# Check cache first
if n in cache:
print(f"Cache hit for n={n}")
return cache[n]
# Calculate recursively
print(f"Calculating fib({n})")
result = fibonacci_with_cache(n-1, cache) + fibonacci_with_cache(n-2, cache)
# Store in cache
cache[n] = result
return result
def test_fibonacci():
"""Test the fibonacci function."""
print("Testing Fibonacci calculation...")
# Test several values
test_values = [0, 1, 2, 3, 5, 8]
for n in test_values:
result = fibonacci_with_cache(n)
print(f"fib({n}) = {result}")
if __name__ == "__main__":
test_fibonacci()
Sticky Mode Debugging Session
Step 1: Enable Sticky Mode
python tutorial2_fibonacci.py
When the debugger starts:
(Pdb++) sticky
# Sticky mode enabled - screen will repaint on each step
Step 2: Visual Step-by-Step Execution
With sticky mode enabled, each step will show the entire function with your current position highlighted:
(Pdb++) s
# Screen shows entire function with current line highlighted
# Much easier to follow execution flow
(Pdb++) s
# Screen updates to show new position
# You can see the complete context at all times
Step 3: Monitor Recursive Calls
(Pdb++) display n
display n: 0
(Pdb++) display cache
display cache: {}
(Pdb++) c
# Continue to next breakpoint (recursive call)
# Watch how n and cache change between calls
Tutorial 3: Interactive Interpreter and Variable Inspection
Learn to leverage PDB++'s interactive interpreter for complex debugging scenarios and advanced variable analysis.
Interactive Debugging Session
# tutorial3_data_analysis.py
import json
from datetime import datetime, timedelta
from collections import defaultdict
class DataAnalyzer:
"""Analyzes user activity data."""
def __init__(self):
self.raw_data = []
self.processed_data = {}
self.analysis_results = {}
def analyze_patterns(self):
"""Analyze user activity patterns."""
import pdb; pdb.set_trace()
self.analysis_results = {}
for user_id, activities in self.processed_data.items():
user_analysis = {
'total_activities': len(activities),
'activity_types': {},
'hourly_distribution': defaultdict(int),
'daily_distribution': defaultdict(int),
'most_active_day': None,
'most_active_hour': None
}
# Analyze activity types
for activity in activities:
activity_type = activity['activity']
user_analysis['activity_types'][activity_type] = \
user_analysis['activity_types'].get(activity_type, 0) + 1
# Track hourly and daily patterns
user_analysis['hourly_distribution'][activity['hour']] += 1
user_analysis['daily_distribution'][activity['day_of_week']] += 1
self.analysis_results[user_id] = user_analysis
return self.analysis_results
Interactive Analysis Session:
(Pdb++) interact
# Start interactive interpreter
>>> # Explore user activities
>>> for user_id, activities in self.processed_data.items():
... print(f"User {user_id}: {len(activities)} activities")
User user_001: 3 activities
User user_002: 2 activities
>>> # Check activity types
>>> user_001_activities = self.processed_data['user_001']
>>> [activity['activity'] for activity in user_001_activities]
['login', 'page_view', 'logout']
>>> # Custom analysis function
>>> def analyze_user_behavior(user_id):
... """Custom analysis function for interactive debugging."""
... if user_id not in self.processed_data:
... return "User not found"
...
... activities = self.processed_data[user_id]
... timeline = sorted(activities, key=lambda x: x['timestamp'])
... return {'timeline': timeline, 'count': len(activities)}
>>> behavior = analyze_user_behavior('user_001')
>>> behavior['count']
3
>>> exit()
Integration
Integrate PDB++ into your development workflow with IDEs, frameworks, testing tools, and CI/CD pipelines for enhanced debugging productivity.
IDE Integration
Visual Studio Code Integration
PDB++ works seamlessly with VS Code's Python debugging capabilities and can be used alongside or instead of the built-in debugger.
Basic VS Code Setup:
- Install PDB++ in your environment:
pip install pdbpp
- Configure VS Code settings (
.vscode/settings.json):
{
"python.terminal.activateEnvironment": true,
"python.debugging.console": "integratedTerminal",
"python.linting.enabled": true,
"terminal.integrated.env.osx": {
"PYTHONBREAKPOINT": "pdb.set_trace"
},
"terminal.integrated.env.linux": {
"PYTHONBREAKPOINT": "pdb.set_trace"
},
"terminal.integrated.env.windows": {
"PYTHONBREAKPOINT": "pdb.set_trace"
}
}
- Create launch configuration (
.vscode/launch.json):
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File with PDB++",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"cwd": "${workspaceFolder}",
"env": {
"PYTHONBREAKPOINT": "pdb.set_trace",
"PYTHONPATH": "${workspaceFolder}"
},
"justMyCode": false
}
]
}
PyCharm Integration
PyCharm can work with PDB++ through external debugging sessions.
PyCharm Setup:
- Configure external tools in PyCharm:
- Go to File → Settings → Tools → External Tools
- Add new tool:
- Name: "Debug with PDB++"
- Program:
python - Arguments:
-m pdb $FilePath$ - Working directory:
$ProjectFileDir$
Testing Integration
pytest Integration
Enhanced testing with PDB++ and pytest:
# conftest.py
import pytest
import os
# Ensure PDB++ is used for debugging tests
os.environ.setdefault('PYTHONBREAKPOINT', 'pdb.set_trace')
@pytest.fixture
def sample_data():
"""Sample data fixture for testing."""
return {
'users': [
{'id': 1, 'name': 'Alice', 'active': True},
{'id': 2, 'name': 'Bob', 'active': False}
],
'settings': {
'theme': 'dark',
'notifications': True
}
}
class DebugHelper:
"""Helper class for test debugging."""
@staticmethod
def debug_test_data(data, description="Test data"):
"""Debug test data with PDB++."""
import pdb; pdb.set_trace()
print(f"Debugging: {description}")
print(f"Data type: {type(data)}")
print(f"Data: {data}")
@pytest.fixture
def debug_helper():
"""Debug helper fixture."""
return DebugHelper()
Test Cases with PDB++:
# test_with_pdbpp.py
import pytest
def test_data_processing_with_debug(sample_data, debug_helper):
"""Test data processing with debugging support."""
import pdb; pdb.set_trace()
# Debug input data
users = sample_data['users']
active_users = [user for user in users if user['active']]
# Use debug helper
debug_helper.debug_test_data(active_users, "Active users")
assert len(active_users) == 1
assert active_users[0]['name'] == 'Alice'
def test_error_handling_with_debug():
"""Test error handling with debugging."""
def problematic_function(data):
import pdb; pdb.set_trace()
if not data:
raise ValueError("Data cannot be empty")
return len(data)
# Test normal case
result = problematic_function([1, 2, 3])
assert result == 3
# Test error case with debugging
with pytest.raises(ValueError):
# Debugger will stop here to examine the error
problematic_function([])
Running Tests with PDB++:
# Run tests with PDB++ debugging
pytest --pdb # Drop into debugger on failures
pytest --pdbcls=pdb:Pdb # Explicitly use PDB++
pytest -s test_file.py # Show output (don't capture)
pytest --tb=short --pdb # Short traceback with debugger
# Run specific test with debugging
pytest -s -k "test_data_processing" --pdb
# Debug test setup/teardown
pytest --setup-show --pdb
CI/CD Integration
GitHub Actions with PDB++
Configure GitHub Actions for debugging with PDB++:
# .github/workflows/debug-tests.yml
name: Debug Tests with PDB++
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
debug-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.9'
- name: Install dependencies
run: |
pip install --upgrade pip
pip install pdbpp pytest
pip install -r requirements.txt
- name: Run tests with debugging info
run: |
# Set environment for PDB++
export PYTHONBREAKPOINT=pdb.set_trace
# Run tests with verbose output
pytest -v --tb=short
# Run specific debug tests (non-interactive)
pytest tests/test_debug.py -v
- name: Debug on failure
if: failure()
run: |
echo "Tests failed - debugging information:"
python -c "
import sys
print('Python version:', sys.version)
import pdb
print('PDB module:', pdb.__file__)
try:
import pdbpp
print('PDB++ available')
except ImportError:
print('PDB++ not available')
"
Docker Integration
Dockerfile for development with PDB++:
# Dockerfile.debug
FROM python:3.9-slim
# Install system dependencies
RUN apt-get update && apt-get install -y \
gcc \
&& rm -rf /var/lib/apt/lists/*
# Set working directory
WORKDIR /app
# Copy requirements
COPY requirements.txt .
COPY requirements-dev.txt .
# Install Python dependencies including PDB++
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install --no-cache-dir -r requirements-dev.txt
RUN pip install pdbpp
# Set environment for debugging
ENV PYTHONBREAKPOINT=pdb.set_trace
ENV PYTHONUNBUFFERED=1
# Copy application code
COPY . .
# Expose port for web applications
EXPOSE 8000
# Default command
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
Docker Compose for debugging:
# docker-compose.debug.yml
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile.debug
ports:
- "8000:8000"
volumes:
- .:/app
environment:
- PYTHONBREAKPOINT=pdb.set_trace
- DEBUG=1
stdin_open: true # Enable interactive debugging
tty: true # Allocate TTY for PDB++
command: python manage.py runserver 0.0.0.0:8000
db:
image: postgres:13
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD: password
ports:
- "5432:5432"
Comparison with pdbp (Modern Alternative)
pdbp is a modern alternative to pdbpp that addresses some compatibility issues:
# pdbp_comparison.py
"""
Comparison between pdbpp and pdbp for modern Python development.
"""
# pdbp installation and usage
"""
# Install pdbp (modern alternative)
pip install pdbp
# Usage (same as pdbpp)
import pdb; pdb.set_trace() # Uses pdbp if installed
# Or explicitly
import pdbp; pdbp.set_trace()
"""
def demo_pdbp_features():
"""Demonstrate pdbp features."""
import pdb; pdb.set_trace() # Will use pdbp if installed
# pdbp features (similar to pdbpp):
# - Syntax highlighting
# - Tab completion
# - Sticky mode
# - Better Windows support (Python 3.11+)
# - Improved dependencies (tabcompleter vs fancycompleter)
data = {
'users': ['Alice', 'Bob', 'Charlie'],
'settings': {'theme': 'dark', 'debug': True}
}
# Use all the same commands as pdbpp
return data
Migration from pdbpp to pdbp:
# Uninstall pdbpp
pip uninstall pdbpp fancycompleter
# Install pdbp
pip install pdbp
# No code changes needed - same interface
Feature Comparison:
| Feature | pdbpp | pdbp | Notes |
|---|---|---|---|
| Syntax Highlighting | ✅ | ✅ | Both support colorful output |
| Tab Completion | ✅ | ✅ | pdbp uses tabcompleter |
| Sticky Mode | ✅ | ✅ | Same functionality |
| Windows Support | ⚠️ | ✅ | pdbp better for Python 3.11+ |
| Dependencies | fancycompleter | tabcompleter | pdbp has fewer issues |
| Drop-in Replacement | ✅ | ✅ | Both replace standard pdb |
| Active Development | ⚠️ | ✅ | pdbp more actively maintained |
Further Reading
Official Documentation
- PDB++ GitHub Repository - Official PDB++ documentation and source code
- pdbp Alternative - Modern PDB++ alternative
- Python PDB Documentation - Base PDB reference
- fancycompleter - Tab completion library used by PDB++
Features and Guides
- PDB++ Features - Complete feature list
- Real Python Debugging - Python debugging guide
- Python Debugging with PDB - Python Module of the Week guide
Development Tools
- pytest Documentation - pytest testing framework
- VS Code Python Debugging - VS Code debugging guide
PDB++ transforms terminal-based debugging with enhanced features and modern conveniences—master it to debug Python applications more effectively with colorful output, smart completion, and visual debugging modes.