# Python Debugging with VSCode
**Live debugging of Python scripts in Revit using VSCode's debugger.**
RevitDevTool integrates `debugpy` to enable full VSCode debugging capabilities: set breakpoints, step through code, inspect variables, and debug Revit API calls in real-time.

---
## Overview
```mermaid
flowchart TD
subgraph VSCode["VSCode (Debugger)"]
VS1[Set breakpoints in Python scripts]
VS2[Press F5 to attach to Revit]
VS3[Step through code execution]
VS4[Inspect variables and Revit API objects]
end
subgraph Revit["Revit + RevitDevTool"]
R1[Start debugpy listener on port 5678]
R2[Wait for VSCode to attach]
R3[Show connection status in UI]
R4[Execute scripts with debugpy active]
R5[Pause at breakpoints]
R6[Send variable data to VSCode]
R1 --> R2 --> R3 --> R4 --> R5 --> R6
end
VSCode <-->|debugpy protocol
port 5678| Revit
```
---
## Quick Start
### 1. Configure Debug Port (Optional)
Open RevitDevTool Settings and set the debug port (default: 5678):

**Debug status indicator** in Trace panel toolbar:
- 🔴 **Red dot** - Debugger not connected
- 🟢 **Green dot** - VSCode debugger attached and ready
### 2. Create VSCode Launch Configuration
Add to `.vscode/launch.json` in your script folder:
```json
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach Revit Python",
"type": "debugpy",
"request": "attach",
"connect": {
"host": "localhost",
"port": 5678
}
}
]
}
```
**Configuration options:**
- `port: 5678` - Must match RevitDevTool debug port setting
- `justMyCode: false` - Allows debugging into Revit API and libraries
- `pathMappings` - Maps local files to execution paths
### 3. Start Debugging
**Step-by-step workflow:**
1. **Launch Revit** with RevitDevTool installed
2. **Open script folder** in VSCode
3. **Set breakpoints** (click left margin, red dot appears)
4. **Press F5** in VSCode (or Run → Start Debugging)
5. **Check status** - Green dot 🟢 in Trace panel = connected
6. **Execute script** in RevitDevTool
7. **Debugger pauses** at your breakpoints
---
## Debugging Features
### Full VSCode Debugging Capabilities
✅ **Breakpoints**
- Click line number margin to set/remove
- Red dot indicates active breakpoint
- Execution pauses when breakpoint is hit
✅ **Step Controls**
- **Step Over (F10)** - Execute current line, move to next
- **Step Into (F11)** - Enter function calls
- **Step Out (Shift+F11)** - Exit current function
- **Continue (F5)** - Resume until next breakpoint
✅ **Variable Inspection**
- **Hover** over variables to see values
- **Variables panel** shows all local/global variables
- **Watch expressions** - Add custom expressions to monitor
- **Call stack** - Navigate execution frames
✅ **Debug Console**
- Evaluate Python expressions during pause
- Access all variables in current scope
- Test Revit API calls interactively
✅ **Conditional Breakpoints**
- Right-click breakpoint → Edit Breakpoint
- Add condition: `wall.Id.IntegerValue > 1000`
- Breaks only when condition is true
✅ **Revit API Inspection**
- Inspect `__revit__` (UIApplication)
- Examine `doc` (Document)
- Explore elements, parameters, geometry
- View collection contents
---
## Example Debugging Session
### Script with Breakpoints
```python
# /// script
# dependencies = ["numpy"]
# ///
import numpy as np
from Autodesk.Revit import DB
doc = __revit__.ActiveUIDocument.Document
# Set breakpoint here (line 10)
walls = DB.FilteredElementCollector(doc).OfClass(DB.Wall).ToElements()
areas = []
for wall in walls:
# Set breakpoint here (line 15) to inspect each wall
curve = wall.Location.Curve
length = curve.Length
# Conditional breakpoint: length > 10
areas.append(length)
print(f"Wall {wall.Id}: {length:.2f} ft")
# Set breakpoint here (line 23)
avg_length = np.mean(areas)
print(f"Average wall length: {avg_length:.2f} ft")
```
### Debugging Workflow
**1. Set breakpoints:**
- Line 10: Before collecting walls
- Line 15: Inside loop to inspect each wall
- Line 23: After calculation
**2. Execute script:**
- Script runs until line 10
- Debugger pauses
**3. Inspect variables:**
- Hover over `doc` → See Document properties
- Variables panel shows `__revit__`, `doc`, `np`
**4. Step through:**
- Press F10 (Step Over) → Line 13
- Variables panel now shows `walls` collection
- Expand `walls` to see elements
**5. Continue to loop:**
- Press F5 (Continue) → Pauses at line 15
- Inspect `wall` variable
- Check `curve`, `length` values
- Debug Console: Type `wall.Name` to see wall name
**6. Conditional breakpoint:**
- Right-click line 15 → Edit Breakpoint
- Condition: `length > 10`
- Press F5 → Only pauses for long walls
**7. Complete execution:**
- Press F5 to finish
- Check final output in Trace panel
---
## Advanced Debugging Patterns
### Pattern 1: Debug Element Collection
```python
from Autodesk.Revit import DB
doc = __revit__.ActiveUIDocument.Document
# Set breakpoint here
collector = DB.FilteredElementCollector(doc)
walls = collector.OfClass(DB.Wall).ToElements()
# Debug Console during pause:
# >>> len(list(walls))
# >>> walls[0].Name
# >>> walls[0].GetType().Name
```
### Pattern 2: Debug Parameter Access
```python
from Autodesk.Revit import DB
doc = __revit__.ActiveUIDocument.Document
wall = doc.GetElement(DB.ElementId(123456))
# Set breakpoint here
params = wall.Parameters
# Inspect in Variables panel:
# - Expand 'params' to see all parameters
# - Hover over individual parameters
# - Check 'param.Definition.Name'
```
### Pattern 3: Debug Geometry Operations
```python
from Autodesk.Revit import DB
doc = __revit__.ActiveUIDocument.Document
wall = doc.GetElement(DB.ElementId(123456))
# Set breakpoint here
curve = wall.Location.Curve
start = curve.GetEndPoint(0)
end = curve.GetEndPoint(1)
# Inspect geometry:
# - Check 'start.X', 'start.Y', 'start.Z'
# - Verify 'curve.Length'
# - Test transformations in Debug Console
```
### Pattern 4: Debug Exception Handling
```python
from Autodesk.Revit import DB
doc = __revit__.ActiveUIDocument.Document
try:
# Set breakpoint here
element = doc.GetElement(DB.ElementId(999999))
name = element.Name # May throw if element is None
except Exception as e:
# Set breakpoint here to inspect exception
print(f"Error: {e}")
# Debug Console: Check 'type(e)', 'str(e)'
```
---
## Troubleshooting
### Debugger Won't Connect
**Symptoms:**
- Status indicator stays red 🔴
- VSCode shows "Connection refused"
- Timeout when attaching
**Solutions:**
1. **Check port availability:**
```powershell
netstat -ano | findstr :5678
```
If port is in use, change port in RevitDevTool Settings
2. **Verify debugpy installation:**
- Check Trace panel for debugpy setup logs
- Look for "Debugpy listening on port 5678" message
3. **Restart Revit:**
- Close Revit completely
- Relaunch and try again
4. **Check firewall:**
- Allow Python.exe through Windows Firewall
- Allow localhost connections on configured port
### Breakpoints Not Hit
**Symptoms:**
- Breakpoints show as gray (not red)
- Script executes without pausing
- "Breakpoint in file that does not exist" warning
**Solutions:**
1. **Verify VSCode is attached:**
- Check green dot 🟢 in Trace panel
- VSCode Debug toolbar should be visible
2. **Check path mappings:**
```json
"pathMappings": [
{
"localRoot": "${workspaceFolder}",
"remoteRoot": "${workspaceFolder}"
}
]
```
Ensure paths match your script location
3. **Use absolute paths:**
- Open script folder as VSCode workspace root
- Avoid nested folders in pathMappings
4. **Set `justMyCode: false`:**
```json
"justMyCode": false
```
Allows debugging into libraries
### Variables Not Showing
**Symptoms:**
- Variables panel empty
- Hover shows no information
- Objects show as ``
**Solutions:**
1. **Use Debug Console:**
- Type variable names directly
- Access properties: `wall.Name`, `doc.Title`
- Call methods: `element.GetType().Name`
2. **Check call stack:**
- Click different frames in Call Stack panel
- Variables change per frame
3. **Expand collections:**
- Click arrow next to collection variables
- May take time for large collections
4. **Revit API objects:**
- Some show as `` (expected)
- Access properties directly in Debug Console
### Performance Issues
**Symptoms:**
- Slow stepping through code
- UI freezes during debugging
- Long pauses between steps
**Solutions:**
1. **Use conditional breakpoints:**
- Instead of breaking every iteration
- Only break when condition is true
2. **Disable breakpoints:**
- Right-click breakpoint → Disable
- Or uncheck in Breakpoints panel
3. **Detach when done:**
- Press Shift+F5 to detach
- Or click Stop in Debug toolbar
4. **Limit collection inspection:**
- Don't expand large collections in Variables panel
- Use Debug Console for specific items
---
## Best Practices
### 1. Strategic Breakpoint Placement
**Good:**
```python
# Set breakpoint before critical operations
result = complex_calculation(data) # ← Breakpoint here
print(result)
```
**Avoid:**
```python
# Don't set breakpoints in tight loops
for i in range(10000):
process(i) # ← Avoid breakpoint here (too slow)
```
### 2. Use Conditional Breakpoints
**Instead of:**
```python
for wall in walls:
if wall.Id.IntegerValue == 123456:
print(wall.Name) # ← Breakpoint here
```
**Use conditional breakpoint:**
```python
for wall in walls:
print(wall.Name) # ← Conditional: wall.Id.IntegerValue == 123456
```
### 3. Debug Console for Quick Checks
**During pause, test expressions:**
```python
# In Debug Console:
>>> wall.Name
'Basic Wall'
>>> wall.GetType().Name
'Wall'
>>> dir(wall) # See all available methods
[...]
```
### 4. Inspect Revit API Objects
**Pattern:**
```python
element = doc.GetElement(element_id)
# Set breakpoint here
# In Debug Console:
>>> element.Category.Name
>>> element.Parameters.Size
>>> [p.Definition.Name for p in element.Parameters]
```
### 5. Clean Up After Debugging
**Before production:**
- Remove all breakpoints (Ctrl+Shift+F9)
- Detach debugger (Shift+F5)
- Test script runs normally without debugger
---
## Performance Notes
### Debugging Overhead
**Minimal when not attached:**
- debugpy listener runs in background
- No performance impact on script execution
- Status check is lightweight
**Moderate when attached:**
- Slight slowdown during execution (expected)
- Stepping through code is slower (by design)
- Variable inspection may take time for large objects
**Best practices:**
- Attach only when debugging needed
- Detach when done (Shift+F5)
- Use conditional breakpoints for loops
### Memory Considerations
**debugpy memory usage:**
- ~10-20 MB when listener is active
- Additional memory during debugging session
- Released when debugger detaches
**Large collections:**
- Avoid expanding huge collections in Variables panel
- Use Debug Console for specific items
- Consider filtering data before inspection
---
## Comparison with Other Tools
### vs pyRevit Debugging
| Feature | RevitDevTool | pyRevit |
| ----------------------------- | -------------- | ------------------------- |
| **Debugger** | VSCode debugpy | Limited (print debugging) |
| **Breakpoints** | Full support | Not available |
| **Variable inspection** | Full VSCode UI | Print statements only |
| **Step through code** | Yes (F10, F11) | No |
| **Python version** | Python 3.13 | IronPython 2.7 |
| **IDE integration** | Native VSCode | External tools only |
### vs Traditional Add-in Debugging
| Feature | Python Debugging | C# Add-in Debugging |
| -------------------------- | ------------------ | ------------------------ |
| **Setup** | Launch config only | Visual Studio project |
| **Attach time** | Instant (F5) | Attach to process |
| **Restart required** | No | Yes (after code changes) |
| **Breakpoints** | Full support | Full support |
| **Performance** | Slight overhead | Native speed |
| **Ease of use** | Very easy | Moderate |
---
## See Also
- **[Python Runtime](CodeExecute-PythonExecution.md)** - Complete Python execution mechanism
- **[Stub Generation](CodeExecute-StubGeneration.md)** - IDE autocomplete setup
- **[vs pyRevit](CodeExecute-VsPyRevit.md)** - Comparison with pyRevit
- **[CodeExecute Overview](CodeExecute-Overview.md)** - Module overview
---
## Demo Script
Try the included demo script to test debugging:
**File:** `source/RevitDevTool.PythonDemo/commands/debugpy_script.py`
```python
# /// script
# dependencies = [
# "numpy",
# ]
# ///
from Autodesk.Revit import UI
uidoc : UI.UIDocument = __revit__.ActiveUIDocument
sel_ids = uidoc.Selection.GetElementIds()
for eid in sel_ids:
el = uidoc.Document.GetElement(eid)
print(el.Id, el.Name)
```
**Steps:**
1. Select some elements in Revit
2. Set breakpoint on line 12 (`for eid in sel_ids:`)
3. Attach debugger (F5 in VSCode)
4. Execute script in RevitDevTool
5. Inspect `sel_ids`, `eid`, `el` variables
6. Step through loop (F10)