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
.canonic(frame
.f_code
.co_filename
) in self
.breaks
136 # Derived classes should override the user_* methods
139 def user_call(self
, frame
, argument_list
):
140 """This method is called when there is the remote possibility
141 that we ever need to stop in this function."""
144 def user_line(self
, frame
):
145 """This method is called when we stop or break at this line."""
148 def user_return(self
, frame
, return_value
):
149 """This method is called when a return trap is set here."""
152 def user_exception(self
, frame
, exc_info
):
153 exc_type
, exc_value
, exc_traceback
= exc_info
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
))
324 i
= max(0, len(stack
) - 1)
329 def format_stack_entry(self
, frame_lineno
, lprefix
=': '):
330 import linecache
, repr
331 frame
, lineno
= frame_lineno
332 filename
= self
.canonic(frame
.f_code
.co_filename
)
333 s
= '%s(%r)' % (filename
, lineno
)
334 if frame
.f_code
.co_name
:
335 s
= s
+ frame
.f_code
.co_name
338 if '__args__' in frame
.f_locals
:
339 args
= frame
.f_locals
['__args__']
343 s
= s
+ repr.repr(args
)
346 if '__return__' in frame
.f_locals
:
347 rv
= frame
.f_locals
['__return__']
349 s
= s
+ repr.repr(rv
)
350 line
= linecache
.getline(filename
, lineno
, frame
.f_globals
)
351 if line
: s
= s
+ lprefix
+ line
.strip()
354 # The following two methods can be called by clients to use
355 # a debugger to debug a statement, given as a string.
357 def run(self
, cmd
, globals=None, locals=None):
360 globals = __main__
.__dict
__
364 sys
.settrace(self
.trace_dispatch
)
365 if not isinstance(cmd
, types
.CodeType
):
368 exec cmd
in globals, locals
375 def runeval(self
, expr
, globals=None, locals=None):
378 globals = __main__
.__dict
__
382 sys
.settrace(self
.trace_dispatch
)
383 if not isinstance(expr
, types
.CodeType
):
386 return eval(expr
, globals, locals)
393 def runctx(self
, cmd
, globals, locals):
395 self
.run(cmd
, globals, locals)
397 # This method is more useful to debug a single function call.
399 def runcall(self
, func
, *args
, **kwds
):
401 sys
.settrace(self
.trace_dispatch
)
404 res
= func(*args
, **kwds
)
421 Implements temporary breakpoints, ignore counts, disabling and
422 (re)-enabling, and conditionals.
424 Breakpoints are indexed by number through bpbynumber and by
425 the file,line tuple using bplist. The former points to a
426 single instance of class Breakpoint. The latter points to a
427 list of such instances since there may be more than one
432 # XXX Keeping state in the class is a mistake -- this means
433 # you cannot have more than one active Bdb instance.
435 next
= 1 # Next bp to be assigned
436 bplist
= {} # indexed by (file, lineno) tuple
437 bpbynumber
= [None] # Each entry is None or an instance of Bpt
438 # index 0 is unused, except for marking an
439 # effective break .... see effective()
441 def __init__(self
, file, line
, temporary
=0, cond
=None, funcname
=None):
442 self
.funcname
= funcname
443 # Needed if funcname is not None.
444 self
.func_first_executable_line
= None
445 self
.file = file # This better be in canonical form!
447 self
.temporary
= temporary
452 self
.number
= Breakpoint
.next
453 Breakpoint
.next
= Breakpoint
.next
+ 1
454 # Build the two lists
455 self
.bpbynumber
.append(self
)
456 if self
.bplist
.has_key((file, line
)):
457 self
.bplist
[file, line
].append(self
)
459 self
.bplist
[file, line
] = [self
]
463 index
= (self
.file, self
.line
)
464 self
.bpbynumber
[self
.number
] = None # No longer in list
465 self
.bplist
[index
].remove(self
)
466 if not self
.bplist
[index
]:
467 # No more bp for this f:l combo
468 del self
.bplist
[index
]
476 def bpprint(self
, out
=None):
487 print >>out
, '%-4dbreakpoint %s at %s:%d' % (self
.number
, disp
,
488 self
.file, self
.line
)
490 print >>out
, '\tstop only if %s' % (self
.cond
,)
492 print >>out
, '\tignore next %d hits' % (self
.ignore
)
494 if (self
.hits
> 1): ss
= 's'
496 print >>out
, ('\tbreakpoint already hit %d time%s' %
499 # -----------end of Breakpoint class----------
501 def checkfuncname(b
, frame
):
502 """Check whether we should break here because of `b.funcname`."""
504 # Breakpoint was set via line number.
505 if b
.line
!= frame
.f_lineno
:
506 # Breakpoint was set at a line with a def statement and the function
507 # defined is called: don't break.
511 # Breakpoint set via function name.
513 if frame
.f_code
.co_name
!= b
.funcname
:
514 # It's not a function call, but rather execution of def statement.
517 # We are in the right frame.
518 if not b
.func_first_executable_line
:
519 # The function is entered for the 1st time.
520 b
.func_first_executable_line
= frame
.f_lineno
522 if b
.func_first_executable_line
!= frame
.f_lineno
:
523 # But we are not at the first line number: don't break.
527 # Determines if there is an effective (active) breakpoint at this
528 # line of code. Returns breakpoint number or 0 if none
529 def effective(file, line
, frame
):
530 """Determine which breakpoint for this file:line is to be acted upon.
532 Called only if we know there is a bpt at this
533 location. Returns breakpoint that was triggered and a flag
534 that indicates if it is ok to delete a temporary bp.
537 possibles
= Breakpoint
.bplist
[file,line
]
538 for i
in range(0, len(possibles
)):
542 if not checkfuncname(b
, frame
):
544 # Count every hit when bp is enabled
547 # If unconditional, and ignoring,
548 # go on to next, else break
550 b
.ignore
= b
.ignore
-1
553 # breakpoint and marker that's ok
554 # to delete if temporary
558 # Ignore count applies only to those bpt hits where the
559 # condition evaluates to true.
561 val
= eval(b
.cond
, frame
.f_globals
,
565 b
.ignore
= b
.ignore
-1
572 # if eval fails, most conservative
573 # thing is to stop on breakpoint
574 # regardless of ignore count.
575 # Don't delete temporary,
576 # as another hint to user.
580 # -------------------- testing --------------------
583 def user_call(self
, frame
, args
):
584 name
= frame
.f_code
.co_name
585 if not name
: name
= '???'
586 print '+++ call', name
, args
587 def user_line(self
, frame
):
589 name
= frame
.f_code
.co_name
590 if not name
: name
= '???'
591 fn
= self
.canonic(frame
.f_code
.co_filename
)
592 line
= linecache
.getline(fn
, frame
.f_lineno
, frame
.f_globals
)
593 print '+++', fn
, frame
.f_lineno
, name
, ':', line
.strip()
594 def user_return(self
, frame
, retval
):
595 print '+++ return', retval
596 def user_exception(self
, frame
, exc_stuff
):
597 print '+++ exception', exc_stuff
603 print 'bar returned', x
611 t
.run('import bdb; bdb.foo(10)')