/Lib/bdb.py

http://unladen-swallow.googlecode.com/ · Python · 613 lines · 414 code · 79 blank · 120 comment · 122 complexity · dee8cd881182661611bfc62dce141e8b MD5 · raw file

  1. """Debugger basics"""
  2. import sys
  3. import os
  4. import types
  5. __all__ = ["BdbQuit","Bdb","Breakpoint"]
  6. class BdbQuit(Exception):
  7. """Exception to give up completely"""
  8. class Bdb:
  9. """Generic Python debugger base class.
  10. This class takes care of details of the trace facility;
  11. a derived class should implement user interaction.
  12. The standard debugger class (pdb.Pdb) is an example.
  13. """
  14. def __init__(self):
  15. self.breaks = {}
  16. self.fncache = {}
  17. def canonic(self, filename):
  18. if filename == "<" + filename[1:-1] + ">":
  19. return filename
  20. canonic = self.fncache.get(filename)
  21. if not canonic:
  22. canonic = os.path.abspath(filename)
  23. canonic = os.path.normcase(canonic)
  24. self.fncache[filename] = canonic
  25. return canonic
  26. def reset(self):
  27. import linecache
  28. linecache.checkcache()
  29. self.botframe = None
  30. self._set_stopinfo(None, None)
  31. def trace_dispatch(self, frame, event, arg):
  32. if self.quitting:
  33. return # None
  34. if event == 'line':
  35. return self.dispatch_line(frame)
  36. if event == 'call':
  37. return self.dispatch_call(frame, arg)
  38. if event == 'return':
  39. return self.dispatch_return(frame, arg)
  40. if event == 'exception':
  41. return self.dispatch_exception(frame, arg)
  42. if event == 'c_call':
  43. return self.trace_dispatch
  44. if event == 'c_exception':
  45. return self.trace_dispatch
  46. if event == 'c_return':
  47. return self.trace_dispatch
  48. print 'bdb.Bdb.dispatch: unknown debugging event:', repr(event)
  49. return self.trace_dispatch
  50. def dispatch_line(self, frame):
  51. if self.stop_here(frame) or self.break_here(frame):
  52. self.user_line(frame)
  53. if self.quitting: raise BdbQuit
  54. return self.trace_dispatch
  55. def dispatch_call(self, frame, arg):
  56. # XXX 'arg' is no longer used
  57. if self.botframe is None:
  58. # First call of dispatch since reset()
  59. self.botframe = frame.f_back # (CT) Note that this may also be None!
  60. return self.trace_dispatch
  61. if not (self.stop_here(frame) or self.break_anywhere(frame)):
  62. # No need to trace this function
  63. return # None
  64. self.user_call(frame, arg)
  65. if self.quitting: raise BdbQuit
  66. return self.trace_dispatch
  67. def dispatch_return(self, frame, arg):
  68. if self.stop_here(frame) or frame == self.returnframe:
  69. self.user_return(frame, arg)
  70. if self.quitting: raise BdbQuit
  71. return self.trace_dispatch
  72. def dispatch_exception(self, frame, arg):
  73. if self.stop_here(frame):
  74. self.user_exception(frame, arg)
  75. if self.quitting: raise BdbQuit
  76. return self.trace_dispatch
  77. # Normally derived classes don't override the following
  78. # methods, but they may if they want to redefine the
  79. # definition of stopping and breakpoints.
  80. def stop_here(self, frame):
  81. # (CT) stopframe may now also be None, see dispatch_call.
  82. # (CT) the former test for None is therefore removed from here.
  83. if frame is self.stopframe:
  84. return frame.f_lineno >= self.stoplineno
  85. while frame is not None and frame is not self.stopframe:
  86. if frame is self.botframe:
  87. return True
  88. frame = frame.f_back
  89. return False
  90. def break_here(self, frame):
  91. filename = self.canonic(frame.f_code.co_filename)
  92. if not filename in self.breaks:
  93. return False
  94. lineno = frame.f_lineno
  95. if not lineno in self.breaks[filename]:
  96. # The line itself has no breakpoint, but maybe the line is the
  97. # first line of a function with breakpoint set by function name.
  98. lineno = frame.f_code.co_firstlineno
  99. if not lineno in self.breaks[filename]:
  100. return False
  101. # flag says ok to delete temp. bp
  102. (bp, flag) = effective(filename, lineno, frame)
  103. if bp:
  104. self.currentbp = bp.number
  105. if (flag and bp.temporary):
  106. self.do_clear(str(bp.number))
  107. return True
  108. else:
  109. return False
  110. def do_clear(self, arg):
  111. raise NotImplementedError, "subclass of bdb must implement do_clear()"
  112. def break_anywhere(self, frame):
  113. return self.canonic(frame.f_code.co_filename) in self.breaks
  114. # Derived classes should override the user_* methods
  115. # to gain control.
  116. def user_call(self, frame, argument_list):
  117. """This method is called when there is the remote possibility
  118. that we ever need to stop in this function."""
  119. pass
  120. def user_line(self, frame):
  121. """This method is called when we stop or break at this line."""
  122. pass
  123. def user_return(self, frame, return_value):
  124. """This method is called when a return trap is set here."""
  125. pass
  126. def user_exception(self, frame, exc_info):
  127. exc_type, exc_value, exc_traceback = exc_info
  128. """This method is called if an exception occurs,
  129. but only if we are to stop at or just below this level."""
  130. pass
  131. def _set_stopinfo(self, stopframe, returnframe, stoplineno=-1):
  132. self.stopframe = stopframe
  133. self.returnframe = returnframe
  134. self.quitting = 0
  135. self.stoplineno = stoplineno
  136. # Derived classes and clients can call the following methods
  137. # to affect the stepping state.
  138. def set_until(self, frame): #the name "until" is borrowed from gdb
  139. """Stop when the line with the line no greater than the current one is
  140. reached or when returning from current frame"""
  141. self._set_stopinfo(frame, frame, frame.f_lineno+1)
  142. def set_step(self):
  143. """Stop after one line of code."""
  144. self._set_stopinfo(None,None)
  145. def set_next(self, frame):
  146. """Stop on the next line in or below the given frame."""
  147. self._set_stopinfo(frame, None)
  148. def set_return(self, frame):
  149. """Stop when returning from the given frame."""
  150. self._set_stopinfo(frame.f_back, frame)
  151. def set_trace(self, frame=None):
  152. """Start debugging from `frame`.
  153. If frame is not specified, debugging starts from caller's frame.
  154. """
  155. if frame is None:
  156. frame = sys._getframe().f_back
  157. self.reset()
  158. while frame:
  159. frame.f_trace = self.trace_dispatch
  160. self.botframe = frame
  161. frame = frame.f_back
  162. self.set_step()
  163. sys.settrace(self.trace_dispatch)
  164. def set_continue(self):
  165. # Don't stop except at breakpoints or when finished
  166. self._set_stopinfo(self.botframe, None)
  167. if not self.breaks:
  168. # no breakpoints; run without debugger overhead
  169. sys.settrace(None)
  170. frame = sys._getframe().f_back
  171. while frame and frame is not self.botframe:
  172. del frame.f_trace
  173. frame = frame.f_back
  174. def set_quit(self):
  175. self.stopframe = self.botframe
  176. self.returnframe = None
  177. self.quitting = 1
  178. sys.settrace(None)
  179. # Derived classes and clients can call the following methods
  180. # to manipulate breakpoints. These methods return an
  181. # error message is something went wrong, None if all is well.
  182. # Set_break prints out the breakpoint line and file:lineno.
  183. # Call self.get_*break*() to see the breakpoints or better
  184. # for bp in Breakpoint.bpbynumber: if bp: bp.bpprint().
  185. def set_break(self, filename, lineno, temporary=0, cond = None,
  186. funcname=None):
  187. filename = self.canonic(filename)
  188. import linecache # Import as late as possible
  189. line = linecache.getline(filename, lineno)
  190. if not line:
  191. return 'Line %s:%d does not exist' % (filename,
  192. lineno)
  193. if not filename in self.breaks:
  194. self.breaks[filename] = []
  195. list = self.breaks[filename]
  196. if not lineno in list:
  197. list.append(lineno)
  198. bp = Breakpoint(filename, lineno, temporary, cond, funcname)
  199. def clear_break(self, filename, lineno):
  200. filename = self.canonic(filename)
  201. if not filename in self.breaks:
  202. return 'There are no breakpoints in %s' % filename
  203. if lineno not in self.breaks[filename]:
  204. return 'There is no breakpoint at %s:%d' % (filename,
  205. lineno)
  206. # If there's only one bp in the list for that file,line
  207. # pair, then remove the breaks entry
  208. for bp in Breakpoint.bplist[filename, lineno][:]:
  209. bp.deleteMe()
  210. if not Breakpoint.bplist.has_key((filename, lineno)):
  211. self.breaks[filename].remove(lineno)
  212. if not self.breaks[filename]:
  213. del self.breaks[filename]
  214. def clear_bpbynumber(self, arg):
  215. try:
  216. number = int(arg)
  217. except:
  218. return 'Non-numeric breakpoint number (%s)' % arg
  219. try:
  220. bp = Breakpoint.bpbynumber[number]
  221. except IndexError:
  222. return 'Breakpoint number (%d) out of range' % number
  223. if not bp:
  224. return 'Breakpoint (%d) already deleted' % number
  225. self.clear_break(bp.file, bp.line)
  226. def clear_all_file_breaks(self, filename):
  227. filename = self.canonic(filename)
  228. if not filename in self.breaks:
  229. return 'There are no breakpoints in %s' % filename
  230. for line in self.breaks[filename]:
  231. blist = Breakpoint.bplist[filename, line]
  232. for bp in blist:
  233. bp.deleteMe()
  234. del self.breaks[filename]
  235. def clear_all_breaks(self):
  236. if not self.breaks:
  237. return 'There are no breakpoints'
  238. for bp in Breakpoint.bpbynumber:
  239. if bp:
  240. bp.deleteMe()
  241. self.breaks = {}
  242. def get_break(self, filename, lineno):
  243. filename = self.canonic(filename)
  244. return filename in self.breaks and \
  245. lineno in self.breaks[filename]
  246. def get_breaks(self, filename, lineno):
  247. filename = self.canonic(filename)
  248. return filename in self.breaks and \
  249. lineno in self.breaks[filename] and \
  250. Breakpoint.bplist[filename, lineno] or []
  251. def get_file_breaks(self, filename):
  252. filename = self.canonic(filename)
  253. if filename in self.breaks:
  254. return self.breaks[filename]
  255. else:
  256. return []
  257. def get_all_breaks(self):
  258. return self.breaks
  259. # Derived classes and clients can call the following method
  260. # to get a data structure representing a stack trace.
  261. def get_stack(self, f, t):
  262. stack = []
  263. if t and t.tb_frame is f:
  264. t = t.tb_next
  265. while f is not None:
  266. stack.append((f, f.f_lineno))
  267. if f is self.botframe:
  268. break
  269. f = f.f_back
  270. stack.reverse()
  271. i = max(0, len(stack) - 1)
  272. while t is not None:
  273. stack.append((t.tb_frame, t.tb_lineno))
  274. t = t.tb_next
  275. if f is None:
  276. i = max(0, len(stack) - 1)
  277. return stack, i
  278. #
  279. def format_stack_entry(self, frame_lineno, lprefix=': '):
  280. import linecache, repr
  281. frame, lineno = frame_lineno
  282. filename = self.canonic(frame.f_code.co_filename)
  283. s = '%s(%r)' % (filename, lineno)
  284. if frame.f_code.co_name:
  285. s = s + frame.f_code.co_name
  286. else:
  287. s = s + "<lambda>"
  288. if '__args__' in frame.f_locals:
  289. args = frame.f_locals['__args__']
  290. else:
  291. args = None
  292. if args:
  293. s = s + repr.repr(args)
  294. else:
  295. s = s + '()'
  296. if '__return__' in frame.f_locals:
  297. rv = frame.f_locals['__return__']
  298. s = s + '->'
  299. s = s + repr.repr(rv)
  300. line = linecache.getline(filename, lineno, frame.f_globals)
  301. if line: s = s + lprefix + line.strip()
  302. return s
  303. # The following two methods can be called by clients to use
  304. # a debugger to debug a statement, given as a string.
  305. def run(self, cmd, globals=None, locals=None):
  306. if globals is None:
  307. import __main__
  308. globals = __main__.__dict__
  309. if locals is None:
  310. locals = globals
  311. self.reset()
  312. sys.settrace(self.trace_dispatch)
  313. if not isinstance(cmd, types.CodeType):
  314. cmd = cmd+'\n'
  315. try:
  316. exec cmd in globals, locals
  317. except BdbQuit:
  318. pass
  319. finally:
  320. self.quitting = 1
  321. sys.settrace(None)
  322. def runeval(self, expr, globals=None, locals=None):
  323. if globals is None:
  324. import __main__
  325. globals = __main__.__dict__
  326. if locals is None:
  327. locals = globals
  328. self.reset()
  329. sys.settrace(self.trace_dispatch)
  330. if not isinstance(expr, types.CodeType):
  331. expr = expr+'\n'
  332. try:
  333. return eval(expr, globals, locals)
  334. except BdbQuit:
  335. pass
  336. finally:
  337. self.quitting = 1
  338. sys.settrace(None)
  339. def runctx(self, cmd, globals, locals):
  340. # B/W compatibility
  341. self.run(cmd, globals, locals)
  342. # This method is more useful to debug a single function call.
  343. def runcall(self, func, *args, **kwds):
  344. self.reset()
  345. sys.settrace(self.trace_dispatch)
  346. res = None
  347. try:
  348. res = func(*args, **kwds)
  349. except BdbQuit:
  350. pass
  351. finally:
  352. self.quitting = 1
  353. sys.settrace(None)
  354. return res
  355. def set_trace():
  356. Bdb().set_trace()
  357. class Breakpoint:
  358. """Breakpoint class
  359. Implements temporary breakpoints, ignore counts, disabling and
  360. (re)-enabling, and conditionals.
  361. Breakpoints are indexed by number through bpbynumber and by
  362. the file,line tuple using bplist. The former points to a
  363. single instance of class Breakpoint. The latter points to a
  364. list of such instances since there may be more than one
  365. breakpoint per line.
  366. """
  367. # XXX Keeping state in the class is a mistake -- this means
  368. # you cannot have more than one active Bdb instance.
  369. next = 1 # Next bp to be assigned
  370. bplist = {} # indexed by (file, lineno) tuple
  371. bpbynumber = [None] # Each entry is None or an instance of Bpt
  372. # index 0 is unused, except for marking an
  373. # effective break .... see effective()
  374. def __init__(self, file, line, temporary=0, cond=None, funcname=None):
  375. self.funcname = funcname
  376. # Needed if funcname is not None.
  377. self.func_first_executable_line = None
  378. self.file = file # This better be in canonical form!
  379. self.line = line
  380. self.temporary = temporary
  381. self.cond = cond
  382. self.enabled = 1
  383. self.ignore = 0
  384. self.hits = 0
  385. self.number = Breakpoint.next
  386. Breakpoint.next = Breakpoint.next + 1
  387. # Build the two lists
  388. self.bpbynumber.append(self)
  389. if self.bplist.has_key((file, line)):
  390. self.bplist[file, line].append(self)
  391. else:
  392. self.bplist[file, line] = [self]
  393. def deleteMe(self):
  394. index = (self.file, self.line)
  395. self.bpbynumber[self.number] = None # No longer in list
  396. self.bplist[index].remove(self)
  397. if not self.bplist[index]:
  398. # No more bp for this f:l combo
  399. del self.bplist[index]
  400. def enable(self):
  401. self.enabled = 1
  402. def disable(self):
  403. self.enabled = 0
  404. def bpprint(self, out=None):
  405. if out is None:
  406. out = sys.stdout
  407. if self.temporary:
  408. disp = 'del '
  409. else:
  410. disp = 'keep '
  411. if self.enabled:
  412. disp = disp + 'yes '
  413. else:
  414. disp = disp + 'no '
  415. print >>out, '%-4dbreakpoint %s at %s:%d' % (self.number, disp,
  416. self.file, self.line)
  417. if self.cond:
  418. print >>out, '\tstop only if %s' % (self.cond,)
  419. if self.ignore:
  420. print >>out, '\tignore next %d hits' % (self.ignore)
  421. if (self.hits):
  422. if (self.hits > 1): ss = 's'
  423. else: ss = ''
  424. print >>out, ('\tbreakpoint already hit %d time%s' %
  425. (self.hits, ss))
  426. # -----------end of Breakpoint class----------
  427. def checkfuncname(b, frame):
  428. """Check whether we should break here because of `b.funcname`."""
  429. if not b.funcname:
  430. # Breakpoint was set via line number.
  431. if b.line != frame.f_lineno:
  432. # Breakpoint was set at a line with a def statement and the function
  433. # defined is called: don't break.
  434. return False
  435. return True
  436. # Breakpoint set via function name.
  437. if frame.f_code.co_name != b.funcname:
  438. # It's not a function call, but rather execution of def statement.
  439. return False
  440. # We are in the right frame.
  441. if not b.func_first_executable_line:
  442. # The function is entered for the 1st time.
  443. b.func_first_executable_line = frame.f_lineno
  444. if b.func_first_executable_line != frame.f_lineno:
  445. # But we are not at the first line number: don't break.
  446. return False
  447. return True
  448. # Determines if there is an effective (active) breakpoint at this
  449. # line of code. Returns breakpoint number or 0 if none
  450. def effective(file, line, frame):
  451. """Determine which breakpoint for this file:line is to be acted upon.
  452. Called only if we know there is a bpt at this
  453. location. Returns breakpoint that was triggered and a flag
  454. that indicates if it is ok to delete a temporary bp.
  455. """
  456. possibles = Breakpoint.bplist[file,line]
  457. for i in range(0, len(possibles)):
  458. b = possibles[i]
  459. if b.enabled == 0:
  460. continue
  461. if not checkfuncname(b, frame):
  462. continue
  463. # Count every hit when bp is enabled
  464. b.hits = b.hits + 1
  465. if not b.cond:
  466. # If unconditional, and ignoring,
  467. # go on to next, else break
  468. if b.ignore > 0:
  469. b.ignore = b.ignore -1
  470. continue
  471. else:
  472. # breakpoint and marker that's ok
  473. # to delete if temporary
  474. return (b,1)
  475. else:
  476. # Conditional bp.
  477. # Ignore count applies only to those bpt hits where the
  478. # condition evaluates to true.
  479. try:
  480. val = eval(b.cond, frame.f_globals,
  481. frame.f_locals)
  482. if val:
  483. if b.ignore > 0:
  484. b.ignore = b.ignore -1
  485. # continue
  486. else:
  487. return (b,1)
  488. # else:
  489. # continue
  490. except:
  491. # if eval fails, most conservative
  492. # thing is to stop on breakpoint
  493. # regardless of ignore count.
  494. # Don't delete temporary,
  495. # as another hint to user.
  496. return (b,0)
  497. return (None, None)
  498. # -------------------- testing --------------------
  499. class Tdb(Bdb):
  500. def user_call(self, frame, args):
  501. name = frame.f_code.co_name
  502. if not name: name = '???'
  503. print '+++ call', name, args
  504. def user_line(self, frame):
  505. import linecache
  506. name = frame.f_code.co_name
  507. if not name: name = '???'
  508. fn = self.canonic(frame.f_code.co_filename)
  509. line = linecache.getline(fn, frame.f_lineno, frame.f_globals)
  510. print '+++', fn, frame.f_lineno, name, ':', line.strip()
  511. def user_return(self, frame, retval):
  512. print '+++ return', retval
  513. def user_exception(self, frame, exc_stuff):
  514. print '+++ exception', exc_stuff
  515. self.set_continue()
  516. def foo(n):
  517. print 'foo(', n, ')'
  518. x = bar(n*10)
  519. print 'bar returned', x
  520. def bar(a):
  521. print 'bar(', a, ')'
  522. return a/2
  523. def test():
  524. t = Tdb()
  525. t.run('import bdb; bdb.foo(10)')
  526. # end