Merged revisions 83951 via svnmerge from
[python/dscho.git] / Lib / bdb.py
blobf16414d506fd5fd93a3bbac7cfb4c45313eb3728
1 """Debugger basics"""
3 import fnmatch
4 import sys
5 import os
6 import types
8 __all__ = ["BdbQuit","Bdb","Breakpoint"]
10 class BdbQuit(Exception):
11 """Exception to give up completely"""
14 class Bdb:
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.
21 """
23 def __init__(self, skip=None):
24 self.skip = set(skip) if skip else None
25 self.breaks = {}
26 self.fncache = {}
28 def canonic(self, filename):
29 if filename == "<" + filename[1:-1] + ">":
30 return filename
31 canonic = self.fncache.get(filename)
32 if not canonic:
33 canonic = os.path.abspath(filename)
34 canonic = os.path.normcase(canonic)
35 self.fncache[filename] = canonic
36 return canonic
38 def reset(self):
39 import linecache
40 linecache.checkcache()
41 self.botframe = None
42 self._set_stopinfo(None, None)
44 def trace_dispatch(self, frame, event, arg):
45 if self.quitting:
46 return # None
47 if event == 'line':
48 return self.dispatch_line(frame)
49 if event == 'call':
50 return self.dispatch_call(frame, arg)
51 if event == 'return':
52 return self.dispatch_return(frame, arg)
53 if event == 'exception':
54 return self.dispatch_exception(frame, arg)
55 if event == 'c_call':
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):
66 self.user_line(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
78 return # None
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):
102 return True
103 return False
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.
108 if self.skip and \
109 self.is_skipped_module(frame.f_globals.get('__name__')):
110 return False
111 if frame is self.stopframe:
112 if self.stoplineno == -1:
113 return False
114 return frame.f_lineno >= self.stoplineno
115 while frame is not None and frame is not self.stopframe:
116 if frame is self.botframe:
117 return True
118 frame = frame.f_back
119 return False
121 def break_here(self, frame):
122 filename = self.canonic(frame.f_code.co_filename)
123 if not filename in self.breaks:
124 return False
125 lineno = frame.f_lineno
126 if not lineno in self.breaks[filename]:
127 # The line itself has no breakpoint, but maybe the line is the
128 # first line of a function with breakpoint set by function name.
129 lineno = frame.f_code.co_firstlineno
130 if not lineno in self.breaks[filename]:
131 return False
133 # flag says ok to delete temp. bp
134 (bp, flag) = effective(filename, lineno, frame)
135 if bp:
136 self.currentbp = bp.number
137 if (flag and bp.temporary):
138 self.do_clear(str(bp.number))
139 return True
140 else:
141 return False
143 def do_clear(self, arg):
144 raise NotImplementedError("subclass of bdb must implement do_clear()")
146 def break_anywhere(self, frame):
147 return self.canonic(frame.f_code.co_filename) in self.breaks
149 # Derived classes should override the user_* methods
150 # to gain control.
152 def user_call(self, frame, argument_list):
153 """This method is called when there is the remote possibility
154 that we ever need to stop in this function."""
155 pass
157 def user_line(self, frame):
158 """This method is called when we stop or break at this line."""
159 pass
161 def user_return(self, frame, return_value):
162 """This method is called when a return trap is set here."""
163 pass
165 def user_exception(self, frame, exc_info):
166 """This method is called if an exception occurs,
167 but only if we are to stop at or just below this level."""
168 pass
170 def _set_stopinfo(self, stopframe, returnframe, stoplineno=0):
171 self.stopframe = stopframe
172 self.returnframe = returnframe
173 self.quitting = 0
174 # stoplineno >= 0 means: stop at line >= the stoplineno
175 # stoplineno -1 means: don't stop at all
176 self.stoplineno = stoplineno
178 # Derived classes and clients can call the following methods
179 # to affect the stepping state.
181 def set_until(self, frame): #the name "until" is borrowed from gdb
182 """Stop when the line with the line no greater than the current one is
183 reached or when returning from current frame"""
184 self._set_stopinfo(frame, frame, frame.f_lineno+1)
186 def set_step(self):
187 """Stop after one line of code."""
188 self._set_stopinfo(None, None)
190 def set_next(self, frame):
191 """Stop on the next line in or below the given frame."""
192 self._set_stopinfo(frame, None)
194 def set_return(self, frame):
195 """Stop when returning from the given frame."""
196 self._set_stopinfo(frame.f_back, frame)
198 def set_trace(self, frame=None):
199 """Start debugging from `frame`.
201 If frame is not specified, debugging starts from caller's frame.
203 if frame is None:
204 frame = sys._getframe().f_back
205 self.reset()
206 while frame:
207 frame.f_trace = self.trace_dispatch
208 self.botframe = frame
209 frame = frame.f_back
210 self.set_step()
211 sys.settrace(self.trace_dispatch)
213 def set_continue(self):
214 # Don't stop except at breakpoints or when finished
215 self._set_stopinfo(self.botframe, None, -1)
216 if not self.breaks:
217 # no breakpoints; run without debugger overhead
218 sys.settrace(None)
219 frame = sys._getframe().f_back
220 while frame and frame is not self.botframe:
221 del frame.f_trace
222 frame = frame.f_back
224 def set_quit(self):
225 self.stopframe = self.botframe
226 self.returnframe = None
227 self.quitting = 1
228 sys.settrace(None)
230 # Derived classes and clients can call the following methods
231 # to manipulate breakpoints. These methods return an
232 # error message is something went wrong, None if all is well.
233 # Set_break prints out the breakpoint line and file:lineno.
234 # Call self.get_*break*() to see the breakpoints or better
235 # for bp in Breakpoint.bpbynumber: if bp: bp.bpprint().
237 def set_break(self, filename, lineno, temporary=0, cond = None,
238 funcname=None):
239 filename = self.canonic(filename)
240 import linecache # Import as late as possible
241 line = linecache.getline(filename, lineno)
242 if not line:
243 return 'Line %s:%d does not exist' % (filename,
244 lineno)
245 if not filename in self.breaks:
246 self.breaks[filename] = []
247 list = self.breaks[filename]
248 if not lineno in list:
249 list.append(lineno)
250 bp = Breakpoint(filename, lineno, temporary, cond, funcname)
252 def clear_break(self, filename, lineno):
253 filename = self.canonic(filename)
254 if not filename in self.breaks:
255 return 'There are no breakpoints in %s' % filename
256 if lineno not in self.breaks[filename]:
257 return 'There is no breakpoint at %s:%d' % (filename,
258 lineno)
259 # If there's only one bp in the list for that file,line
260 # pair, then remove the breaks entry
261 for bp in Breakpoint.bplist[filename, lineno][:]:
262 bp.deleteMe()
263 if (filename, lineno) not in Breakpoint.bplist:
264 self.breaks[filename].remove(lineno)
265 if not self.breaks[filename]:
266 del self.breaks[filename]
268 def clear_bpbynumber(self, arg):
269 try:
270 number = int(arg)
271 except:
272 return 'Non-numeric breakpoint number (%s)' % arg
273 try:
274 bp = Breakpoint.bpbynumber[number]
275 except IndexError:
276 return 'Breakpoint number (%d) out of range' % number
277 if not bp:
278 return 'Breakpoint (%d) already deleted' % number
279 self.clear_break(bp.file, bp.line)
281 def clear_all_file_breaks(self, filename):
282 filename = self.canonic(filename)
283 if not filename in self.breaks:
284 return 'There are no breakpoints in %s' % filename
285 for line in self.breaks[filename]:
286 blist = Breakpoint.bplist[filename, line]
287 for bp in blist:
288 bp.deleteMe()
289 del self.breaks[filename]
291 def clear_all_breaks(self):
292 if not self.breaks:
293 return 'There are no breakpoints'
294 for bp in Breakpoint.bpbynumber:
295 if bp:
296 bp.deleteMe()
297 self.breaks = {}
299 def get_break(self, filename, lineno):
300 filename = self.canonic(filename)
301 return filename in self.breaks and \
302 lineno in self.breaks[filename]
304 def get_breaks(self, filename, lineno):
305 filename = self.canonic(filename)
306 return filename in self.breaks and \
307 lineno in self.breaks[filename] and \
308 Breakpoint.bplist[filename, lineno] or []
310 def get_file_breaks(self, filename):
311 filename = self.canonic(filename)
312 if filename in self.breaks:
313 return self.breaks[filename]
314 else:
315 return []
317 def get_all_breaks(self):
318 return self.breaks
320 # Derived classes and clients can call the following method
321 # to get a data structure representing a stack trace.
323 def get_stack(self, f, t):
324 stack = []
325 if t and t.tb_frame is f:
326 t = t.tb_next
327 while f is not None:
328 stack.append((f, f.f_lineno))
329 if f is self.botframe:
330 break
331 f = f.f_back
332 stack.reverse()
333 i = max(0, len(stack) - 1)
334 while t is not None:
335 stack.append((t.tb_frame, t.tb_lineno))
336 t = t.tb_next
337 if f is None:
338 i = max(0, len(stack) - 1)
339 return stack, i
343 def format_stack_entry(self, frame_lineno, lprefix=': '):
344 import linecache, reprlib
345 frame, lineno = frame_lineno
346 filename = self.canonic(frame.f_code.co_filename)
347 s = '%s(%r)' % (filename, lineno)
348 if frame.f_code.co_name:
349 s = s + frame.f_code.co_name
350 else:
351 s = s + "<lambda>"
352 if '__args__' in frame.f_locals:
353 args = frame.f_locals['__args__']
354 else:
355 args = None
356 if args:
357 s = s + reprlib.repr(args)
358 else:
359 s = s + '()'
360 if '__return__' in frame.f_locals:
361 rv = frame.f_locals['__return__']
362 s = s + '->'
363 s = s + reprlib.repr(rv)
364 line = linecache.getline(filename, lineno, frame.f_globals)
365 if line: s = s + lprefix + line.strip()
366 return s
368 # The following two methods can be called by clients to use
369 # a debugger to debug a statement, given as a string.
371 def run(self, cmd, globals=None, locals=None):
372 if globals is None:
373 import __main__
374 globals = __main__.__dict__
375 if locals is None:
376 locals = globals
377 self.reset()
378 sys.settrace(self.trace_dispatch)
379 if not isinstance(cmd, types.CodeType):
380 cmd = cmd+'\n'
381 try:
382 exec(cmd, globals, locals)
383 except BdbQuit:
384 pass
385 finally:
386 self.quitting = 1
387 sys.settrace(None)
389 def runeval(self, expr, globals=None, locals=None):
390 if globals is None:
391 import __main__
392 globals = __main__.__dict__
393 if locals is None:
394 locals = globals
395 self.reset()
396 sys.settrace(self.trace_dispatch)
397 if not isinstance(expr, types.CodeType):
398 expr = expr+'\n'
399 try:
400 return eval(expr, globals, locals)
401 except BdbQuit:
402 pass
403 finally:
404 self.quitting = 1
405 sys.settrace(None)
407 def runctx(self, cmd, globals, locals):
408 # B/W compatibility
409 self.run(cmd, globals, locals)
411 # This method is more useful to debug a single function call.
413 def runcall(self, func, *args, **kwds):
414 self.reset()
415 sys.settrace(self.trace_dispatch)
416 res = None
417 try:
418 res = func(*args, **kwds)
419 except BdbQuit:
420 pass
421 finally:
422 self.quitting = 1
423 sys.settrace(None)
424 return res
427 def set_trace():
428 Bdb().set_trace()
431 class Breakpoint:
433 """Breakpoint class
435 Implements temporary breakpoints, ignore counts, disabling and
436 (re)-enabling, and conditionals.
438 Breakpoints are indexed by number through bpbynumber and by
439 the file,line tuple using bplist. The former points to a
440 single instance of class Breakpoint. The latter points to a
441 list of such instances since there may be more than one
442 breakpoint per line.
446 # XXX Keeping state in the class is a mistake -- this means
447 # you cannot have more than one active Bdb instance.
449 next = 1 # Next bp to be assigned
450 bplist = {} # indexed by (file, lineno) tuple
451 bpbynumber = [None] # Each entry is None or an instance of Bpt
452 # index 0 is unused, except for marking an
453 # effective break .... see effective()
455 def __init__(self, file, line, temporary=0, cond=None, funcname=None):
456 self.funcname = funcname
457 # Needed if funcname is not None.
458 self.func_first_executable_line = None
459 self.file = file # This better be in canonical form!
460 self.line = line
461 self.temporary = temporary
462 self.cond = cond
463 self.enabled = 1
464 self.ignore = 0
465 self.hits = 0
466 self.number = Breakpoint.next
467 Breakpoint.next = Breakpoint.next + 1
468 # Build the two lists
469 self.bpbynumber.append(self)
470 if (file, line) in self.bplist:
471 self.bplist[file, line].append(self)
472 else:
473 self.bplist[file, line] = [self]
476 def deleteMe(self):
477 index = (self.file, self.line)
478 self.bpbynumber[self.number] = None # No longer in list
479 self.bplist[index].remove(self)
480 if not self.bplist[index]:
481 # No more bp for this f:l combo
482 del self.bplist[index]
484 def enable(self):
485 self.enabled = 1
487 def disable(self):
488 self.enabled = 0
490 def bpprint(self, out=None):
491 if out is None:
492 out = sys.stdout
493 if self.temporary:
494 disp = 'del '
495 else:
496 disp = 'keep '
497 if self.enabled:
498 disp = disp + 'yes '
499 else:
500 disp = disp + 'no '
501 print('%-4dbreakpoint %s at %s:%d' % (self.number, disp,
502 self.file, self.line), file=out)
503 if self.cond:
504 print('\tstop only if %s' % (self.cond,), file=out)
505 if self.ignore:
506 print('\tignore next %d hits' % (self.ignore), file=out)
507 if (self.hits):
508 if (self.hits > 1): ss = 's'
509 else: ss = ''
510 print(('\tbreakpoint already hit %d time%s' %
511 (self.hits, ss)), file=out)
513 # -----------end of Breakpoint class----------
515 def checkfuncname(b, frame):
516 """Check whether we should break here because of `b.funcname`."""
517 if not b.funcname:
518 # Breakpoint was set via line number.
519 if b.line != frame.f_lineno:
520 # Breakpoint was set at a line with a def statement and the function
521 # defined is called: don't break.
522 return False
523 return True
525 # Breakpoint set via function name.
527 if frame.f_code.co_name != b.funcname:
528 # It's not a function call, but rather execution of def statement.
529 return False
531 # We are in the right frame.
532 if not b.func_first_executable_line:
533 # The function is entered for the 1st time.
534 b.func_first_executable_line = frame.f_lineno
536 if b.func_first_executable_line != frame.f_lineno:
537 # But we are not at the first line number: don't break.
538 return False
539 return True
541 # Determines if there is an effective (active) breakpoint at this
542 # line of code. Returns breakpoint number or 0 if none
543 def effective(file, line, frame):
544 """Determine which breakpoint for this file:line is to be acted upon.
546 Called only if we know there is a bpt at this
547 location. Returns breakpoint that was triggered and a flag
548 that indicates if it is ok to delete a temporary bp.
551 possibles = Breakpoint.bplist[file,line]
552 for i in range(0, len(possibles)):
553 b = possibles[i]
554 if b.enabled == 0:
555 continue
556 if not checkfuncname(b, frame):
557 continue
558 # Count every hit when bp is enabled
559 b.hits = b.hits + 1
560 if not b.cond:
561 # If unconditional, and ignoring,
562 # go on to next, else break
563 if b.ignore > 0:
564 b.ignore = b.ignore -1
565 continue
566 else:
567 # breakpoint and marker that's ok
568 # to delete if temporary
569 return (b,1)
570 else:
571 # Conditional bp.
572 # Ignore count applies only to those bpt hits where the
573 # condition evaluates to true.
574 try:
575 val = eval(b.cond, frame.f_globals,
576 frame.f_locals)
577 if val:
578 if b.ignore > 0:
579 b.ignore = b.ignore -1
580 # continue
581 else:
582 return (b,1)
583 # else:
584 # continue
585 except:
586 # if eval fails, most conservative
587 # thing is to stop on breakpoint
588 # regardless of ignore count.
589 # Don't delete temporary,
590 # as another hint to user.
591 return (b,0)
592 return (None, None)
594 # -------------------- testing --------------------
596 class Tdb(Bdb):
597 def user_call(self, frame, args):
598 name = frame.f_code.co_name
599 if not name: name = '???'
600 print('+++ call', name, args)
601 def user_line(self, frame):
602 import linecache
603 name = frame.f_code.co_name
604 if not name: name = '???'
605 fn = self.canonic(frame.f_code.co_filename)
606 line = linecache.getline(fn, frame.f_lineno, frame.f_globals)
607 print('+++', fn, frame.f_lineno, name, ':', line.strip())
608 def user_return(self, frame, retval):
609 print('+++ return', retval)
610 def user_exception(self, frame, exc_stuff):
611 print('+++ exception', exc_stuff)
612 self.set_continue()
614 def foo(n):
615 print('foo(', n, ')')
616 x = bar(n*10)
617 print('bar returned', x)
619 def bar(a):
620 print('bar(', a, ')')
621 return a/2
623 def test():
624 t = Tdb()
625 t.run('import bdb; bdb.foo(10)')
627 # end