Skip to content

Commit 6f5221d

Browse files
committed
bdb: Add initial micropython support.
Requires micropython to be compiled with MICROPY_PY_SYS_SETTRACE. Also requires micropython/micropython#8767
1 parent ab4929d commit 6f5221d

File tree

1 file changed

+31
-13
lines changed

1 file changed

+31
-13
lines changed

python-stdlib/bdb/bdb.py

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
"""Debugger basics"""
22

3+
# This is originally from cpython 3.10: https://raw.githubusercontent.com/python/cpython/3.10/Lib/bdb.py
4+
# Patches for micropython have been commented as such.
5+
36
import fnmatch
47
import sys
58
import os
6-
from inspect import CO_GENERATOR, CO_COROUTINE, CO_ASYNC_GENERATOR
9+
10+
## MPY: no inspect module avaialble
11+
# from inspect import CO_GENERATOR, CO_COROUTINE, CO_ASYNC_GENERATOR
712

813
__all__ = ["BdbQuit", "Bdb", "Breakpoint"]
914

10-
GENERATOR_AND_COROUTINE_FLAGS = CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR
15+
## MPY: These flags currently don't exist
16+
# GENERATOR_AND_COROUTINE_FLAGS = CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR
1117

1218

1319
class BdbQuit(Exception):
@@ -46,11 +52,12 @@ def canonic(self, filename):
4652
"""
4753
if filename == "<" + filename[1:-1] + ">":
4854
return filename
55+
4956
canonic = self.fncache.get(filename)
5057
if not canonic:
5158
canonic = os.path.abspath(filename)
5259
canonic = os.path.normcase(canonic)
53-
self.fncache[filename] = canonic
60+
self.fncache[filename] = canonic
5461
return canonic
5562

5663
def reset(self):
@@ -115,6 +122,12 @@ def dispatch_line(self, frame):
115122
if self.quitting: raise BdbQuit
116123
return self.trace_dispatch
117124

125+
def is_coroutine(self, frame):
126+
## MPY: co_flags attrib not available, compatible method of detecting coroutine TBD
127+
# return frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS
128+
return False
129+
130+
118131
def dispatch_call(self, frame, arg):
119132
"""Invoke user function and return trace function for call event.
120133
@@ -131,7 +144,7 @@ def dispatch_call(self, frame, arg):
131144
# No need to trace this function
132145
return # None
133146
# Ignore call events in generator except when stepping.
134-
if self.stopframe and frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS:
147+
if self.stopframe and self.is_coroutine(frame):
135148
return self.trace_dispatch
136149
self.user_call(frame, arg)
137150
if self.quitting: raise BdbQuit
@@ -146,7 +159,7 @@ def dispatch_return(self, frame, arg):
146159
"""
147160
if self.stop_here(frame) or frame == self.returnframe:
148161
# Ignore return events in generator except when stepping.
149-
if self.stopframe and frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS:
162+
if self.stopframe and self.is_coroutine(frame):
150163
return self.trace_dispatch
151164
try:
152165
self.frame_returning = frame
@@ -170,7 +183,7 @@ def dispatch_exception(self, frame, arg):
170183
# When stepping with next/until/return in a generator frame, skip
171184
# the internal StopIteration exception (with no traceback)
172185
# triggered by a subiterator run with the 'yield from' statement.
173-
if not (frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS
186+
if not (self.is_coroutine(frame)
174187
and arg[0] is StopIteration and arg[2] is None):
175188
self.user_exception(frame, arg)
176189
if self.quitting: raise BdbQuit
@@ -179,7 +192,7 @@ def dispatch_exception(self, frame, arg):
179192
# next/until command at the last statement in the generator before the
180193
# exception.
181194
elif (self.stopframe and frame is not self.stopframe
182-
and self.stopframe.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS
195+
and self.is_coroutine(self.stopframe)
183196
and arg[0] in (StopIteration, GeneratorExit)):
184197
self.user_exception(frame, arg)
185198
if self.quitting: raise BdbQuit
@@ -315,7 +328,7 @@ def set_next(self, frame):
315328

316329
def set_return(self, frame):
317330
"""Stop when returning from the given frame."""
318-
if frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS:
331+
if self.is_coroutine(frame):
319332
self._set_stopinfo(frame, None, -1)
320333
else:
321334
self._set_stopinfo(frame.f_back, frame)
@@ -326,7 +339,7 @@ def set_trace(self, frame=None):
326339
If frame is not specified, debugging starts from caller's frame.
327340
"""
328341
if frame is None:
329-
frame = sys._getframe().f_back
342+
frame = sys._getframe(1)
330343
self.reset()
331344
while frame:
332345
frame.f_trace = self.trace_dispatch
@@ -345,7 +358,8 @@ def set_continue(self):
345358
if not self.breaks:
346359
# no breakpoints; run without debugger overhead
347360
sys.settrace(None)
348-
frame = sys._getframe().f_back
361+
## MPY: was sys._getframe().f_back but f_back missing when inside trace dispatch functions
362+
frame = sys._getframe(1)
349363
while frame and frame is not self.botframe:
350364
del frame.f_trace
351365
frame = frame.f_back
@@ -557,7 +571,11 @@ def format_stack_entry(self, frame_lineno, lprefix=': '):
557571
line of code (if it exists).
558572
559573
"""
560-
import linecache, reprlib
574+
# frame, lineno = frame_lineno
575+
# return repr(frame.f_code)
576+
## MPY: linecache, reprlib, f_locals not yet available
577+
# import linecache, reprlib
578+
import linecache
561579
frame, lineno = frame_lineno
562580
filename = self.canonic(frame.f_code.co_filename)
563581
s = '%s(%r)' % (filename, lineno)
@@ -569,7 +587,7 @@ def format_stack_entry(self, frame_lineno, lprefix=': '):
569587
if '__return__' in frame.f_locals:
570588
rv = frame.f_locals['__return__']
571589
s += '->'
572-
s += reprlib.repr(rv)
590+
s += repr(rv)
573591
line = linecache.getline(filename, lineno, frame.f_globals)
574592
if line:
575593
s += lprefix + line.strip()
@@ -628,7 +646,7 @@ def runctx(self, cmd, globals, locals):
628646

629647
# This method is more useful to debug a single function call.
630648

631-
def runcall(self, func, /, *args, **kwds):
649+
def runcall(self, func, *args, **kwds):
632650
"""Debug a single function call.
633651
634652
Return the result of the function call.

0 commit comments

Comments
 (0)