stackviewer.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import linecache
  2. import os
  3. import tkinter as tk
  4. from idlelib.debugobj import ObjectTreeItem, make_objecttreeitem
  5. from idlelib.tree import TreeNode, TreeItem, ScrolledCanvas
  6. def StackBrowser(root, exc, flist=None, top=None):
  7. global sc, item, node # For testing.
  8. if top is None:
  9. top = tk.Toplevel(root)
  10. sc = ScrolledCanvas(top, bg="white", highlightthickness=0)
  11. sc.frame.pack(expand=1, fill="both")
  12. item = StackTreeItem(exc, flist)
  13. node = TreeNode(sc.canvas, None, item)
  14. node.expand()
  15. class StackTreeItem(TreeItem):
  16. def __init__(self, exc, flist=None):
  17. self.flist = flist
  18. self.stack = self.get_stack(None if exc is None else exc.__traceback__)
  19. self.text = f"{type(exc).__name__}: {str(exc)}"
  20. def get_stack(self, tb):
  21. stack = []
  22. if tb and tb.tb_frame is None:
  23. tb = tb.tb_next
  24. while tb is not None:
  25. stack.append((tb.tb_frame, tb.tb_lineno))
  26. tb = tb.tb_next
  27. return stack
  28. def GetText(self): # Titlecase names are overrides.
  29. return self.text
  30. def GetSubList(self):
  31. sublist = []
  32. for info in self.stack:
  33. item = FrameTreeItem(info, self.flist)
  34. sublist.append(item)
  35. return sublist
  36. class FrameTreeItem(TreeItem):
  37. def __init__(self, info, flist):
  38. self.info = info
  39. self.flist = flist
  40. def GetText(self):
  41. frame, lineno = self.info
  42. try:
  43. modname = frame.f_globals["__name__"]
  44. except:
  45. modname = "?"
  46. code = frame.f_code
  47. filename = code.co_filename
  48. funcname = code.co_name
  49. sourceline = linecache.getline(filename, lineno)
  50. sourceline = sourceline.strip()
  51. if funcname in ("?", "", None):
  52. item = "%s, line %d: %s" % (modname, lineno, sourceline)
  53. else:
  54. item = "%s.%s(...), line %d: %s" % (modname, funcname,
  55. lineno, sourceline)
  56. return item
  57. def GetSubList(self):
  58. frame, lineno = self.info
  59. sublist = []
  60. if frame.f_globals is not frame.f_locals:
  61. item = VariablesTreeItem("<locals>", frame.f_locals, self.flist)
  62. sublist.append(item)
  63. item = VariablesTreeItem("<globals>", frame.f_globals, self.flist)
  64. sublist.append(item)
  65. return sublist
  66. def OnDoubleClick(self):
  67. if self.flist:
  68. frame, lineno = self.info
  69. filename = frame.f_code.co_filename
  70. if os.path.isfile(filename):
  71. self.flist.gotofileline(filename, lineno)
  72. class VariablesTreeItem(ObjectTreeItem):
  73. def GetText(self):
  74. return self.labeltext
  75. def GetLabelText(self):
  76. return None
  77. def IsExpandable(self):
  78. return len(self.object) > 0
  79. def GetSubList(self):
  80. sublist = []
  81. for key in self.object.keys():
  82. try:
  83. value = self.object[key]
  84. except KeyError:
  85. continue
  86. def setfunction(value, key=key, object=self.object):
  87. object[key] = value
  88. item = make_objecttreeitem(key + " =", value, setfunction)
  89. sublist.append(item)
  90. return sublist
  91. def _stack_viewer(parent): # htest #
  92. from idlelib.pyshell import PyShellFileList
  93. top = tk.Toplevel(parent)
  94. top.title("Test StackViewer")
  95. x, y = map(int, parent.geometry().split('+')[1:])
  96. top.geometry("+%d+%d" % (x + 50, y + 175))
  97. flist = PyShellFileList(top)
  98. try: # to obtain a traceback object
  99. intentional_name_error
  100. except NameError as e:
  101. StackBrowser(top, e, flist=flist, top=top)
  102. if __name__ == '__main__':
  103. from unittest import main
  104. main('idlelib.idle_test.test_stackviewer', verbosity=2, exit=False)
  105. from idlelib.idle_test.htest import run
  106. run(_stack_viewer)