Add debugging with pdb

Below is the new section you can insert right after Section 14 – Project Structure Example (or before the Mini-Project).

Add debugging with pdb

Add debugging with pdb

Below is the new section you can insert right after Section 14.5 – Testing with pytest (or before the Mini-Project).
It follows the same clean, professional style and includes real-world debugging workflows using pdb and ipdb.


14.6 Debugging with pdb (and ipdb)

“Debugging is twice as hard as writing the code in the first place.”Brian Kernighan


Why Debug?

  • print() debugging → fragile, clutters code
  • pdbinteractive, step-by-step control
  • Works in scripts, functions, Jupyter, and even post-mortem

1. Install ipdb (Enhanced pdb)

pip install ipdb

ipdb = pdb + IPython features:
- Syntax highlighting
- Tab completion
- Better ! shell access

Add to requirements.txt:

ipdb>=0.13

2. Basic pdb Usage

Method 1: Insert breakpoint in code

# src/buggy.py
def calculate_tax(income: float) -> float:
    import pdb; pdb.set_trace()  # ← BREAKPOINT
    rate = 0.2
    if income > 100_000:
        rate = 0.3
    tax = income * rate
    return round(tax, 2)

print(calculate_tax(120_000))

Run:

python src/buggy.py

You’ll see:

> /path/to/buggy.py(4)calculate_tax()
-> rate = 0.2
(Pdb)

3. Essential pdb Commands

Command Shortcut Action
list l Show current code
next n Step over (next line)
step s Step into function
continue c Run until next breakpoint
return r Run until function returns
print(var) p var Print variable
pp dict Pretty-print
where w Show stack trace
up / down Move up/down call stack
interact Start local Python REPL
quit q Exit debugger

Example Session:

(Pdb) l
  1     def calculate_tax(income: float) -> float:
  2         import pdb; pdb.set_trace()
  3         rate = 0.2
  4  ->     if income > 100_000:
  5             rate = 0.3
  6         tax = income * rate
  7         return round(tax, 2)

(Pdb) p income
120000.0
(Pdb) n
> ...line 5...
(Pdb) p rate
0.3
(Pdb) c  # continue

4. Modern Alternative: breakpoint() (Python 3.7+)

No need to import pdb!

def risky_operation(x: int):
    result = x / (x - 5)
    breakpoint()  # ← Auto uses ipdb if installed
    return result * 2

print(risky_operation(3))

Python automatically uses:
- ipdb → if installed
- pdb → fallback


5. Post-Mortem Debugging (After Crash)

# src/crash.py
def divide(a, b):
    return a / b

divide(10, 0)  # ZeroDivisionError

Run with post-mortem:

python -m pdb src/crash.py

At crash:

ZeroDivisionError: division by zero
Uncaught exception. Entering post mortem debugging
> ...crash.py(2)divide()
-> return a / b
(Pdb) p a, b
(10, 0)
(Pdb) where
...

Or automatically:

python -m pdb -c continue src/crash.py

6. Conditional Breakpoints

def process_items(items):
    for i, item in enumerate(items):
        if i == 3:  # only stop at index 3
            breakpoint()
        print(f"Processing {item}")

Or in pdb:

(Pdb) break calculate_tax, income > 150000
(Pdb) c

7. Debugging in VS Code

  1. Install Python extension
  2. Set breakpoint (click left gutter)
  3. Press F5 → Select "Python File"
  4. Debug panel: watch variables, call stack, breakpoints

launch.json example:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Debug with ipdb",
            "type": "python",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal",
            "env": {"PYTHONBREAKPOINT": "ipdb.set_trace"}
        }
    ]
}

Set PYTHONBREAKPOINT=ipdb.set_tracebreakpoint() uses ipdb


8. Real-World Example: Debug the Task Manager

# task_manager.py (add this line to debug)
def add(self, title: str):
    if not title.strip():
        raise ValueError("Title cannot be empty")
    self.tasks.append(Task(title))
    breakpoint()  # ← STOP HERE
    self.save()

Run:

python task_manager.py add "  "

You’ll hit:

(Pdb) p title
'  '
(Pdb) p title.strip()
''
(Pdb) up
> ...main()...
(Pdb) p sys.argv
['task_manager.py', 'add', '  ']

Now you see the bug: empty/whitespace titles!


9. Best Practices

Do Don’t
Use breakpoint() in Python ≥3.7 Use print() for complex logic
Remove pdb.set_trace() before commit Commit pdb lines
Use conditional breakpoints Stop on every loop iteration
Combine with logging for production Rely only on debugger
Use ipdb in dev Use raw pdb if ipdb is available

10. Quick Reference

# Run with auto post-mortem
python -m pdb -c continue script.py

# Force ipdb
PYTHONBREAKPOINT=ipdb.set_trace python script.py

# In code
breakpoint()  # best
# or
import ipdb; ipdb.set_trace()

Bonus: .pdbrc – Custom Startup

Create ~/.pdbrc:

# ~/.pdbrc
alias pp import pprint; pprint.pprint(%1)
alias vars p self.__dict__ if hasattr(self, '__dict__') else locals()

Now in debugger:

(Pdb) pp my_dict
(Pdb) vars

Summary

Tool Use Case
breakpoint() Modern, clean, auto-uses ipdb
ipdb Rich REPL, tab completion
pdb Always available, lightweight
VS Code GUI debugging, breakpoints, watch
Post-mortem Debug crashes instantly

Now you can find and fix bugs like a pro!

Next Step: Add a deliberate bug in the Task Manager, then use breakpoint() to fix it interactively.


Insert this section into your notes after Section 14.5.
Your Python tutorial is now complete with testing + debugging.


Happy Debugging!

Last updated: Nov 12, 2025

Add debugging with pdb

Below is the new section you can insert right after Section 14 – Project Structure Example (or before the Mini-Project).

Add debugging with pdb

Add debugging with pdb

Below is the new section you can insert right after Section 14.5 – Testing with pytest (or before the Mini-Project).
It follows the same clean, professional style and includes real-world debugging workflows using pdb and ipdb.


14.6 Debugging with pdb (and ipdb)

“Debugging is twice as hard as writing the code in the first place.”Brian Kernighan


Why Debug?

  • print() debugging → fragile, clutters code
  • pdbinteractive, step-by-step control
  • Works in scripts, functions, Jupyter, and even post-mortem

1. Install ipdb (Enhanced pdb)

pip install ipdb

ipdb = pdb + IPython features:
- Syntax highlighting
- Tab completion
- Better ! shell access

Add to requirements.txt:

ipdb>=0.13

2. Basic pdb Usage

Method 1: Insert breakpoint in code

# src/buggy.py
def calculate_tax(income: float) -> float:
    import pdb; pdb.set_trace()  # ← BREAKPOINT
    rate = 0.2
    if income > 100_000:
        rate = 0.3
    tax = income * rate
    return round(tax, 2)

print(calculate_tax(120_000))

Run:

python src/buggy.py

You’ll see:

> /path/to/buggy.py(4)calculate_tax()
-> rate = 0.2
(Pdb)

3. Essential pdb Commands

Command Shortcut Action
list l Show current code
next n Step over (next line)
step s Step into function
continue c Run until next breakpoint
return r Run until function returns
print(var) p var Print variable
pp dict Pretty-print
where w Show stack trace
up / down Move up/down call stack
interact Start local Python REPL
quit q Exit debugger

Example Session:

(Pdb) l
  1     def calculate_tax(income: float) -> float:
  2         import pdb; pdb.set_trace()
  3         rate = 0.2
  4  ->     if income > 100_000:
  5             rate = 0.3
  6         tax = income * rate
  7         return round(tax, 2)

(Pdb) p income
120000.0
(Pdb) n
> ...line 5...
(Pdb) p rate
0.3
(Pdb) c  # continue

4. Modern Alternative: breakpoint() (Python 3.7+)

No need to import pdb!

def risky_operation(x: int):
    result = x / (x - 5)
    breakpoint()  # ← Auto uses ipdb if installed
    return result * 2

print(risky_operation(3))

Python automatically uses:
- ipdb → if installed
- pdb → fallback


5. Post-Mortem Debugging (After Crash)

# src/crash.py
def divide(a, b):
    return a / b

divide(10, 0)  # ZeroDivisionError

Run with post-mortem:

python -m pdb src/crash.py

At crash:

ZeroDivisionError: division by zero
Uncaught exception. Entering post mortem debugging
> ...crash.py(2)divide()
-> return a / b
(Pdb) p a, b
(10, 0)
(Pdb) where
...

Or automatically:

python -m pdb -c continue src/crash.py

6. Conditional Breakpoints

def process_items(items):
    for i, item in enumerate(items):
        if i == 3:  # only stop at index 3
            breakpoint()
        print(f"Processing {item}")

Or in pdb:

(Pdb) break calculate_tax, income > 150000
(Pdb) c

7. Debugging in VS Code

  1. Install Python extension
  2. Set breakpoint (click left gutter)
  3. Press F5 → Select "Python File"
  4. Debug panel: watch variables, call stack, breakpoints

launch.json example:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Debug with ipdb",
            "type": "python",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal",
            "env": {"PYTHONBREAKPOINT": "ipdb.set_trace"}
        }
    ]
}

Set PYTHONBREAKPOINT=ipdb.set_tracebreakpoint() uses ipdb


8. Real-World Example: Debug the Task Manager

# task_manager.py (add this line to debug)
def add(self, title: str):
    if not title.strip():
        raise ValueError("Title cannot be empty")
    self.tasks.append(Task(title))
    breakpoint()  # ← STOP HERE
    self.save()

Run:

python task_manager.py add "  "

You’ll hit:

(Pdb) p title
'  '
(Pdb) p title.strip()
''
(Pdb) up
> ...main()...
(Pdb) p sys.argv
['task_manager.py', 'add', '  ']

Now you see the bug: empty/whitespace titles!


9. Best Practices

Do Don’t
Use breakpoint() in Python ≥3.7 Use print() for complex logic
Remove pdb.set_trace() before commit Commit pdb lines
Use conditional breakpoints Stop on every loop iteration
Combine with logging for production Rely only on debugger
Use ipdb in dev Use raw pdb if ipdb is available

10. Quick Reference

# Run with auto post-mortem
python -m pdb -c continue script.py

# Force ipdb
PYTHONBREAKPOINT=ipdb.set_trace python script.py

# In code
breakpoint()  # best
# or
import ipdb; ipdb.set_trace()

Bonus: .pdbrc – Custom Startup

Create ~/.pdbrc:

# ~/.pdbrc
alias pp import pprint; pprint.pprint(%1)
alias vars p self.__dict__ if hasattr(self, '__dict__') else locals()

Now in debugger:

(Pdb) pp my_dict
(Pdb) vars

Summary

Tool Use Case
breakpoint() Modern, clean, auto-uses ipdb
ipdb Rich REPL, tab completion
pdb Always available, lightweight
VS Code GUI debugging, breakpoints, watch
Post-mortem Debug crashes instantly

Now you can find and fix bugs like a pro!

Next Step: Add a deliberate bug in the Task Manager, then use breakpoint() to fix it interactively.


Insert this section into your notes after Section 14.5.
Your Python tutorial is now complete with testing + debugging.


Happy Debugging!

Last updated: Nov 12, 2025