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