1
1
"""Debugger basics"""
2
2
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
+
3
6
import fnmatch
4
7
import sys
5
8
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
7
12
8
13
__all__ = ["BdbQuit" , "Bdb" , "Breakpoint" ]
9
14
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
11
17
12
18
13
19
class BdbQuit (Exception ):
@@ -46,17 +52,21 @@ def canonic(self, filename):
46
52
"""
47
53
if filename == "<" + filename [1 :- 1 ] + ">" :
48
54
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
55
64
56
65
def reset (self ):
57
66
"""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()
60
70
self .botframe = None
61
71
self ._set_stopinfo (None , None )
62
72
@@ -115,6 +125,12 @@ def dispatch_line(self, frame):
115
125
if self .quitting : raise BdbQuit
116
126
return self .trace_dispatch
117
127
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
+
118
134
def dispatch_call (self , frame , arg ):
119
135
"""Invoke user function and return trace function for call event.
120
136
@@ -131,7 +147,7 @@ def dispatch_call(self, frame, arg):
131
147
# No need to trace this function
132
148
return # None
133
149
# 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 ) :
135
151
return self .trace_dispatch
136
152
self .user_call (frame , arg )
137
153
if self .quitting : raise BdbQuit
@@ -146,7 +162,7 @@ def dispatch_return(self, frame, arg):
146
162
"""
147
163
if self .stop_here (frame ) or frame == self .returnframe :
148
164
# 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 ) :
150
166
return self .trace_dispatch
151
167
try :
152
168
self .frame_returning = frame
@@ -170,7 +186,7 @@ def dispatch_exception(self, frame, arg):
170
186
# When stepping with next/until/return in a generator frame, skip
171
187
# the internal StopIteration exception (with no traceback)
172
188
# 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 )
174
190
and arg [0 ] is StopIteration and arg [2 ] is None ):
175
191
self .user_exception (frame , arg )
176
192
if self .quitting : raise BdbQuit
@@ -179,7 +195,7 @@ def dispatch_exception(self, frame, arg):
179
195
# next/until command at the last statement in the generator before the
180
196
# exception.
181
197
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 )
183
199
and arg [0 ] in (StopIteration , GeneratorExit )):
184
200
self .user_exception (frame , arg )
185
201
if self .quitting : raise BdbQuit
@@ -315,7 +331,7 @@ def set_next(self, frame):
315
331
316
332
def set_return (self , frame ):
317
333
"""Stop when returning from the given frame."""
318
- if frame . f_code . co_flags & GENERATOR_AND_COROUTINE_FLAGS :
334
+ if self . is_coroutine ( frame ) :
319
335
self ._set_stopinfo (frame , None , - 1 )
320
336
else :
321
337
self ._set_stopinfo (frame .f_back , frame )
@@ -326,7 +342,7 @@ def set_trace(self, frame=None):
326
342
If frame is not specified, debugging starts from caller's frame.
327
343
"""
328
344
if frame is None :
329
- frame = sys ._getframe (). f_back
345
+ frame = sys ._getframe (1 )
330
346
self .reset ()
331
347
while frame :
332
348
frame .f_trace = self .trace_dispatch
@@ -345,7 +361,8 @@ def set_continue(self):
345
361
if not self .breaks :
346
362
# no breakpoints; run without debugger overhead
347
363
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 )
349
366
while frame and frame is not self .botframe :
350
367
del frame .f_trace
351
368
frame = frame .f_back
@@ -381,10 +398,11 @@ def set_break(self, filename, lineno, temporary=False, cond=None,
381
398
The filename should be in canonical form.
382
399
"""
383
400
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)
388
406
self ._add_to_breaks (filename , lineno )
389
407
bp = Breakpoint (filename , lineno , temporary , cond , funcname )
390
408
return None
@@ -557,23 +575,26 @@ def format_stack_entry(self, frame_lineno, lprefix=': '):
557
575
line of code (if it exists).
558
576
559
577
"""
560
- import linecache , reprlib
561
578
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
577
598
578
599
# The following methods can be called by clients to use
579
600
# a debugger to debug a statement or an expression.
@@ -628,7 +649,7 @@ def runctx(self, cmd, globals, locals):
628
649
629
650
# This method is more useful to debug a single function call.
630
651
631
- def runcall (self , func , / , * args , ** kwds ):
652
+ def runcall (self , func , * args , ** kwds ):
632
653
"""Debug a single function call.
633
654
634
655
Return the result of the function call.
0 commit comments