1 # A generic Python debugger base class.
2 # This class takes care of details of the trace facility;
3 # a derived class should implement user interaction.
4 # There are two debuggers based upon this:
5 # 'pdb', a text-oriented debugger not unlike dbx or gdb;
6 # and 'wdb', a window-oriented debugger.
7 # And of course... you can roll your own!
11 BdbQuit
= 'bdb.BdbQuit' # Exception to give up completely
14 class Bdb
: # Basic Debugger
21 linecache
.checkcache()
24 self
.returnframe
= None
27 def trace_dispatch(self
, frame
, event
, arg
):
31 return self
.dispatch_line(frame
)
33 return self
.dispatch_call(frame
, arg
)
35 return self
.dispatch_return(frame
, arg
)
36 if event
== 'exception':
37 return self
.dispatch_exception(frame
, arg
)
38 print 'bdb.Bdb.dispatch: unknown debugging event:', `event`
39 return self
.trace_dispatch
41 def dispatch_line(self
, frame
):
42 if self
.stop_here(frame
) or self
.break_here(frame
):
44 if self
.quitting
: raise BdbQuit
45 return self
.trace_dispatch
47 def dispatch_call(self
, frame
, arg
):
48 frame
.f_locals
['__args__'] = arg
49 if self
.botframe
is None:
50 # First call of dispatch since reset()
52 return self
.trace_dispatch
53 if not (self
.stop_here(frame
) or self
.break_anywhere(frame
)):
54 # No need to trace this function
56 self
.user_call(frame
, arg
)
57 if self
.quitting
: raise BdbQuit
58 return self
.trace_dispatch
60 def dispatch_return(self
, frame
, arg
):
61 if self
.stop_here(frame
) or frame
== self
.returnframe
:
62 self
.user_return(frame
, arg
)
63 if self
.quitting
: raise BdbQuit
65 def dispatch_exception(self
, frame
, arg
):
66 if self
.stop_here(frame
):
67 self
.user_exception(frame
, arg
)
68 if self
.quitting
: raise BdbQuit
69 return self
.trace_dispatch
71 # Normally derived classes don't override the following
72 # methods, but they may if they want to redefine the
73 # definition of stopping and breakpoints.
75 def stop_here(self
, frame
):
76 if self
.stopframe
is None:
78 if frame
is self
.stopframe
:
80 while frame
is not None and frame
is not self
.stopframe
:
81 if frame
is self
.botframe
:
86 def break_here(self
, frame
):
87 if not self
.breaks
.has_key(frame
.f_code
.co_filename
):
89 if not frame
.f_lineno
in \
90 self
.breaks
[frame
.f_code
.co_filename
]:
94 def break_anywhere(self
, frame
):
95 return self
.breaks
.has_key(frame
.f_code
.co_filename
)
97 # Derived classes should override the user_* methods
100 def user_call(self
, frame
, argument_list
):
101 # This method is called when there is the remote possibility
102 # that we ever need to stop in this function
105 def user_line(self
, frame
):
106 # This method is called when we stop or break at this line
109 def user_return(self
, frame
, return_value
):
110 # This method is called when a return trap is set here
113 def user_exception(self
, frame
, (exc_type
, exc_value
, exc_traceback
)):
114 # This method is called if an exception occurs,
115 # but only if we are to stop at or just below this level
118 # Derived classes and clients can call the following methods
119 # to affect the stepping state.
122 # Stop after one line of code
123 self
.stopframe
= None
124 self
.returnframe
= None
127 def set_next(self
, frame
):
128 # Stop on the next line in or below the given frame
129 self
.stopframe
= frame
130 self
.returnframe
= None
133 def set_return(self
, frame
):
134 # Stop when returning from the given frame
135 self
.stopframe
= frame
.f_back
136 self
.returnframe
= frame
140 # Start debugging from here
144 frame
= sys
.exc_traceback
.tb_frame
.f_back
147 frame
.f_trace
= self
.trace_dispatch
148 self
.botframe
= frame
151 sys
.settrace(self
.trace_dispatch
)
153 def set_continue(self
):
154 # Don't stop except at breakpoints or when finished
155 self
.stopframe
= self
.botframe
156 self
.returnframe
= None
159 # no breakpoints; run without debugger overhead
162 1 + '' # raise an exception
164 frame
= sys
.exc_traceback
.tb_frame
.f_back
165 while frame
and frame
is not self
.botframe
:
170 self
.stopframe
= self
.botframe
171 self
.returnframe
= None
175 # Derived classes and clients can call the following methods
176 # to manipulate breakpoints. These methods return an
177 # error message is something went wrong, None if all is well.
178 # Call self.get_*break*() to see the breakpoints.
180 def set_break(self
, filename
, lineno
):
181 import linecache
# Import as late as possible
182 line
= linecache
.getline(filename
, lineno
)
184 return 'That line does not exist!'
185 if not self
.breaks
.has_key(filename
):
186 self
.breaks
[filename
] = []
187 list = self
.breaks
[filename
]
189 return 'There is already a breakpoint there!'
192 def clear_break(self
, filename
, lineno
):
193 if not self
.breaks
.has_key(filename
):
194 return 'There are no breakpoints in that file!'
195 if lineno
not in self
.breaks
[filename
]:
196 return 'There is no breakpoint there!'
197 self
.breaks
[filename
].remove(lineno
)
198 if not self
.breaks
[filename
]:
199 del self
.breaks
[filename
]
201 def clear_all_file_breaks(self
, filename
):
202 if not self
.breaks
.has_key(filename
):
203 return 'There are no breakpoints in that file!'
204 del self
.breaks
[filename
]
206 def clear_all_breaks(self
):
208 return 'There are no breakpoints!'
211 def get_break(self
, filename
, lineno
):
212 return self
.breaks
.has_key(filename
) and \
213 lineno
in self
.breaks
[filename
]
215 def get_file_breaks(self
, filename
):
216 if self
.breaks
.has_key(filename
):
217 return self
.breaks
[filename
]
221 def get_all_breaks(self
):
224 # Derived classes and clients can call the following method
225 # to get a data structure representing a stack trace.
227 def get_stack(self
, f
, t
):
229 if t
and t
.tb_frame
is f
:
232 stack
.append((f
, f
.f_lineno
))
233 if f
is self
.botframe
:
237 i
= max(0, len(stack
) - 1)
239 stack
.append((t
.tb_frame
, t
.tb_lineno
))
245 def format_stack_entry(self
, frame_lineno
, lprefix
=': '):
246 import linecache
, repr, string
247 frame
, lineno
= frame_lineno
248 filename
= frame
.f_code
.co_filename
249 s
= filename
+ '(' + `lineno`
+ ')'
250 if frame
.f_code
.co_name
:
251 s
= s
+ frame
.f_code
.co_name
254 if frame
.f_locals
.has_key('__args__'):
255 args
= frame
.f_locals
['__args__']
259 s
= s
+ repr.repr(args
)
262 if frame
.f_locals
.has_key('__return__'):
263 rv
= frame
.f_locals
['__return__']
265 s
= s
+ repr.repr(rv
)
266 line
= linecache
.getline(filename
, lineno
)
267 if line
: s
= s
+ lprefix
+ string
.strip(line
)
270 # The following two methods can be called by clients to use
271 # a debugger to debug a statement, given as a string.
273 def run(self
, cmd
, globals=None, locals=None):
276 globals = __main__
.__dict
__
280 sys
.settrace(self
.trace_dispatch
)
283 exec cmd
+ '\n' in globals, locals
290 def runeval(self
, expr
, globals=None, locals=None):
293 globals = __main__
.__dict
__
297 sys
.settrace(self
.trace_dispatch
)
300 return eval(expr
+ '\n', globals, locals)
307 def runctx(self
, cmd
, globals, locals):
309 self
.run(cmd
, globals, locals)
311 # This method is more useful to debug a single function call.
313 def runcall(self
, func
, *args
):
315 sys
.settrace(self
.trace_dispatch
)
319 res
= apply(func
, args
)
331 # -------------------- testing --------------------
334 def user_call(self
, frame
, args
):
335 name
= frame
.f_code
.co_name
336 if not name
: name
= '???'
337 print '+++ call', name
, args
338 def user_line(self
, frame
):
339 import linecache
, string
340 name
= frame
.f_code
.co_name
341 if not name
: name
= '???'
342 fn
= frame
.f_code
.co_filename
343 line
= linecache
.getline(fn
, frame
.f_lineno
)
344 print '+++', fn
, frame
.f_lineno
, name
, ':', string
.strip(line
)
345 def user_return(self
, frame
, retval
):
346 print '+++ return', retval
347 def user_exception(self
, frame
, exc_stuff
):
348 print '+++ exception', exc_stuff
354 print 'bar returned', x
362 t
.run('import bdb; bdb.foo(10)')