blob: bc38607f8930f6260b5ffb8e7f3bc2329db07829 [file] [log] [blame]
Guido van Rossum6ea27cc1999-01-25 20:51:34 +00001# Debugger basics
Guido van Rossumbabe2bf1992-01-22 22:21:31 +00002
3import sys
Guido van Rossum4808dcb1996-10-15 14:40:21 +00004import types
Guido van Rossumbabe2bf1992-01-22 22:21:31 +00005
6BdbQuit = 'bdb.BdbQuit' # Exception to give up completely
7
8
Guido van Rossum6ea27cc1999-01-25 20:51:34 +00009class Bdb:
Guido van Rossumbabe2bf1992-01-22 22:21:31 +000010
Guido van Rossum6ea27cc1999-01-25 20:51:34 +000011 """Generic Python debugger base class.
12
13 This class takes care of details of the trace facility;
14 a derived class should implement user interaction.
15 The standard debugger class (pdb.Pdb) is an example.
16 """
17
Guido van Rossum5ef74b81993-06-23 11:55:24 +000018 def __init__(self):
Guido van Rossumbabe2bf1992-01-22 22:21:31 +000019 self.breaks = {}
Guido van Rossumbabe2bf1992-01-22 22:21:31 +000020
21 def reset(self):
Guido van Rossumb6775db1994-08-01 11:34:53 +000022 import linecache
23 linecache.checkcache()
Guido van Rossumbabe2bf1992-01-22 22:21:31 +000024 self.botframe = None
25 self.stopframe = None
26 self.returnframe = None
27 self.quitting = 0
28
29 def trace_dispatch(self, frame, event, arg):
30 if self.quitting:
31 return # None
32 if event == 'line':
33 return self.dispatch_line(frame)
34 if event == 'call':
35 return self.dispatch_call(frame, arg)
36 if event == 'return':
37 return self.dispatch_return(frame, arg)
38 if event == 'exception':
39 return self.dispatch_exception(frame, arg)
40 print 'bdb.Bdb.dispatch: unknown debugging event:', `event`
41 return self.trace_dispatch
42
43 def dispatch_line(self, frame):
44 if self.stop_here(frame) or self.break_here(frame):
45 self.user_line(frame)
46 if self.quitting: raise BdbQuit
47 return self.trace_dispatch
48
49 def dispatch_call(self, frame, arg):
Guido van Rossum75bb54c1998-09-28 15:33:38 +000050 # XXX 'arg' is no longer used
Guido van Rossumbabe2bf1992-01-22 22:21:31 +000051 if self.botframe is None:
52 # First call of dispatch since reset()
53 self.botframe = frame
54 return self.trace_dispatch
55 if not (self.stop_here(frame) or self.break_anywhere(frame)):
56 # No need to trace this function
57 return # None
58 self.user_call(frame, arg)
59 if self.quitting: raise BdbQuit
60 return self.trace_dispatch
61
62 def dispatch_return(self, frame, arg):
63 if self.stop_here(frame) or frame == self.returnframe:
64 self.user_return(frame, arg)
65 if self.quitting: raise BdbQuit
66
67 def dispatch_exception(self, frame, arg):
68 if self.stop_here(frame):
69 self.user_exception(frame, arg)
70 if self.quitting: raise BdbQuit
71 return self.trace_dispatch
72
73 # Normally derived classes don't override the following
Guido van Rossum4e160981992-09-02 20:43:20 +000074 # methods, but they may if they want to redefine the
Guido van Rossumbabe2bf1992-01-22 22:21:31 +000075 # definition of stopping and breakpoints.
76
77 def stop_here(self, frame):
78 if self.stopframe is None:
79 return 1
80 if frame is self.stopframe:
81 return 1
82 while frame is not None and frame is not self.stopframe:
83 if frame is self.botframe:
84 return 1
85 frame = frame.f_back
86 return 0
Guido van Rossumd93643f1998-09-11 22:38:35 +000087
Guido van Rossumbabe2bf1992-01-22 22:21:31 +000088 def break_here(self, frame):
Guido van Rossum66836171997-07-11 13:43:31 +000089 filename=frame.f_code.co_filename
Guido van Rossumff02e1d1997-07-11 13:42:50 +000090 if not self.breaks.has_key(filename):
Guido van Rossumbabe2bf1992-01-22 22:21:31 +000091 return 0
Guido van Rossumff02e1d1997-07-11 13:42:50 +000092 lineno=frame.f_lineno
93 if not lineno in self.breaks[filename]:
Guido van Rossumbabe2bf1992-01-22 22:21:31 +000094 return 0
Guido van Rossumd93643f1998-09-11 22:38:35 +000095 # flag says ok to delete temp. bp
96 (bp, flag) = effective(filename, lineno, frame)
97 if bp:
98 self.currentbp = bp.number
99 if (flag and bp.temporary):
Guido van Rossum691d27a1998-11-18 15:56:06 +0000100 self.do_clear(str(bp.number))
Guido van Rossumd93643f1998-09-11 22:38:35 +0000101 return 1
102 else:
103 return 0
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000104
105 def break_anywhere(self, frame):
106 return self.breaks.has_key(frame.f_code.co_filename)
107
Guido van Rossum4e160981992-09-02 20:43:20 +0000108 # Derived classes should override the user_* methods
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000109 # to gain control.
110
111 def user_call(self, frame, argument_list):
Guido van Rossum4e160981992-09-02 20:43:20 +0000112 # This method is called when there is the remote possibility
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000113 # that we ever need to stop in this function
114 pass
115
116 def user_line(self, frame):
Guido van Rossum4e160981992-09-02 20:43:20 +0000117 # This method is called when we stop or break at this line
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000118 pass
119
120 def user_return(self, frame, return_value):
Guido van Rossum4e160981992-09-02 20:43:20 +0000121 # This method is called when a return trap is set here
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000122 pass
123
124 def user_exception(self, frame, (exc_type, exc_value, exc_traceback)):
Guido van Rossum4e160981992-09-02 20:43:20 +0000125 # This method is called if an exception occurs,
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000126 # but only if we are to stop at or just below this level
127 pass
128
Guido van Rossum4e160981992-09-02 20:43:20 +0000129 # Derived classes and clients can call the following methods
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000130 # to affect the stepping state.
131
132 def set_step(self):
133 # Stop after one line of code
134 self.stopframe = None
135 self.returnframe = None
136 self.quitting = 0
137
138 def set_next(self, frame):
139 # Stop on the next line in or below the given frame
140 self.stopframe = frame
141 self.returnframe = None
142 self.quitting = 0
143
144 def set_return(self, frame):
145 # Stop when returning from the given frame
146 self.stopframe = frame.f_back
147 self.returnframe = frame
148 self.quitting = 0
149
Guido van Rossumb6775db1994-08-01 11:34:53 +0000150 def set_trace(self):
151 # Start debugging from here
152 try:
153 1 + ''
154 except:
Guido van Rossumf15d1591997-09-29 23:22:12 +0000155 frame = sys.exc_info()[2].tb_frame.f_back
Guido van Rossumb6775db1994-08-01 11:34:53 +0000156 self.reset()
157 while frame:
158 frame.f_trace = self.trace_dispatch
159 self.botframe = frame
160 frame = frame.f_back
161 self.set_step()
162 sys.settrace(self.trace_dispatch)
163
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000164 def set_continue(self):
165 # Don't stop except at breakpoints or when finished
166 self.stopframe = self.botframe
167 self.returnframe = None
168 self.quitting = 0
Guido van Rossumb6775db1994-08-01 11:34:53 +0000169 if not self.breaks:
170 # no breakpoints; run without debugger overhead
171 sys.settrace(None)
172 try:
173 1 + '' # raise an exception
174 except:
Guido van Rossumf15d1591997-09-29 23:22:12 +0000175 frame = sys.exc_info()[2].tb_frame.f_back
Guido van Rossumb6775db1994-08-01 11:34:53 +0000176 while frame and frame is not self.botframe:
177 del frame.f_trace
178 frame = frame.f_back
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000179
180 def set_quit(self):
181 self.stopframe = self.botframe
182 self.returnframe = None
183 self.quitting = 1
Guido van Rossumedbfcbd1992-03-27 15:09:46 +0000184 sys.settrace(None)
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000185
Guido van Rossum4e160981992-09-02 20:43:20 +0000186 # Derived classes and clients can call the following methods
187 # to manipulate breakpoints. These methods return an
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000188 # error message is something went wrong, None if all is well.
Guido van Rossumd93643f1998-09-11 22:38:35 +0000189 # Set_break prints out the breakpoint line and file:lineno.
190 # Call self.get_*break*() to see the breakpoints or better
191 # for bp in Breakpoint.bpbynumber: if bp: bp.bpprint().
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000192
Guido van Rossumd93643f1998-09-11 22:38:35 +0000193 def set_break(self, filename, lineno, temporary=0, cond = None):
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000194 import linecache # Import as late as possible
195 line = linecache.getline(filename, lineno)
196 if not line:
Guido van Rossum6ea27cc1999-01-25 20:51:34 +0000197 return 'Line %s:%d does not exist' % (filename,
198 lineno)
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000199 if not self.breaks.has_key(filename):
200 self.breaks[filename] = []
201 list = self.breaks[filename]
Guido van Rossumd93643f1998-09-11 22:38:35 +0000202 if not lineno in list:
203 list.append(lineno)
204 bp = Breakpoint(filename, lineno, temporary, cond)
Guido van Rossumd93643f1998-09-11 22:38:35 +0000205
Guido van Rossum6ea27cc1999-01-25 20:51:34 +0000206 def clear_break(self, filename, lineno):
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000207 if not self.breaks.has_key(filename):
Guido van Rossum6ea27cc1999-01-25 20:51:34 +0000208 return 'There are no breakpoints in %s' % filename
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000209 if lineno not in self.breaks[filename]:
Guido van Rossum6ea27cc1999-01-25 20:51:34 +0000210 return 'There is no breakpoint at %s:%d' % (filename,
211 lineno)
Guido van Rossumd93643f1998-09-11 22:38:35 +0000212 # If there's only one bp in the list for that file,line
213 # pair, then remove the breaks entry
Guido van Rossum6ea27cc1999-01-25 20:51:34 +0000214 for bp in Breakpoint.bplist[filename, lineno][:]:
215 bp.deleteMe()
216 if not Breakpoint.bplist.has_key((filename, lineno)):
Guido van Rossumd93643f1998-09-11 22:38:35 +0000217 self.breaks[filename].remove(lineno)
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000218 if not self.breaks[filename]:
219 del self.breaks[filename]
220
Guido van Rossum6ea27cc1999-01-25 20:51:34 +0000221 def clear_bpbynumber(self, arg):
222 try:
223 number = int(arg)
224 except:
225 return 'Non-numeric breakpoint number (%s)' % arg
226 try:
227 bp = Breakpoint.bpbynumber[number]
228 except IndexError:
229 return 'Breakpoint number (%d) out of range' % number
230 if not bp:
231 return 'Breakpoint (%d) already deleted' % number
232 self.clear_break(bp.file, bp.line)
233
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000234 def clear_all_file_breaks(self, filename):
235 if not self.breaks.has_key(filename):
Guido van Rossum6ea27cc1999-01-25 20:51:34 +0000236 return 'There are no breakpoints in %s' % filename
Guido van Rossumd93643f1998-09-11 22:38:35 +0000237 for line in self.breaks[filename]:
238 blist = Breakpoint.bplist[filename, line]
239 for bp in blist:
240 bp.deleteMe()
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000241 del self.breaks[filename]
242
Guido van Rossumb6775db1994-08-01 11:34:53 +0000243 def clear_all_breaks(self):
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000244 if not self.breaks:
Guido van Rossum6ea27cc1999-01-25 20:51:34 +0000245 return 'There are no breakpoints'
Guido van Rossumd93643f1998-09-11 22:38:35 +0000246 for bp in Breakpoint.bpbynumber:
247 if bp:
248 bp.deleteMe()
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000249 self.breaks = {}
250
251 def get_break(self, filename, lineno):
252 return self.breaks.has_key(filename) and \
253 lineno in self.breaks[filename]
254
Guido van Rossum6ea27cc1999-01-25 20:51:34 +0000255 def get_breaks(self, filename, lineno):
256 return self.breaks.has_key(filename) and \
257 lineno in self.breaks[filename] and \
258 Breakpoint.bplist[filename, line] or []
259
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000260 def get_file_breaks(self, filename):
261 if self.breaks.has_key(filename):
262 return self.breaks[filename]
263 else:
264 return []
265
266 def get_all_breaks(self):
267 return self.breaks
268
Guido van Rossum4e160981992-09-02 20:43:20 +0000269 # Derived classes and clients can call the following method
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000270 # to get a data structure representing a stack trace.
271
272 def get_stack(self, f, t):
273 stack = []
274 if t and t.tb_frame is f:
275 t = t.tb_next
276 while f is not None:
277 stack.append((f, f.f_lineno))
278 if f is self.botframe:
279 break
280 f = f.f_back
281 stack.reverse()
282 i = max(0, len(stack) - 1)
283 while t is not None:
284 stack.append((t.tb_frame, t.tb_lineno))
285 t = t.tb_next
286 return stack, i
287
Guido van Rossumfac6da21992-01-27 16:59:34 +0000288 #
289
Guido van Rossuma558e371994-11-10 22:27:35 +0000290 def format_stack_entry(self, frame_lineno, lprefix=': '):
Guido van Rossumb6775db1994-08-01 11:34:53 +0000291 import linecache, repr, string
Guido van Rossum89a78691992-12-14 12:57:56 +0000292 frame, lineno = frame_lineno
Guido van Rossumfac6da21992-01-27 16:59:34 +0000293 filename = frame.f_code.co_filename
294 s = filename + '(' + `lineno` + ')'
Guido van Rossumb6775db1994-08-01 11:34:53 +0000295 if frame.f_code.co_name:
Guido van Rossumd93643f1998-09-11 22:38:35 +0000296 s = s + frame.f_code.co_name
Guido van Rossumb6775db1994-08-01 11:34:53 +0000297 else:
Guido van Rossumd93643f1998-09-11 22:38:35 +0000298 s = s + "<lambda>"
Guido van Rossumfac6da21992-01-27 16:59:34 +0000299 if frame.f_locals.has_key('__args__'):
300 args = frame.f_locals['__args__']
Guido van Rossumb6aa92e1995-02-03 12:50:04 +0000301 else:
302 args = None
303 if args:
304 s = s + repr.repr(args)
305 else:
306 s = s + '()'
Guido van Rossumfac6da21992-01-27 16:59:34 +0000307 if frame.f_locals.has_key('__return__'):
308 rv = frame.f_locals['__return__']
309 s = s + '->'
310 s = s + repr.repr(rv)
311 line = linecache.getline(filename, lineno)
Guido van Rossuma558e371994-11-10 22:27:35 +0000312 if line: s = s + lprefix + string.strip(line)
Guido van Rossumfac6da21992-01-27 16:59:34 +0000313 return s
314
Guido van Rossum4e160981992-09-02 20:43:20 +0000315 # The following two methods can be called by clients to use
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000316 # a debugger to debug a statement, given as a string.
317
Guido van Rossum5e38b6f1995-02-27 13:13:40 +0000318 def run(self, cmd, globals=None, locals=None):
319 if globals is None:
320 import __main__
321 globals = __main__.__dict__
322 if locals is None:
323 locals = globals
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000324 self.reset()
Guido van Rossumedbfcbd1992-03-27 15:09:46 +0000325 sys.settrace(self.trace_dispatch)
Guido van Rossum4808dcb1996-10-15 14:40:21 +0000326 if type(cmd) <> types.CodeType:
327 cmd = cmd+'\n'
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000328 try:
Guido van Rossumceb3ba21992-04-03 16:32:37 +0000329 try:
Guido van Rossum4808dcb1996-10-15 14:40:21 +0000330 exec cmd in globals, locals
Guido van Rossumceb3ba21992-04-03 16:32:37 +0000331 except BdbQuit:
332 pass
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000333 finally:
334 self.quitting = 1
Guido van Rossumedbfcbd1992-03-27 15:09:46 +0000335 sys.settrace(None)
Guido van Rossum5e38b6f1995-02-27 13:13:40 +0000336
337 def runeval(self, expr, globals=None, locals=None):
338 if globals is None:
339 import __main__
340 globals = __main__.__dict__
341 if locals is None:
342 locals = globals
343 self.reset()
344 sys.settrace(self.trace_dispatch)
Guido van Rossum4808dcb1996-10-15 14:40:21 +0000345 if type(expr) <> types.CodeType:
346 expr = expr+'\n'
Guido van Rossum5e38b6f1995-02-27 13:13:40 +0000347 try:
348 try:
Guido van Rossum4808dcb1996-10-15 14:40:21 +0000349 return eval(expr, globals, locals)
Guido van Rossum5e38b6f1995-02-27 13:13:40 +0000350 except BdbQuit:
351 pass
352 finally:
353 self.quitting = 1
354 sys.settrace(None)
355
356 def runctx(self, cmd, globals, locals):
357 # B/W compatibility
358 self.run(cmd, globals, locals)
Guido van Rossum4e160981992-09-02 20:43:20 +0000359
360 # This method is more useful to debug a single function call.
361
362 def runcall(self, func, *args):
363 self.reset()
364 sys.settrace(self.trace_dispatch)
Guido van Rossum5e38b6f1995-02-27 13:13:40 +0000365 res = None
Guido van Rossum4e160981992-09-02 20:43:20 +0000366 try:
367 try:
Guido van Rossum5e38b6f1995-02-27 13:13:40 +0000368 res = apply(func, args)
Guido van Rossum4e160981992-09-02 20:43:20 +0000369 except BdbQuit:
370 pass
371 finally:
372 self.quitting = 1
373 sys.settrace(None)
Guido van Rossum5e38b6f1995-02-27 13:13:40 +0000374 return res
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000375
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000376
Guido van Rossumb6775db1994-08-01 11:34:53 +0000377def set_trace():
378 Bdb().set_trace()
379
Guido van Rossumd93643f1998-09-11 22:38:35 +0000380
381class Breakpoint:
382
383 """Breakpoint class
384
385 Implements temporary breakpoints, ignore counts, disabling and
386 (re)-enabling, and conditionals.
387
388 Breakpoints are indexed by number through bpbynumber and by
389 the file,line tuple using bplist. The former points to a
390 single instance of class Breakpoint. The latter points to a
391 list of such instances since there may be more than one
392 breakpoint per line.
393
394 """
395
Guido van Rossum6ea27cc1999-01-25 20:51:34 +0000396 # XXX Keeping state in the class is a mistake -- this means
397 # you cannot have more than one active Bdb instance.
Guido van Rossumd93643f1998-09-11 22:38:35 +0000398
399 next = 1 # Next bp to be assigned
400 bplist = {} # indexed by (file, lineno) tuple
401 bpbynumber = [None] # Each entry is None or an instance of Bpt
402 # index 0 is unused, except for marking an
403 # effective break .... see effective()
404
405 def __init__(self, file, line, temporary=0, cond = None):
406 self.file = file
407 self.line = line
408 self.temporary = temporary
409 self.cond = cond
410 self.enabled = 1
411 self.ignore = 0
412 self.hits = 0
413 self.number = Breakpoint.next
414 Breakpoint.next = Breakpoint.next + 1
415 # Build the two lists
416 self.bpbynumber.append(self)
417 if self.bplist.has_key((file, line)):
418 self.bplist[file, line].append(self)
419 else:
420 self.bplist[file, line] = [self]
421
422
423 def deleteMe(self):
424 index = (self.file, self.line)
425 self.bpbynumber[self.number] = None # No longer in list
426 self.bplist[index].remove(self)
427 if not self.bplist[index]:
428 # No more bp for this f:l combo
429 del self.bplist[index]
430
431 def enable(self):
432 self.enabled = 1
433
434 def disable(self):
435 self.enabled = 0
436
437 def bpprint(self):
438 if self.temporary:
439 disp = 'del '
440 else:
441 disp = 'keep '
442 if self.enabled:
443 disp = disp + 'yes'
444 else:
445 disp = disp + 'no '
446 print '%-4dbreakpoint %s at %s:%d' % (self.number, disp,
447 self.file, self.line)
448 if self.cond:
449 print '\tstop only if %s' % (self.cond,)
450 if self.ignore:
451 print '\tignore next %d hits' % (self.ignore)
452 if (self.hits):
453 if (self.hits > 1): ss = 's'
454 else: ss = ''
455 print ('\tbreakpoint already hit %d time%s' %
456 (self.hits, ss))
457
458# -----------end of Breakpoint class----------
459
460# Determines if there is an effective (active) breakpoint at this
461# line of code. Returns breakpoint number or 0 if none
462def effective(file, line, frame):
463 """Determine which breakpoint for this file:line is to be acted upon.
464
465 Called only if we know there is a bpt at this
466 location. Returns breakpoint that was triggered and a flag
467 that indicates if it is ok to delete a temporary bp.
468
469 """
470 possibles = Breakpoint.bplist[file,line]
471 for i in range(0, len(possibles)):
472 b = possibles[i]
473 if b.enabled == 0:
474 continue
475 # Count every hit when bp is enabled
476 b.hits = b.hits + 1
477 if not b.cond:
478 # If unconditional, and ignoring,
479 # go on to next, else break
480 if b.ignore > 0:
481 b.ignore = b.ignore -1
482 continue
483 else:
484 # breakpoint and marker that's ok
485 # to delete if temporary
486 return (b,1)
487 else:
488 # Conditional bp.
489 # Ignore count applies only to those bpt hits where the
490 # condition evaluates to true.
491 try:
492 val = eval(b.cond, frame.f_globals,
493 frame.f_locals)
494 if val:
495 if b.ignore > 0:
496 b.ignore = b.ignore -1
497 # continue
498 else:
499 return (b,1)
500 # else:
501 # continue
502 except:
503 # if eval fails, most conservative
504 # thing is to stop on breakpoint
505 # regardless of ignore count.
506 # Don't delete temporary,
507 # as another hint to user.
508 return (b,0)
509 return (None, None)
510
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000511# -------------------- testing --------------------
512
513class Tdb(Bdb):
514 def user_call(self, frame, args):
Guido van Rossumb6775db1994-08-01 11:34:53 +0000515 name = frame.f_code.co_name
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000516 if not name: name = '???'
517 print '+++ call', name, args
518 def user_line(self, frame):
Guido van Rossumb6775db1994-08-01 11:34:53 +0000519 import linecache, string
520 name = frame.f_code.co_name
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000521 if not name: name = '???'
522 fn = frame.f_code.co_filename
523 line = linecache.getline(fn, frame.f_lineno)
524 print '+++', fn, frame.f_lineno, name, ':', string.strip(line)
525 def user_return(self, frame, retval):
526 print '+++ return', retval
527 def user_exception(self, frame, exc_stuff):
528 print '+++ exception', exc_stuff
529 self.set_continue()
530
531def foo(n):
532 print 'foo(', n, ')'
533 x = bar(n*10)
534 print 'bar returned', x
535
536def bar(a):
537 print 'bar(', a, ')'
538 return a/2
539
540def test():
Guido van Rossum5ef74b81993-06-23 11:55:24 +0000541 t = Tdb()
Guido van Rossumbabe2bf1992-01-22 22:21:31 +0000542 t.run('import bdb; bdb.foo(10)')