7 __all__
= ["BdbQuit","Bdb","Breakpoint"]
9 class BdbQuit(Exception):
10 """Exception to give up completely"""
15 """Generic Python debugger base class.
17 This class takes care of details of the trace facility;
18 a derived class should implement user interaction.
19 The standard debugger class (pdb.Pdb) is an example.
26 def canonic(self
, filename
):
27 if filename
== "<" + filename
[1:-1] + ">":
29 canonic
= self
.fncache
.get(filename
)
31 canonic
= os
.path
.abspath(filename
)
32 canonic
= os
.path
.normcase(canonic
)
33 self
.fncache
[filename
] = canonic
38 linecache
.checkcache()
40 self
._set
_stopinfo
(None, None)
42 def trace_dispatch(self
, frame
, event
, arg
):
46 return self
.dispatch_line(frame
)
48 return self
.dispatch_call(frame
, arg
)
50 return self
.dispatch_return(frame
, arg
)
51 if event
== 'exception':
52 return self
.dispatch_exception(frame
, arg
)
54 return self
.trace_dispatch
55 if event
== 'c_exception':
56 return self
.trace_dispatch
57 if event
== 'c_return':
58 return self
.trace_dispatch
59 print 'bdb.Bdb.dispatch: unknown debugging event:', repr(event
)
60 return self
.trace_dispatch
62 def dispatch_line(self
, frame
):
63 if self
.stop_here(frame
) or self
.break_here(frame
):
65 if self
.quitting
: raise BdbQuit
66 return self
.trace_dispatch
68 def dispatch_call(self
, frame
, arg
):
69 # XXX 'arg' is no longer used
70 if self
.botframe
is None:
71 # First call of dispatch since reset()
72 self
.botframe
= frame
.f_back
# (CT) Note that this may also be None!
73 return self
.trace_dispatch
74 if not (self
.stop_here(frame
) or self
.break_anywhere(frame
)):
75 # No need to trace this function
77 self
.user_call(frame
, arg
)
78 if self
.quitting
: raise BdbQuit
79 return self
.trace_dispatch
81 def dispatch_return(self
, frame
, arg
):
82 if self
.stop_here(frame
) or frame
== self
.returnframe
:
83 self
.user_return(frame
, arg
)
84 if self
.quitting
: raise BdbQuit
85 return self
.trace_dispatch
87 def dispatch_exception(self
, frame
, arg
):
88 if self
.stop_here(frame
):
89 self
.user_exception(frame
, arg
)
90 if self
.quitting
: raise BdbQuit
91 return self
.trace_dispatch
93 # Normally derived classes don't override the following
94 # methods, but they may if they want to redefine the
95 # definition of stopping and breakpoints.
97 def stop_here(self
, frame
):
98 # (CT) stopframe may now also be None, see dispatch_call.
99 # (CT) the former test for None is therefore removed from here.
100 if frame
is self
.stopframe
:
101 return frame
.f_lineno
>= self
.stoplineno
102 while frame
is not None and frame
is not self
.stopframe
:
103 if frame
is self
.botframe
:
108 def break_here(self
, frame
):
109 filename
= self
.canonic(frame
.f_code
.co_filename
)
110 if not filename
in self
.breaks
:
112 lineno
= frame
.f_lineno
113 if not lineno
in self
.breaks
[filename
]:
114 # The line itself has no breakpoint, but maybe the line is the
115 # first line of a function with breakpoint set by function name.
116 lineno
= frame
.f_code
.co_firstlineno
117 if not lineno
in self
.breaks
[filename
]:
120 # flag says ok to delete temp. bp
121 (bp
, flag
) = effective(filename
, lineno
, frame
)
123 self
.currentbp
= bp
.number
124 if (flag
and bp
.temporary
):
125 self
.do_clear(str(bp
.number
))
130 def do_clear(self
, arg
):
131 raise NotImplementedError, "subclass of bdb must implement do_clear()"
133 def break_anywhere(self
, frame
):
134 return self
.breaks
.has_key(
135 self
.canonic(frame
.f_code
.co_filename
))
137 # Derived classes should override the user_* methods
140 def user_call(self
, frame
, argument_list
):
141 """This method is called when there is the remote possibility
142 that we ever need to stop in this function."""
145 def user_line(self
, frame
):
146 """This method is called when we stop or break at this line."""
149 def user_return(self
, frame
, return_value
):
150 """This method is called when a return trap is set here."""
153 def user_exception(self
, frame
, (exc_type
, exc_value
, exc_traceback
)):
154 """This method is called if an exception occurs,
155 but only if we are to stop at or just below this level."""
158 def _set_stopinfo(self
, stopframe
, returnframe
, stoplineno
=-1):
159 self
.stopframe
= stopframe
160 self
.returnframe
= returnframe
162 self
.stoplineno
= stoplineno
164 # Derived classes and clients can call the following methods
165 # to affect the stepping state.
167 def set_until(self
, frame
): #the name "until" is borrowed from gdb
168 """Stop when the line with the line no greater than the current one is
169 reached or when returning from current frame"""
170 self
._set
_stopinfo
(frame
, frame
, frame
.f_lineno
+1)
173 """Stop after one line of code."""
174 self
._set
_stopinfo
(None,None)
176 def set_next(self
, frame
):
177 """Stop on the next line in or below the given frame."""
178 self
._set
_stopinfo
(frame
, None)
180 def set_return(self
, frame
):
181 """Stop when returning from the given frame."""
182 self
._set
_stopinfo
(frame
.f_back
, frame
)
184 def set_trace(self
, frame
=None):
185 """Start debugging from `frame`.
187 If frame is not specified, debugging starts from caller's frame.
190 frame
= sys
._getframe
().f_back
193 frame
.f_trace
= self
.trace_dispatch
194 self
.botframe
= frame
197 sys
.settrace(self
.trace_dispatch
)
199 def set_continue(self
):
200 # Don't stop except at breakpoints or when finished
201 self
._set
_stopinfo
(self
.botframe
, None)
203 # no breakpoints; run without debugger overhead
205 frame
= sys
._getframe
().f_back
206 while frame
and frame
is not self
.botframe
:
211 self
.stopframe
= self
.botframe
212 self
.returnframe
= None
216 # Derived classes and clients can call the following methods
217 # to manipulate breakpoints. These methods return an
218 # error message is something went wrong, None if all is well.
219 # Set_break prints out the breakpoint line and file:lineno.
220 # Call self.get_*break*() to see the breakpoints or better
221 # for bp in Breakpoint.bpbynumber: if bp: bp.bpprint().
223 def set_break(self
, filename
, lineno
, temporary
=0, cond
= None,
225 filename
= self
.canonic(filename
)
226 import linecache
# Import as late as possible
227 line
= linecache
.getline(filename
, lineno
)
229 return 'Line %s:%d does not exist' % (filename
,
231 if not filename
in self
.breaks
:
232 self
.breaks
[filename
] = []
233 list = self
.breaks
[filename
]
234 if not lineno
in list:
236 bp
= Breakpoint(filename
, lineno
, temporary
, cond
, funcname
)
238 def clear_break(self
, filename
, lineno
):
239 filename
= self
.canonic(filename
)
240 if not filename
in self
.breaks
:
241 return 'There are no breakpoints in %s' % filename
242 if lineno
not in self
.breaks
[filename
]:
243 return 'There is no breakpoint at %s:%d' % (filename
,
245 # If there's only one bp in the list for that file,line
246 # pair, then remove the breaks entry
247 for bp
in Breakpoint
.bplist
[filename
, lineno
][:]:
249 if not Breakpoint
.bplist
.has_key((filename
, lineno
)):
250 self
.breaks
[filename
].remove(lineno
)
251 if not self
.breaks
[filename
]:
252 del self
.breaks
[filename
]
254 def clear_bpbynumber(self
, arg
):
258 return 'Non-numeric breakpoint number (%s)' % arg
260 bp
= Breakpoint
.bpbynumber
[number
]
262 return 'Breakpoint number (%d) out of range' % number
264 return 'Breakpoint (%d) already deleted' % number
265 self
.clear_break(bp
.file, bp
.line
)
267 def clear_all_file_breaks(self
, filename
):
268 filename
= self
.canonic(filename
)
269 if not filename
in self
.breaks
:
270 return 'There are no breakpoints in %s' % filename
271 for line
in self
.breaks
[filename
]:
272 blist
= Breakpoint
.bplist
[filename
, line
]
275 del self
.breaks
[filename
]
277 def clear_all_breaks(self
):
279 return 'There are no breakpoints'
280 for bp
in Breakpoint
.bpbynumber
:
285 def get_break(self
, filename
, lineno
):
286 filename
= self
.canonic(filename
)
287 return filename
in self
.breaks
and \
288 lineno
in self
.breaks
[filename
]
290 def get_breaks(self
, filename
, lineno
):
291 filename
= self
.canonic(filename
)
292 return filename
in self
.breaks
and \
293 lineno
in self
.breaks
[filename
] and \
294 Breakpoint
.bplist
[filename
, lineno
] or []
296 def get_file_breaks(self
, filename
):
297 filename
= self
.canonic(filename
)
298 if filename
in self
.breaks
:
299 return self
.breaks
[filename
]
303 def get_all_breaks(self
):
306 # Derived classes and clients can call the following method
307 # to get a data structure representing a stack trace.
309 def get_stack(self
, f
, t
):
311 if t
and t
.tb_frame
is f
:
314 stack
.append((f
, f
.f_lineno
))
315 if f
is self
.botframe
:
319 i
= max(0, len(stack
) - 1)
321 stack
.append((t
.tb_frame
, t
.tb_lineno
))
327 def format_stack_entry(self
, frame_lineno
, lprefix
=': '):
328 import linecache
, repr
329 frame
, lineno
= frame_lineno
330 filename
= self
.canonic(frame
.f_code
.co_filename
)
331 s
= '%s(%r)' % (filename
, lineno
)
332 if frame
.f_code
.co_name
:
333 s
= s
+ frame
.f_code
.co_name
336 if '__args__' in frame
.f_locals
:
337 args
= frame
.f_locals
['__args__']
341 s
= s
+ repr.repr(args
)
344 if '__return__' in frame
.f_locals
:
345 rv
= frame
.f_locals
['__return__']
347 s
= s
+ repr.repr(rv
)
348 line
= linecache
.getline(filename
, lineno
)
349 if line
: s
= s
+ lprefix
+ line
.strip()
352 # The following two methods can be called by clients to use
353 # a debugger to debug a statement, given as a string.
355 def run(self
, cmd
, globals=None, locals=None):
358 globals = __main__
.__dict
__
362 sys
.settrace(self
.trace_dispatch
)
363 if not isinstance(cmd
, types
.CodeType
):
366 exec cmd
in globals, locals
373 def runeval(self
, expr
, globals=None, locals=None):
376 globals = __main__
.__dict
__
380 sys
.settrace(self
.trace_dispatch
)
381 if not isinstance(expr
, types
.CodeType
):
384 return eval(expr
, globals, locals)
391 def runctx(self
, cmd
, globals, locals):
393 self
.run(cmd
, globals, locals)
395 # This method is more useful to debug a single function call.
397 def runcall(self
, func
, *args
, **kwds
):
399 sys
.settrace(self
.trace_dispatch
)
402 res
= func(*args
, **kwds
)
419 Implements temporary breakpoints, ignore counts, disabling and
420 (re)-enabling, and conditionals.
422 Breakpoints are indexed by number through bpbynumber and by
423 the file,line tuple using bplist. The former points to a
424 single instance of class Breakpoint. The latter points to a
425 list of such instances since there may be more than one
430 # XXX Keeping state in the class is a mistake -- this means
431 # you cannot have more than one active Bdb instance.
433 next
= 1 # Next bp to be assigned
434 bplist
= {} # indexed by (file, lineno) tuple
435 bpbynumber
= [None] # Each entry is None or an instance of Bpt
436 # index 0 is unused, except for marking an
437 # effective break .... see effective()
439 def __init__(self
, file, line
, temporary
=0, cond
=None, funcname
=None):
440 self
.funcname
= funcname
441 # Needed if funcname is not None.
442 self
.func_first_executable_line
= None
443 self
.file = file # This better be in canonical form!
445 self
.temporary
= temporary
450 self
.number
= Breakpoint
.next
451 Breakpoint
.next
= Breakpoint
.next
+ 1
452 # Build the two lists
453 self
.bpbynumber
.append(self
)
454 if self
.bplist
.has_key((file, line
)):
455 self
.bplist
[file, line
].append(self
)
457 self
.bplist
[file, line
] = [self
]
461 index
= (self
.file, self
.line
)
462 self
.bpbynumber
[self
.number
] = None # No longer in list
463 self
.bplist
[index
].remove(self
)
464 if not self
.bplist
[index
]:
465 # No more bp for this f:l combo
466 del self
.bplist
[index
]
474 def bpprint(self
, out
=None):
485 print >>out
, '%-4dbreakpoint %s at %s:%d' % (self
.number
, disp
,
486 self
.file, self
.line
)
488 print >>out
, '\tstop only if %s' % (self
.cond
,)
490 print >>out
, '\tignore next %d hits' % (self
.ignore
)
492 if (self
.hits
> 1): ss
= 's'
494 print >>out
, ('\tbreakpoint already hit %d time%s' %
497 # -----------end of Breakpoint class----------
499 def checkfuncname(b
, frame
):
500 """Check whether we should break here because of `b.funcname`."""
502 # Breakpoint was set via line number.
503 if b
.line
!= frame
.f_lineno
:
504 # Breakpoint was set at a line with a def statement and the function
505 # defined is called: don't break.
509 # Breakpoint set via function name.
511 if frame
.f_code
.co_name
!= b
.funcname
:
512 # It's not a function call, but rather execution of def statement.
515 # We are in the right frame.
516 if not b
.func_first_executable_line
:
517 # The function is entered for the 1st time.
518 b
.func_first_executable_line
= frame
.f_lineno
520 if b
.func_first_executable_line
!= frame
.f_lineno
:
521 # But we are not at the first line number: don't break.
525 # Determines if there is an effective (active) breakpoint at this
526 # line of code. Returns breakpoint number or 0 if none
527 def effective(file, line
, frame
):
528 """Determine which breakpoint for this file:line is to be acted upon.
530 Called only if we know there is a bpt at this
531 location. Returns breakpoint that was triggered and a flag
532 that indicates if it is ok to delete a temporary bp.
535 possibles
= Breakpoint
.bplist
[file,line
]
536 for i
in range(0, len(possibles
)):
540 if not checkfuncname(b
, frame
):
542 # Count every hit when bp is enabled
545 # If unconditional, and ignoring,
546 # go on to next, else break
548 b
.ignore
= b
.ignore
-1
551 # breakpoint and marker that's ok
552 # to delete if temporary
556 # Ignore count applies only to those bpt hits where the
557 # condition evaluates to true.
559 val
= eval(b
.cond
, frame
.f_globals
,
563 b
.ignore
= b
.ignore
-1
570 # if eval fails, most conservative
571 # thing is to stop on breakpoint
572 # regardless of ignore count.
573 # Don't delete temporary,
574 # as another hint to user.
578 # -------------------- testing --------------------
581 def user_call(self
, frame
, args
):
582 name
= frame
.f_code
.co_name
583 if not name
: name
= '???'
584 print '+++ call', name
, args
585 def user_line(self
, frame
):
587 name
= frame
.f_code
.co_name
588 if not name
: name
= '???'
589 fn
= self
.canonic(frame
.f_code
.co_filename
)
590 line
= linecache
.getline(fn
, frame
.f_lineno
)
591 print '+++', fn
, frame
.f_lineno
, name
, ':', line
.strip()
592 def user_return(self
, frame
, retval
):
593 print '+++ return', retval
594 def user_exception(self
, frame
, exc_stuff
):
595 print '+++ exception', exc_stuff
601 print 'bar returned', x
609 t
.run('import bdb; bdb.foo(10)')