8 __all__
= ["BdbQuit","Bdb","Breakpoint"]
10 class BdbQuit(Exception):
11 """Exception to give up completely"""
16 """Generic Python debugger base class.
18 This class takes care of details of the trace facility;
19 a derived class should implement user interaction.
20 The standard debugger class (pdb.Pdb) is an example.
23 def __init__(self
, skip
=None):
24 self
.skip
= set(skip
) if skip
else None
28 def canonic(self
, filename
):
29 if filename
== "<" + filename
[1:-1] + ">":
31 canonic
= self
.fncache
.get(filename
)
33 canonic
= os
.path
.abspath(filename
)
34 canonic
= os
.path
.normcase(canonic
)
35 self
.fncache
[filename
] = canonic
40 linecache
.checkcache()
42 self
._set
_stopinfo
(None, None)
44 def trace_dispatch(self
, frame
, event
, arg
):
48 return self
.dispatch_line(frame
)
50 return self
.dispatch_call(frame
, arg
)
52 return self
.dispatch_return(frame
, arg
)
53 if event
== 'exception':
54 return self
.dispatch_exception(frame
, arg
)
56 return self
.trace_dispatch
57 if event
== 'c_exception':
58 return self
.trace_dispatch
59 if event
== 'c_return':
60 return self
.trace_dispatch
61 print('bdb.Bdb.dispatch: unknown debugging event:', repr(event
))
62 return self
.trace_dispatch
64 def dispatch_line(self
, frame
):
65 if self
.stop_here(frame
) or self
.break_here(frame
):
67 if self
.quitting
: raise BdbQuit
68 return self
.trace_dispatch
70 def dispatch_call(self
, frame
, arg
):
71 # XXX 'arg' is no longer used
72 if self
.botframe
is None:
73 # First call of dispatch since reset()
74 self
.botframe
= frame
.f_back
# (CT) Note that this may also be None!
75 return self
.trace_dispatch
76 if not (self
.stop_here(frame
) or self
.break_anywhere(frame
)):
77 # No need to trace this function
79 self
.user_call(frame
, arg
)
80 if self
.quitting
: raise BdbQuit
81 return self
.trace_dispatch
83 def dispatch_return(self
, frame
, arg
):
84 if self
.stop_here(frame
) or frame
== self
.returnframe
:
85 self
.user_return(frame
, arg
)
86 if self
.quitting
: raise BdbQuit
87 return self
.trace_dispatch
89 def dispatch_exception(self
, frame
, arg
):
90 if self
.stop_here(frame
):
91 self
.user_exception(frame
, arg
)
92 if self
.quitting
: raise BdbQuit
93 return self
.trace_dispatch
95 # Normally derived classes don't override the following
96 # methods, but they may if they want to redefine the
97 # definition of stopping and breakpoints.
99 def is_skipped_module(self
, module_name
):
100 for pattern
in self
.skip
:
101 if fnmatch
.fnmatch(module_name
, pattern
):
105 def stop_here(self
, frame
):
106 # (CT) stopframe may now also be None, see dispatch_call.
107 # (CT) the former test for None is therefore removed from here.
109 self
.is_skipped_module(frame
.f_globals
.get('__name__')):
111 if frame
is self
.stopframe
:
112 return frame
.f_lineno
>= self
.stoplineno
113 while frame
is not None and frame
is not self
.stopframe
:
114 if frame
is self
.botframe
:
119 def break_here(self
, frame
):
120 filename
= self
.canonic(frame
.f_code
.co_filename
)
121 if not filename
in self
.breaks
:
123 lineno
= frame
.f_lineno
124 if not lineno
in self
.breaks
[filename
]:
125 # The line itself has no breakpoint, but maybe the line is the
126 # first line of a function with breakpoint set by function name.
127 lineno
= frame
.f_code
.co_firstlineno
128 if not lineno
in self
.breaks
[filename
]:
131 # flag says ok to delete temp. bp
132 (bp
, flag
) = effective(filename
, lineno
, frame
)
134 self
.currentbp
= bp
.number
135 if (flag
and bp
.temporary
):
136 self
.do_clear(str(bp
.number
))
141 def do_clear(self
, arg
):
142 raise NotImplementedError("subclass of bdb must implement do_clear()")
144 def break_anywhere(self
, frame
):
145 return self
.canonic(frame
.f_code
.co_filename
) in self
.breaks
147 # Derived classes should override the user_* methods
150 def user_call(self
, frame
, argument_list
):
151 """This method is called when there is the remote possibility
152 that we ever need to stop in this function."""
155 def user_line(self
, frame
):
156 """This method is called when we stop or break at this line."""
159 def user_return(self
, frame
, return_value
):
160 """This method is called when a return trap is set here."""
163 def user_exception(self
, frame
, exc_info
):
164 """This method is called if an exception occurs,
165 but only if we are to stop at or just below this level."""
168 def _set_stopinfo(self
, stopframe
, returnframe
, stoplineno
=-1):
169 self
.stopframe
= stopframe
170 self
.returnframe
= returnframe
172 self
.stoplineno
= stoplineno
174 # Derived classes and clients can call the following methods
175 # to affect the stepping state.
177 def set_until(self
, frame
): #the name "until" is borrowed from gdb
178 """Stop when the line with the line no greater than the current one is
179 reached or when returning from current frame"""
180 self
._set
_stopinfo
(frame
, frame
, frame
.f_lineno
+1)
183 """Stop after one line of code."""
184 self
._set
_stopinfo
(None,None)
186 def set_next(self
, frame
):
187 """Stop on the next line in or below the given frame."""
188 self
._set
_stopinfo
(frame
, None)
190 def set_return(self
, frame
):
191 """Stop when returning from the given frame."""
192 self
._set
_stopinfo
(frame
.f_back
, frame
)
194 def set_trace(self
, frame
=None):
195 """Start debugging from `frame`.
197 If frame is not specified, debugging starts from caller's frame.
200 frame
= sys
._getframe
().f_back
203 frame
.f_trace
= self
.trace_dispatch
204 self
.botframe
= frame
207 sys
.settrace(self
.trace_dispatch
)
209 def set_continue(self
):
210 # Don't stop except at breakpoints or when finished
211 self
._set
_stopinfo
(self
.botframe
, None)
213 # no breakpoints; run without debugger overhead
215 frame
= sys
._getframe
().f_back
216 while frame
and frame
is not self
.botframe
:
221 self
.stopframe
= self
.botframe
222 self
.returnframe
= None
226 # Derived classes and clients can call the following methods
227 # to manipulate breakpoints. These methods return an
228 # error message is something went wrong, None if all is well.
229 # Set_break prints out the breakpoint line and file:lineno.
230 # Call self.get_*break*() to see the breakpoints or better
231 # for bp in Breakpoint.bpbynumber: if bp: bp.bpprint().
233 def set_break(self
, filename
, lineno
, temporary
=0, cond
= None,
235 filename
= self
.canonic(filename
)
236 import linecache
# Import as late as possible
237 line
= linecache
.getline(filename
, lineno
)
239 return 'Line %s:%d does not exist' % (filename
,
241 if not filename
in self
.breaks
:
242 self
.breaks
[filename
] = []
243 list = self
.breaks
[filename
]
244 if not lineno
in list:
246 bp
= Breakpoint(filename
, lineno
, temporary
, cond
, funcname
)
248 def clear_break(self
, filename
, lineno
):
249 filename
= self
.canonic(filename
)
250 if not filename
in self
.breaks
:
251 return 'There are no breakpoints in %s' % filename
252 if lineno
not in self
.breaks
[filename
]:
253 return 'There is no breakpoint at %s:%d' % (filename
,
255 # If there's only one bp in the list for that file,line
256 # pair, then remove the breaks entry
257 for bp
in Breakpoint
.bplist
[filename
, lineno
][:]:
259 if (filename
, lineno
) not in Breakpoint
.bplist
:
260 self
.breaks
[filename
].remove(lineno
)
261 if not self
.breaks
[filename
]:
262 del self
.breaks
[filename
]
264 def clear_bpbynumber(self
, arg
):
268 return 'Non-numeric breakpoint number (%s)' % arg
270 bp
= Breakpoint
.bpbynumber
[number
]
272 return 'Breakpoint number (%d) out of range' % number
274 return 'Breakpoint (%d) already deleted' % number
275 self
.clear_break(bp
.file, bp
.line
)
277 def clear_all_file_breaks(self
, filename
):
278 filename
= self
.canonic(filename
)
279 if not filename
in self
.breaks
:
280 return 'There are no breakpoints in %s' % filename
281 for line
in self
.breaks
[filename
]:
282 blist
= Breakpoint
.bplist
[filename
, line
]
285 del self
.breaks
[filename
]
287 def clear_all_breaks(self
):
289 return 'There are no breakpoints'
290 for bp
in Breakpoint
.bpbynumber
:
295 def get_break(self
, filename
, lineno
):
296 filename
= self
.canonic(filename
)
297 return filename
in self
.breaks
and \
298 lineno
in self
.breaks
[filename
]
300 def get_breaks(self
, filename
, lineno
):
301 filename
= self
.canonic(filename
)
302 return filename
in self
.breaks
and \
303 lineno
in self
.breaks
[filename
] and \
304 Breakpoint
.bplist
[filename
, lineno
] or []
306 def get_file_breaks(self
, filename
):
307 filename
= self
.canonic(filename
)
308 if filename
in self
.breaks
:
309 return self
.breaks
[filename
]
313 def get_all_breaks(self
):
316 # Derived classes and clients can call the following method
317 # to get a data structure representing a stack trace.
319 def get_stack(self
, f
, t
):
321 if t
and t
.tb_frame
is f
:
324 stack
.append((f
, f
.f_lineno
))
325 if f
is self
.botframe
:
329 i
= max(0, len(stack
) - 1)
331 stack
.append((t
.tb_frame
, t
.tb_lineno
))
334 i
= max(0, len(stack
) - 1)
339 def format_stack_entry(self
, frame_lineno
, lprefix
=': '):
340 import linecache
, reprlib
341 frame
, lineno
= frame_lineno
342 filename
= self
.canonic(frame
.f_code
.co_filename
)
343 s
= '%s(%r)' % (filename
, lineno
)
344 if frame
.f_code
.co_name
:
345 s
= s
+ frame
.f_code
.co_name
348 if '__args__' in frame
.f_locals
:
349 args
= frame
.f_locals
['__args__']
353 s
= s
+ reprlib
.repr(args
)
356 if '__return__' in frame
.f_locals
:
357 rv
= frame
.f_locals
['__return__']
359 s
= s
+ reprlib
.repr(rv
)
360 line
= linecache
.getline(filename
, lineno
, frame
.f_globals
)
361 if line
: s
= s
+ lprefix
+ line
.strip()
364 # The following two methods can be called by clients to use
365 # a debugger to debug a statement, given as a string.
367 def run(self
, cmd
, globals=None, locals=None):
370 globals = __main__
.__dict
__
374 sys
.settrace(self
.trace_dispatch
)
375 if not isinstance(cmd
, types
.CodeType
):
378 exec(cmd
, globals, locals)
385 def runeval(self
, expr
, globals=None, locals=None):
388 globals = __main__
.__dict
__
392 sys
.settrace(self
.trace_dispatch
)
393 if not isinstance(expr
, types
.CodeType
):
396 return eval(expr
, globals, locals)
403 def runctx(self
, cmd
, globals, locals):
405 self
.run(cmd
, globals, locals)
407 # This method is more useful to debug a single function call.
409 def runcall(self
, func
, *args
, **kwds
):
411 sys
.settrace(self
.trace_dispatch
)
414 res
= func(*args
, **kwds
)
431 Implements temporary breakpoints, ignore counts, disabling and
432 (re)-enabling, and conditionals.
434 Breakpoints are indexed by number through bpbynumber and by
435 the file,line tuple using bplist. The former points to a
436 single instance of class Breakpoint. The latter points to a
437 list of such instances since there may be more than one
442 # XXX Keeping state in the class is a mistake -- this means
443 # you cannot have more than one active Bdb instance.
445 next
= 1 # Next bp to be assigned
446 bplist
= {} # indexed by (file, lineno) tuple
447 bpbynumber
= [None] # Each entry is None or an instance of Bpt
448 # index 0 is unused, except for marking an
449 # effective break .... see effective()
451 def __init__(self
, file, line
, temporary
=0, cond
=None, funcname
=None):
452 self
.funcname
= funcname
453 # Needed if funcname is not None.
454 self
.func_first_executable_line
= None
455 self
.file = file # This better be in canonical form!
457 self
.temporary
= temporary
462 self
.number
= Breakpoint
.next
463 Breakpoint
.next
= Breakpoint
.next
+ 1
464 # Build the two lists
465 self
.bpbynumber
.append(self
)
466 if (file, line
) in self
.bplist
:
467 self
.bplist
[file, line
].append(self
)
469 self
.bplist
[file, line
] = [self
]
473 index
= (self
.file, self
.line
)
474 self
.bpbynumber
[self
.number
] = None # No longer in list
475 self
.bplist
[index
].remove(self
)
476 if not self
.bplist
[index
]:
477 # No more bp for this f:l combo
478 del self
.bplist
[index
]
486 def bpprint(self
, out
=None):
497 print('%-4dbreakpoint %s at %s:%d' % (self
.number
, disp
,
498 self
.file, self
.line
), file=out
)
500 print('\tstop only if %s' % (self
.cond
,), file=out
)
502 print('\tignore next %d hits' % (self
.ignore
), file=out
)
504 if (self
.hits
> 1): ss
= 's'
506 print(('\tbreakpoint already hit %d time%s' %
507 (self
.hits
, ss
)), file=out
)
509 # -----------end of Breakpoint class----------
511 def checkfuncname(b
, frame
):
512 """Check whether we should break here because of `b.funcname`."""
514 # Breakpoint was set via line number.
515 if b
.line
!= frame
.f_lineno
:
516 # Breakpoint was set at a line with a def statement and the function
517 # defined is called: don't break.
521 # Breakpoint set via function name.
523 if frame
.f_code
.co_name
!= b
.funcname
:
524 # It's not a function call, but rather execution of def statement.
527 # We are in the right frame.
528 if not b
.func_first_executable_line
:
529 # The function is entered for the 1st time.
530 b
.func_first_executable_line
= frame
.f_lineno
532 if b
.func_first_executable_line
!= frame
.f_lineno
:
533 # But we are not at the first line number: don't break.
537 # Determines if there is an effective (active) breakpoint at this
538 # line of code. Returns breakpoint number or 0 if none
539 def effective(file, line
, frame
):
540 """Determine which breakpoint for this file:line is to be acted upon.
542 Called only if we know there is a bpt at this
543 location. Returns breakpoint that was triggered and a flag
544 that indicates if it is ok to delete a temporary bp.
547 possibles
= Breakpoint
.bplist
[file,line
]
548 for i
in range(0, len(possibles
)):
552 if not checkfuncname(b
, frame
):
554 # Count every hit when bp is enabled
557 # If unconditional, and ignoring,
558 # go on to next, else break
560 b
.ignore
= b
.ignore
-1
563 # breakpoint and marker that's ok
564 # to delete if temporary
568 # Ignore count applies only to those bpt hits where the
569 # condition evaluates to true.
571 val
= eval(b
.cond
, frame
.f_globals
,
575 b
.ignore
= b
.ignore
-1
582 # if eval fails, most conservative
583 # thing is to stop on breakpoint
584 # regardless of ignore count.
585 # Don't delete temporary,
586 # as another hint to user.
590 # -------------------- testing --------------------
593 def user_call(self
, frame
, args
):
594 name
= frame
.f_code
.co_name
595 if not name
: name
= '???'
596 print('+++ call', name
, args
)
597 def user_line(self
, frame
):
599 name
= frame
.f_code
.co_name
600 if not name
: name
= '???'
601 fn
= self
.canonic(frame
.f_code
.co_filename
)
602 line
= linecache
.getline(fn
, frame
.f_lineno
, frame
.f_globals
)
603 print('+++', fn
, frame
.f_lineno
, name
, ':', line
.strip())
604 def user_return(self
, frame
, retval
):
605 print('+++ return', retval
)
606 def user_exception(self
, frame
, exc_stuff
):
607 print('+++ exception', exc_stuff
)
611 print('foo(', n
, ')')
613 print('bar returned', x
)
616 print('bar(', a
, ')')
621 t
.run('import bdb; bdb.foo(10)')