Skip to content

Commit b690b51

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 2d2abf2 commit b690b51

File tree

1 file changed

+59
-38
lines changed

1 file changed

+59
-38
lines changed

python-stdlib/bdb/bdb.py

Lines changed: 59 additions & 38 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,17 +52,21 @@ def canonic(self, filename):
4652
"""
4753
if filename == "<" + filename[1:-1] + ">":
4854
return filename
49-
canonic = self.fncache.get(filename)
50-
if not canonic:
51-
canonic = os.path.abspath(filename)
52-
canonic = os.path.normcase(canonic)
53-
self.fncache[filename] = canonic
54-
return canonic
55+
56+
## MPY: os.path module difficult to add as dependency
57+
# canonic = self.fncache.get(filename)
58+
# if not canonic:
59+
# canonic = os.path.abspath(filename)
60+
# canonic = os.path.normcase(canonic)
61+
# self.fncache[filename] = canonic
62+
# return canonic
63+
return filename
5564

5665
def reset(self):
5766
"""Set values of attributes as ready to start debugging."""
58-
import linecache
59-
linecache.checkcache()
67+
## MPY: linecache not yet available
68+
# import linecache
69+
# linecache.checkcache()
6070
self.botframe = None
6171
self._set_stopinfo(None, None)
6272

@@ -115,6 +125,12 @@ def dispatch_line(self, frame):
115125
if self.quitting: raise BdbQuit
116126
return self.trace_dispatch
117127

128+
def is_coroutine(self, frame):
129+
## MPY: co_flags attrib not available, compatible method of detecting coroutine TBD
130+
# return frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS
131+
return False
132+
133+
118134
def dispatch_call(self, frame, arg):
119135
"""Invoke user function and return trace function for call event.
120136
@@ -131,7 +147,7 @@ def dispatch_call(self, frame, arg):
131147
# No need to trace this function
132148
return # None
133149
# Ignore call events in generator except when stepping.
134-
if self.stopframe and frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS:
150+
if self.stopframe and self.is_coroutine(frame):
135151
return self.trace_dispatch
136152
self.user_call(frame, arg)
137153
if self.quitting: raise BdbQuit
@@ -146,7 +162,7 @@ def dispatch_return(self, frame, arg):
146162
"""
147163
if self.stop_here(frame) or frame == self.returnframe:
148164
# Ignore return events in generator except when stepping.
149-
if self.stopframe and frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS:
165+
if self.stopframe and self.is_coroutine(frame):
150166
return self.trace_dispatch
151167
try:
152168
self.frame_returning = frame
@@ -170,7 +186,7 @@ def dispatch_exception(self, frame, arg):
170186
# When stepping with next/until/return in a generator frame, skip
171187
# the internal StopIteration exception (with no traceback)
172188
# triggered by a subiterator run with the 'yield from' statement.
173-
if not (frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS
189+
if not (self.is_coroutine(frame)
174190
and arg[0] is StopIteration and arg[2] is None):
175191
self.user_exception(frame, arg)
176192
if self.quitting: raise BdbQuit
@@ -179,7 +195,7 @@ def dispatch_exception(self, frame, arg):
179195
# next/until command at the last statement in the generator before the
180196
# exception.
181197
elif (self.stopframe and frame is not self.stopframe
182-
and self.stopframe.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS
198+
and self.is_coroutine(self.stopframe)
183199
and arg[0] in (StopIteration, GeneratorExit)):
184200
self.user_exception(frame, arg)
185201
if self.quitting: raise BdbQuit
@@ -315,7 +331,7 @@ def set_next(self, frame):
315331

316332
def set_return(self, frame):
317333
"""Stop when returning from the given frame."""
318-
if frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS:
334+
if self.is_coroutine(frame):
319335
self._set_stopinfo(frame, None, -1)
320336
else:
321337
self._set_stopinfo(frame.f_back, frame)
@@ -326,7 +342,7 @@ def set_trace(self, frame=None):
326342
If frame is not specified, debugging starts from caller's frame.
327343
"""
328344
if frame is None:
329-
frame = sys._getframe().f_back
345+
frame = sys._getframe(1)
330346
self.reset()
331347
while frame:
332348
frame.f_trace = self.trace_dispatch
@@ -345,7 +361,8 @@ def set_continue(self):
345361
if not self.breaks:
346362
# no breakpoints; run without debugger overhead
347363
sys.settrace(None)
348-
frame = sys._getframe().f_back
364+
## MPY: was sys._getframe().f_back but f_back missing when inside trace dispatch functions
365+
frame = sys._getframe(1)
349366
while frame and frame is not self.botframe:
350367
del frame.f_trace
351368
frame = frame.f_back
@@ -381,10 +398,11 @@ def set_break(self, filename, lineno, temporary=False, cond=None,
381398
The filename should be in canonical form.
382399
"""
383400
filename = self.canonic(filename)
384-
import linecache # Import as late as possible
385-
line = linecache.getline(filename, lineno)
386-
if not line:
387-
return 'Line %s:%d does not exist' % (filename, lineno)
401+
## MPY: linecache not yet available
402+
# import linecache # Import as late as possible
403+
# line = linecache.getline(filename, lineno)
404+
# if not line:
405+
# return 'Line %s:%d does not exist' % (filename, lineno)
388406
self._add_to_breaks(filename, lineno)
389407
bp = Breakpoint(filename, lineno, temporary, cond, funcname)
390408
return None
@@ -557,23 +575,26 @@ def format_stack_entry(self, frame_lineno, lprefix=': '):
557575
line of code (if it exists).
558576
559577
"""
560-
import linecache, reprlib
561578
frame, lineno = frame_lineno
562-
filename = self.canonic(frame.f_code.co_filename)
563-
s = '%s(%r)' % (filename, lineno)
564-
if frame.f_code.co_name:
565-
s += frame.f_code.co_name
566-
else:
567-
s += "<lambda>"
568-
s += '()'
569-
if '__return__' in frame.f_locals:
570-
rv = frame.f_locals['__return__']
571-
s += '->'
572-
s += reprlib.repr(rv)
573-
line = linecache.getline(filename, lineno, frame.f_globals)
574-
if line:
575-
s += lprefix + line.strip()
576-
return s
579+
return repr(frame.f_code)
580+
## MPY: linecache, reprlib, f_locals not yet available
581+
# import linecache, reprlib
582+
# frame, lineno = frame_lineno
583+
# filename = self.canonic(frame.f_code.co_filename)
584+
# s = '%s(%r)' % (filename, lineno)
585+
# if frame.f_code.co_name:
586+
# s += frame.f_code.co_name
587+
# else:
588+
# s += "<lambda>"
589+
# s += '()'
590+
# if '__return__' in frame.f_locals:
591+
# rv = frame.f_locals['__return__']
592+
# s += '->'
593+
# s += reprlib.repr(rv)
594+
# line = linecache.getline(filename, lineno, frame.f_globals)
595+
# if line:
596+
# s += lprefix + line.strip()
597+
# return s
577598

578599
# The following methods can be called by clients to use
579600
# a debugger to debug a statement or an expression.
@@ -628,7 +649,7 @@ def runctx(self, cmd, globals, locals):
628649

629650
# This method is more useful to debug a single function call.
630651

631-
def runcall(self, func, /, *args, **kwds):
652+
def runcall(self, func, *args, **kwds):
632653
"""Debug a single function call.
633654
634655
Return the result of the function call.

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