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
@@ -305,8 +321,9 @@ def set_step(self):
305
321
# for performance reasons) when returning from the current frame.
306
322
if self .frame_returning :
307
323
caller_frame = self .frame_returning .f_back
308
- if caller_frame and not caller_frame .f_trace :
309
- caller_frame .f_trace = self .trace_dispatch
324
+ ## MPY: f_trace attrib not yet available
325
+ # if caller_frame and not caller_frame.f_trace:
326
+ # caller_frame.f_trace = self.trace_dispatch
310
327
self ._set_stopinfo (None , None )
311
328
312
329
def set_next (self , frame ):
@@ -315,7 +332,7 @@ def set_next(self, frame):
315
332
316
333
def set_return (self , frame ):
317
334
"""Stop when returning from the given frame."""
318
- if frame . f_code . co_flags & GENERATOR_AND_COROUTINE_FLAGS :
335
+ if self . is_coroutine ( frame ) :
319
336
self ._set_stopinfo (frame , None , - 1 )
320
337
else :
321
338
self ._set_stopinfo (frame .f_back , frame )
@@ -326,12 +343,13 @@ def set_trace(self, frame=None):
326
343
If frame is not specified, debugging starts from caller's frame.
327
344
"""
328
345
if frame is None :
329
- frame = sys ._getframe (). f_back
346
+ frame = sys ._getframe (1 )
330
347
self .reset ()
331
- while frame :
332
- frame .f_trace = self .trace_dispatch
333
- self .botframe = frame
334
- frame = frame .f_back
348
+ ## MPY: f_trace attrib not yet available
349
+ # while frame:
350
+ # frame.f_trace = self.trace_dispatch
351
+ # self.botframe = frame
352
+ # frame = frame.f_back
335
353
self .set_step ()
336
354
sys .settrace (self .trace_dispatch )
337
355
@@ -345,10 +363,12 @@ def set_continue(self):
345
363
if not self .breaks :
346
364
# no breakpoints; run without debugger overhead
347
365
sys .settrace (None )
348
- frame = sys ._getframe ().f_back
349
- while frame and frame is not self .botframe :
350
- del frame .f_trace
351
- frame = frame .f_back
366
+ ## MPY: was sys._getframe().f_back but f_back missing when inside trace dispatch functions
367
+ frame = sys ._getframe (1 )
368
+ ## MPY: f_trace attrib not yet available
369
+ # while frame and frame is not self.botframe:
370
+ # del frame.f_trace
371
+ # frame = frame.f_back
352
372
353
373
def set_quit (self ):
354
374
"""Set quitting attribute to True.
@@ -381,10 +401,11 @@ def set_break(self, filename, lineno, temporary=False, cond=None,
381
401
The filename should be in canonical form.
382
402
"""
383
403
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 )
404
+ ## MPY: linecache not yet available
405
+ # import linecache # Import as late as possible
406
+ # line = linecache.getline(filename, lineno)
407
+ # if not line:
408
+ # return 'Line %s:%d does not exist' % (filename, lineno)
388
409
self ._add_to_breaks (filename , lineno )
389
410
bp = Breakpoint (filename , lineno , temporary , cond , funcname )
390
411
return None
@@ -557,23 +578,26 @@ def format_stack_entry(self, frame_lineno, lprefix=': '):
557
578
line of code (if it exists).
558
579
559
580
"""
560
- import linecache , reprlib
561
581
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
582
+ return repr (frame .f_code )
583
+ ## MPY: linecache, reprlib, f_locals not yet available
584
+ # import linecache, reprlib
585
+ # frame, lineno = frame_lineno
586
+ # filename = self.canonic(frame.f_code.co_filename)
587
+ # s = '%s(%r)' % (filename, lineno)
588
+ # if frame.f_code.co_name:
589
+ # s += frame.f_code.co_name
590
+ # else:
591
+ # s += "<lambda>"
592
+ # s += '()'
593
+ # if '__return__' in frame.f_locals:
594
+ # rv = frame.f_locals['__return__']
595
+ # s += '->'
596
+ # s += reprlib.repr(rv)
597
+ # line = linecache.getline(filename, lineno, frame.f_globals)
598
+ # if line:
599
+ # s += lprefix + line.strip()
600
+ # return s
577
601
578
602
# The following methods can be called by clients to use
579
603
# a debugger to debug a statement or an expression.
@@ -628,7 +652,7 @@ def runctx(self, cmd, globals, locals):
628
652
629
653
# This method is more useful to debug a single function call.
630
654
631
- def runcall (self , func , / , * args , ** kwds ):
655
+ def runcall (self , func , * args , ** kwds ):
632
656
"""Debug a single function call.
633
657
634
658
Return the result of the function call.
0 commit comments