Skip to content

Commit 5d491e0

Browse files
pi-anlclaude
andcommitted
debugpy: Fix VS Code path mapping to prevent read-only file copies.
When breakpoints are hit, VS Code was opening read-only copies of source files instead of the original workspace files due to path mismatches between VS Code's absolute paths and MicroPython's runtime paths. Changes: - Add path mapping dictionary to track VS Code path <-> runtime path relationships - Enhance breakpoint matching to handle relative paths and basename matches - Update stack trace reporting to use mapped VS Code paths - Add debug logging for path mapping diagnostics - Fix VS Code launch configuration (debugpy -> python, enable logging) This ensures VS Code correctly opens the original editable source files when debugging, rather than creating read-only temporary copies. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
1 parent c4202e4 commit 5d491e0

File tree

3 files changed

+56
-5
lines changed

3 files changed

+56
-5
lines changed

python-ecosys/debugpy/debugpy/server/debug_session.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,9 @@ def _handle_set_breakpoints(self, seq, args):
263263
filename = source.get("path", "<unknown>")
264264
breakpoints = args.get("breakpoints", [])
265265

266+
# Debug log the source information
267+
self._debug_print(f"[DAP] setBreakpoints source info: {source}")
268+
266269
# Set breakpoints in pdb adapter
267270
actual_breakpoints = self.pdb.set_breakpoints(filename, breakpoints)
268271

python-ecosys/debugpy/debugpy/server/pdb_adapter.py

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import sys
44
import time
5+
import os
56
from ..common.constants import (
67
TRACE_CALL, TRACE_LINE, TRACE_RETURN, TRACE_EXCEPTION,
78
SCOPE_LOCALS, SCOPE_GLOBALS
@@ -21,11 +22,27 @@ def __init__(self):
2122
self.continue_event = False
2223
self.variables_cache = {} # frameId -> variables
2324
self.frame_id_counter = 1
25+
self.path_mapping = {} # runtime_path -> vscode_path mapping
2426

2527
def _debug_print(self, message):
2628
"""Print debug message only if debug logging is enabled."""
2729
if hasattr(self, '_debug_session') and self._debug_session.debug_logging:
2830
print(message)
31+
32+
def _normalize_path(self, path):
33+
"""Normalize a file path for consistent comparisons."""
34+
# Convert to absolute path if possible
35+
try:
36+
if hasattr(os.path, 'abspath'):
37+
path = os.path.abspath(path)
38+
elif hasattr(os.path, 'realpath'):
39+
path = os.path.realpath(path)
40+
except:
41+
pass
42+
43+
# Ensure consistent separators
44+
path = path.replace('\\', '/')
45+
return path
2946

3047
def set_trace_function(self, trace_func):
3148
"""Install the trace function."""
@@ -39,6 +56,9 @@ def set_breakpoints(self, filename, breakpoints):
3956
self.breakpoints[filename] = {}
4057
actual_breakpoints = []
4158

59+
# Debug log the breakpoint path
60+
self._debug_print(f"[PDB] Setting breakpoints for file: {filename}")
61+
4262
for bp in breakpoints:
4363
line = bp.get("line")
4464
if line:
@@ -73,12 +93,23 @@ def should_stop(self, frame, event, arg):
7393
if filename in self.breakpoints:
7494
if lineno in self.breakpoints[filename]:
7595
self._debug_print(f"[PDB] HIT BREAKPOINT (exact match) at {filename}:{lineno}")
96+
# Record the path mapping (in this case, they're already the same)
97+
self.path_mapping[filename] = filename
7698
self.hit_breakpoint = True
7799
return True
78100

79101
# Also try checking by basename for path mismatches
80102
def basename(path):
81103
return path.split('/')[-1] if '/' in path else path
104+
105+
# Check if this might be a relative path match
106+
def ends_with_path(full_path, relative_path):
107+
"""Check if full_path ends with relative_path components."""
108+
full_parts = full_path.replace('\\', '/').split('/')
109+
rel_parts = relative_path.replace('\\', '/').split('/')
110+
if len(rel_parts) > len(full_parts):
111+
return False
112+
return full_parts[-len(rel_parts):] == rel_parts
82113

83114
file_basename = basename(filename)
84115
self._debug_print(f"[PDB] Fallback basename match: '{file_basename}' vs available files")
@@ -89,6 +120,18 @@ def basename(path):
89120
self._debug_print(f"[PDB] Basename match found! Checking line {lineno} in {list(self.breakpoints[bp_file].keys())}")
90121
if lineno in self.breakpoints[bp_file]:
91122
self._debug_print(f"[PDB] HIT BREAKPOINT (fallback basename match) at {filename}:{lineno} -> {bp_file}")
123+
# Record the path mapping so we can report the correct path in stack traces
124+
self.path_mapping[filename] = bp_file
125+
self.hit_breakpoint = True
126+
return True
127+
128+
# Also check if the runtime path might be relative and the breakpoint path absolute
129+
if ends_with_path(bp_file, filename):
130+
self._debug_print(f"[PDB] Relative path match: {bp_file} ends with {filename}")
131+
if lineno in self.breakpoints[bp_file]:
132+
self._debug_print(f"[PDB] HIT BREAKPOINT (relative path match) at {filename}:{lineno} -> {bp_file}")
133+
# Record the path mapping so we can report the correct path in stack traces
134+
self.path_mapping[filename] = bp_file
92135
self.hit_breakpoint = True
93136
return True
94137

@@ -171,11 +214,16 @@ def get_stack_trace(self):
171214
name = frame.f_code.co_name
172215
line = frame.f_lineno
173216

217+
# Use the VS Code path if we have a mapping, otherwise use the original path
218+
display_path = self.path_mapping.get(filename, filename)
219+
if filename != display_path:
220+
self._debug_print(f"[PDB] Stack trace path mapping: {filename} -> {display_path}")
221+
174222
# Create frame info
175223
frames.append({
176224
"id": frame_id,
177225
"name": name,
178-
"source": {"path": filename},
226+
"source": {"path": display_path},
179227
"line": line,
180228
"column": 1,
181229
"endLine": line,

python-ecosys/debugpy/vscode_launch_example.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@
22
"version": "0.2.0",
33
"configurations": [
44
{
5-
"name": "Micropython Attach",
6-
"type": "debugpy",
5+
"name": "Attach to MicroPython",
6+
"type": "python",
77
"request": "attach",
88
"connect": {
99
"host": "localhost",
1010
"port": 5678
1111
},
1212
"pathMappings": [
1313
{
14-
"localRoot": "${workspaceFolder}/lib/micropython-lib/python-ecosys/debugpy",
14+
"localRoot": "${workspaceFolder}",
1515
"remoteRoot": "."
1616
}
1717
],
18-
// "logToFile": true,
18+
"logToFile": true,
1919
"justMyCode": false
2020
}
2121
]

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy