PageRenderTime 42ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/pydbgr/lib/stack.py

http://pydbgr.googlecode.com/
Python | 253 lines | 191 code | 21 blank | 41 comment | 38 complexity | 460fed0f349a62375650244b81311c5d MD5 | raw file
Possible License(s): GPL-3.0
  1. # -*- coding: utf-8 -*-
  2. # Copyright (C) 2008, 2009, 2010 Rocky Bernstein <rocky@gnu.org>
  3. #
  4. # This program is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation, either version 3 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. """ Functions for working with Python frames"""
  17. import re, types
  18. from import_relative import import_relative
  19. Mbytecode = import_relative('bytecode', top_name='pydbgr')
  20. Mprint = import_relative('print', top_name='pydbgr')
  21. def count_frames(frame, count_start=0):
  22. "Return a count of the number of frames"
  23. count = -count_start
  24. while frame:
  25. count += 1
  26. frame = frame.f_back
  27. return count
  28. import repr as Mrepr
  29. import inspect
  30. _re_pseudo_file = re.compile(r'^<.+>')
  31. def format_stack_entry(dbg_obj, frame_lineno, lprefix=': ',
  32. include_location=True):
  33. """Format and return a stack entry gdb-style.
  34. Note: lprefix is not used. It is kept for compatibility.
  35. """
  36. frame, lineno = frame_lineno
  37. filename = frame2file(dbg_obj.core, frame)
  38. s = ''
  39. if frame.f_code.co_name:
  40. s = frame.f_code.co_name
  41. else:
  42. s = "<lambda>"
  43. pass
  44. args, varargs, varkw, local_vars = inspect.getargvalues(frame)
  45. if '<module>' == s and ([], None, None,) == (args, varargs, varkw,):
  46. is_module = True
  47. if is_exec_stmt(frame):
  48. s += ' exec()'
  49. else:
  50. fn_name = get_call_function_name(frame)
  51. if fn_name: s += ' %s()' % fn_name
  52. pass
  53. else:
  54. is_module = False
  55. parms=inspect.formatargvalues(args, varargs, varkw, local_vars)
  56. maxargstrsize = dbg_obj.settings['maxargstrsize']
  57. if len(parms) >= maxargstrsize:
  58. parms = "%s...)" % parms[0:maxargstrsize]
  59. pass
  60. s += parms
  61. pass
  62. # Note: ddd can't handle wrapped stack entries (yet).
  63. # The 35 is hoaky though. FIXME.
  64. if len(s) >= 35: s += "\n "
  65. if '__return__' in frame.f_locals:
  66. rv = frame.f_locals['__return__']
  67. s += '->'
  68. s += Mrepr.repr(rv)
  69. pass
  70. if include_location:
  71. is_pseudo_file = _re_pseudo_file.match(filename)
  72. add_quotes_around_file = not is_pseudo_file
  73. if is_module:
  74. if not is_exec_stmt(frame) and not is_pseudo_file:
  75. s += ' file'
  76. elif s == '?()':
  77. if is_exec_stmt(frame):
  78. s = 'in exec'
  79. # exec_str = get_exec_string(frame.f_back)
  80. # if exec_str != None:
  81. # filename = exec_str
  82. # add_quotes_around_file = False
  83. # pass
  84. # pass
  85. elif not is_pseudo_file:
  86. s = 'in file'
  87. pass
  88. pass
  89. elif not is_pseudo_file:
  90. s += ' called from file'
  91. pass
  92. if add_quotes_around_file: filename = "'%s'" % filename
  93. s += " %s at line %r" % (filename, lineno)
  94. return s
  95. def frame2file(core_obj, frame):
  96. return core_obj.filename(core_obj.canonic_filename(frame))
  97. def is_exec_stmt(frame):
  98. """Return True if we are looking at an exec statement"""
  99. return hasattr(frame, 'f_back') and frame.f_back is not None and \
  100. Mbytecode.op_at_frame(frame.f_back)=='EXEC_STMT'
  101. import dis
  102. def get_call_function_name(frame):
  103. """If f_back is looking at a call function, return
  104. the name for it. Otherwise return None"""
  105. f_back = frame.f_back
  106. if not f_back: return None
  107. if 'CALL_FUNCTION' != Mbytecode.op_at_frame(f_back): return None
  108. co = f_back.f_code
  109. code = co.co_code
  110. # labels = dis.findlabels(code)
  111. linestarts = dict(dis.findlinestarts(co))
  112. inst = f_back.f_lasti
  113. while inst >= 0:
  114. # c = code[inst]
  115. # op = ord(c)
  116. if inst in linestarts:
  117. inst += 1
  118. oparg = ord(code[inst]) + (ord(code[inst+1]) << 8)
  119. return co.co_names[oparg]
  120. inst -= 1
  121. pass
  122. return None
  123. def print_stack_entry(proc_obj, i_stack):
  124. frame_lineno = proc_obj.stack[len(proc_obj.stack)-i_stack-1]
  125. frame, lineno = frame_lineno
  126. if frame is proc_obj.curframe:
  127. proc_obj.intf[-1].msg_nocr('->')
  128. else:
  129. proc_obj.intf[-1].msg_nocr('##')
  130. proc_obj.intf[-1].msg("%d %s" %
  131. (i_stack, format_stack_entry(proc_obj.debugger, frame_lineno)))
  132. def print_stack_trace(proc_obj, count=None):
  133. "Print count entries of the stack trace"
  134. if count is None:
  135. n=len(proc_obj.stack)
  136. else:
  137. n=min(len(proc_obj.stack), count)
  138. try:
  139. for i in range(n):
  140. print_stack_entry(proc_obj, i)
  141. except KeyboardInterrupt:
  142. pass
  143. return
  144. def print_dict(s, obj, title):
  145. if hasattr(obj, "__dict__"):
  146. d=obj.__dict__
  147. if type(d) == types.DictType or type(d) == types.DictProxyType:
  148. keys = d.keys()
  149. if len(keys) == 0:
  150. s += "\n No %s" % title
  151. else:
  152. s += "\n %s:\n" % title
  153. keys.sort()
  154. for key in keys:
  155. s+=" '%s':\t%s\n" % (key, d[key])
  156. pass
  157. pass
  158. pass
  159. return s
  160. def eval_print_obj(arg, frame, format=None, short=False):
  161. """Return a string representation of an object """
  162. try:
  163. if not frame:
  164. # ?? Should we have set up a dummy globals
  165. # to have persistence?
  166. val = eval(arg, None, None)
  167. else:
  168. val = eval(arg, frame.f_globals, frame.f_locals)
  169. pass
  170. except:
  171. return 'No symbol "' + arg + '" in current context.'
  172. return print_obj(arg, val, format, short)
  173. def print_obj(arg, val, format=None, short=False):
  174. """Return a string representation of an object """
  175. what = arg
  176. if format:
  177. what = format + ' ' + arg
  178. val = Mprint.printf(val, format)
  179. pass
  180. s = '%s = %s' % (what, val)
  181. if not short:
  182. s += '\n type = %s' % type(val)
  183. # Try to list the members of a class.
  184. # Not sure if this is correct or the
  185. # best way to do.
  186. s = print_dict(s, val, "object variables")
  187. if hasattr(val, "__class__"):
  188. s = print_dict(s, val.__class__, "class variables")
  189. pass
  190. pass
  191. return s
  192. # Demo stuff above
  193. if __name__=='__main__':
  194. class MockDebuggerCore():
  195. def canonic_filename(self, frame):
  196. return frame.f_code.co_filename
  197. def filename(self, name):
  198. return name
  199. pass
  200. class MockDebugger():
  201. def __init__(self):
  202. self.core = MockDebuggerCore()
  203. self.settings = {
  204. 'maxargstrsize': 80
  205. }
  206. pass
  207. pass
  208. frame = inspect.currentframe()
  209. m = MockDebugger()
  210. print format_stack_entry(m, (frame, 10,))
  211. print "frame count: ", count_frames(frame)
  212. print "frame count: ", count_frames(frame.f_back)
  213. print "frame count: ", count_frames(frame, 1)
  214. print "def statement: x=5?: ", Mbytecode.is_def_stmt('x=5', frame)
  215. # Not a "def" statement because frame is wrong spot
  216. print Mbytecode.is_def_stmt('def foo():', frame)
  217. def sqr(x): x * x
  218. def fn(x):
  219. frame = inspect.currentframe()
  220. print get_call_function_name(frame)
  221. return
  222. print '=' * 30
  223. eval('fn(5)')
  224. print '=' * 30
  225. print print_obj('fn', fn)
  226. print '=' * 30
  227. print print_obj('len', len)
  228. print '=' * 30
  229. print print_obj('MockDebugger', MockDebugger)
  230. pass