StackViewer.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. import os
  2. import sys
  3. import linecache
  4. import re
  5. import Tkinter as tk
  6. from idlelib.TreeWidget import TreeNode, TreeItem, ScrolledCanvas
  7. from idlelib.ObjectBrowser import ObjectTreeItem, make_objecttreeitem
  8. from idlelib.PyShell import PyShellFileList
  9. def StackBrowser(root, flist=None, tb=None, top=None):
  10. if top is None:
  11. top = tk.Toplevel(root)
  12. sc = ScrolledCanvas(top, bg="white", highlightthickness=0)
  13. sc.frame.pack(expand=1, fill="both")
  14. item = StackTreeItem(flist, tb)
  15. node = TreeNode(sc.canvas, None, item)
  16. node.expand()
  17. class StackTreeItem(TreeItem):
  18. def __init__(self, flist=None, tb=None):
  19. self.flist = flist
  20. self.stack = self.get_stack(tb)
  21. self.text = self.get_exception()
  22. def get_stack(self, tb):
  23. if tb is None:
  24. tb = sys.last_traceback
  25. stack = []
  26. if tb and tb.tb_frame is None:
  27. tb = tb.tb_next
  28. while tb is not None:
  29. stack.append((tb.tb_frame, tb.tb_lineno))
  30. tb = tb.tb_next
  31. return stack
  32. def get_exception(self):
  33. type = sys.last_type
  34. value = sys.last_value
  35. if hasattr(type, "__name__"):
  36. type = type.__name__
  37. s = str(type)
  38. if value is not None:
  39. s = s + ": " + str(value)
  40. return s
  41. def GetText(self):
  42. return self.text
  43. def GetSubList(self):
  44. sublist = []
  45. for info in self.stack:
  46. item = FrameTreeItem(info, self.flist)
  47. sublist.append(item)
  48. return sublist
  49. class FrameTreeItem(TreeItem):
  50. def __init__(self, info, flist):
  51. self.info = info
  52. self.flist = flist
  53. def GetText(self):
  54. frame, lineno = self.info
  55. try:
  56. modname = frame.f_globals["__name__"]
  57. except:
  58. modname = "?"
  59. code = frame.f_code
  60. filename = code.co_filename
  61. funcname = code.co_name
  62. sourceline = linecache.getline(filename, lineno)
  63. sourceline = sourceline.strip()
  64. if funcname in ("?", "", None):
  65. item = "%s, line %d: %s" % (modname, lineno, sourceline)
  66. else:
  67. item = "%s.%s(...), line %d: %s" % (modname, funcname,
  68. lineno, sourceline)
  69. return item
  70. def GetSubList(self):
  71. frame, lineno = self.info
  72. sublist = []
  73. if frame.f_globals is not frame.f_locals:
  74. item = VariablesTreeItem("<locals>", frame.f_locals, self.flist)
  75. sublist.append(item)
  76. item = VariablesTreeItem("<globals>", frame.f_globals, self.flist)
  77. sublist.append(item)
  78. return sublist
  79. def OnDoubleClick(self):
  80. if self.flist:
  81. frame, lineno = self.info
  82. filename = frame.f_code.co_filename
  83. if os.path.isfile(filename):
  84. self.flist.gotofileline(filename, lineno)
  85. class VariablesTreeItem(ObjectTreeItem):
  86. def GetText(self):
  87. return self.labeltext
  88. def GetLabelText(self):
  89. return None
  90. def IsExpandable(self):
  91. return len(self.object) > 0
  92. def GetSubList(self):
  93. sublist = []
  94. for key in self.object.keys():
  95. try:
  96. value = self.object[key]
  97. except KeyError:
  98. continue
  99. def setfunction(value, key=key, object=self.object):
  100. object[key] = value
  101. item = make_objecttreeitem(key + " =", value, setfunction)
  102. sublist.append(item)
  103. return sublist
  104. def keys(self): # unused, left for possible 3rd party use
  105. return self.object.keys()
  106. def _stack_viewer(parent): # htest #
  107. root = tk.Tk()
  108. root.title("Test StackViewer")
  109. width, height, x, y = list(map(int, re.split('[x+]', parent.geometry())))
  110. root.geometry("+%d+%d"%(x, y + 150))
  111. flist = PyShellFileList(root)
  112. try: # to obtain a traceback object
  113. intentional_name_error
  114. except NameError:
  115. exc_type, exc_value, exc_tb = sys.exc_info()
  116. # inject stack trace to sys
  117. sys.last_type = exc_type
  118. sys.last_value = exc_value
  119. sys.last_traceback = exc_tb
  120. StackBrowser(root, flist=flist, top=root, tb=exc_tb)
  121. # restore sys to original state
  122. del sys.last_type
  123. del sys.last_value
  124. del sys.last_traceback
  125. if __name__ == '__main__':
  126. from idlelib.idle_test.htest import run
  127. run(_stack_viewer)