PageRenderTime 86ms CodeModel.GetById 4ms RepoModel.GetById 0ms app.codeStats 0ms

/lib-python/modified-2.7/idlelib/Debugger.py

https://bitbucket.org/dac_io/pypy
Python | 481 lines | 452 code | 15 blank | 14 comment | 25 complexity | 1a87f3e2f317a4cf6137715d7a5b95b1 MD5 | raw file
  1. import os
  2. import bdb
  3. import types
  4. from Tkinter import *
  5. from idlelib.WindowList import ListedToplevel
  6. from idlelib.ScrolledList import ScrolledList
  7. from idlelib import macosxSupport
  8. class Idb(bdb.Bdb):
  9. def __init__(self, gui):
  10. self.gui = gui
  11. bdb.Bdb.__init__(self)
  12. def user_line(self, frame):
  13. if self.in_rpc_code(frame):
  14. self.set_step()
  15. return
  16. message = self.__frame2message(frame)
  17. self.gui.interaction(message, frame)
  18. def user_exception(self, frame, info):
  19. if self.in_rpc_code(frame):
  20. self.set_step()
  21. return
  22. message = self.__frame2message(frame)
  23. self.gui.interaction(message, frame, info)
  24. def in_rpc_code(self, frame):
  25. if frame.f_code.co_filename.count('rpc.py'):
  26. return True
  27. else:
  28. prev_frame = frame.f_back
  29. if prev_frame.f_code.co_filename.count('Debugger.py'):
  30. # (that test will catch both Debugger.py and RemoteDebugger.py)
  31. return False
  32. return self.in_rpc_code(prev_frame)
  33. def __frame2message(self, frame):
  34. code = frame.f_code
  35. filename = code.co_filename
  36. lineno = frame.f_lineno
  37. basename = os.path.basename(filename)
  38. message = "%s:%s" % (basename, lineno)
  39. if code.co_name != "?":
  40. message = "%s: %s()" % (message, code.co_name)
  41. return message
  42. class Debugger:
  43. vstack = vsource = vlocals = vglobals = None
  44. def __init__(self, pyshell, idb=None):
  45. if idb is None:
  46. idb = Idb(self)
  47. self.pyshell = pyshell
  48. self.idb = idb
  49. self.frame = None
  50. self.make_gui()
  51. self.interacting = 0
  52. def run(self, *args):
  53. try:
  54. self.interacting = 1
  55. return self.idb.run(*args)
  56. finally:
  57. self.interacting = 0
  58. def close(self, event=None):
  59. if self.interacting:
  60. self.top.bell()
  61. return
  62. if self.stackviewer:
  63. self.stackviewer.close(); self.stackviewer = None
  64. # Clean up pyshell if user clicked debugger control close widget.
  65. # (Causes a harmless extra cycle through close_debugger() if user
  66. # toggled debugger from pyshell Debug menu)
  67. self.pyshell.close_debugger()
  68. # Now close the debugger control window....
  69. self.top.destroy()
  70. def make_gui(self):
  71. pyshell = self.pyshell
  72. self.flist = pyshell.flist
  73. self.root = root = pyshell.root
  74. self.top = top = ListedToplevel(root)
  75. self.top.wm_title("Debug Control")
  76. self.top.wm_iconname("Debug")
  77. top.wm_protocol("WM_DELETE_WINDOW", self.close)
  78. self.top.bind("<Escape>", self.close)
  79. #
  80. self.bframe = bframe = Frame(top)
  81. self.bframe.pack(anchor="w")
  82. self.buttons = bl = []
  83. #
  84. self.bcont = b = Button(bframe, text="Go", command=self.cont)
  85. bl.append(b)
  86. self.bstep = b = Button(bframe, text="Step", command=self.step)
  87. bl.append(b)
  88. self.bnext = b = Button(bframe, text="Over", command=self.next)
  89. bl.append(b)
  90. self.bret = b = Button(bframe, text="Out", command=self.ret)
  91. bl.append(b)
  92. self.bret = b = Button(bframe, text="Quit", command=self.quit)
  93. bl.append(b)
  94. #
  95. for b in bl:
  96. b.configure(state="disabled")
  97. b.pack(side="left")
  98. #
  99. self.cframe = cframe = Frame(bframe)
  100. self.cframe.pack(side="left")
  101. #
  102. if not self.vstack:
  103. self.__class__.vstack = BooleanVar(top)
  104. self.vstack.set(1)
  105. self.bstack = Checkbutton(cframe,
  106. text="Stack", command=self.show_stack, variable=self.vstack)
  107. self.bstack.grid(row=0, column=0)
  108. if not self.vsource:
  109. self.__class__.vsource = BooleanVar(top)
  110. self.bsource = Checkbutton(cframe,
  111. text="Source", command=self.show_source, variable=self.vsource)
  112. self.bsource.grid(row=0, column=1)
  113. if not self.vlocals:
  114. self.__class__.vlocals = BooleanVar(top)
  115. self.vlocals.set(1)
  116. self.blocals = Checkbutton(cframe,
  117. text="Locals", command=self.show_locals, variable=self.vlocals)
  118. self.blocals.grid(row=1, column=0)
  119. if not self.vglobals:
  120. self.__class__.vglobals = BooleanVar(top)
  121. self.bglobals = Checkbutton(cframe,
  122. text="Globals", command=self.show_globals, variable=self.vglobals)
  123. self.bglobals.grid(row=1, column=1)
  124. #
  125. self.status = Label(top, anchor="w")
  126. self.status.pack(anchor="w")
  127. self.error = Label(top, anchor="w")
  128. self.error.pack(anchor="w", fill="x")
  129. self.errorbg = self.error.cget("background")
  130. #
  131. self.fstack = Frame(top, height=1)
  132. self.fstack.pack(expand=1, fill="both")
  133. self.flocals = Frame(top)
  134. self.flocals.pack(expand=1, fill="both")
  135. self.fglobals = Frame(top, height=1)
  136. self.fglobals.pack(expand=1, fill="both")
  137. #
  138. if self.vstack.get():
  139. self.show_stack()
  140. if self.vlocals.get():
  141. self.show_locals()
  142. if self.vglobals.get():
  143. self.show_globals()
  144. def interaction(self, message, frame, info=None):
  145. self.frame = frame
  146. self.status.configure(text=message)
  147. #
  148. if info:
  149. type, value, tb = info
  150. try:
  151. m1 = type.__name__
  152. except AttributeError:
  153. m1 = "%s" % str(type)
  154. if value is not None:
  155. try:
  156. m1 = "%s: %s" % (m1, str(value))
  157. except:
  158. pass
  159. bg = "yellow"
  160. else:
  161. m1 = ""
  162. tb = None
  163. bg = self.errorbg
  164. self.error.configure(text=m1, background=bg)
  165. #
  166. sv = self.stackviewer
  167. if sv:
  168. stack, i = self.idb.get_stack(self.frame, tb)
  169. sv.load_stack(stack, i)
  170. #
  171. self.show_variables(1)
  172. #
  173. if self.vsource.get():
  174. self.sync_source_line()
  175. #
  176. for b in self.buttons:
  177. b.configure(state="normal")
  178. #
  179. self.top.wakeup()
  180. self.root.mainloop()
  181. #
  182. for b in self.buttons:
  183. b.configure(state="disabled")
  184. self.status.configure(text="")
  185. self.error.configure(text="", background=self.errorbg)
  186. self.frame = None
  187. def sync_source_line(self):
  188. frame = self.frame
  189. if not frame:
  190. return
  191. filename, lineno = self.__frame2fileline(frame)
  192. if filename[:1] + filename[-1:] != "<>" and os.path.exists(filename):
  193. self.flist.gotofileline(filename, lineno)
  194. def __frame2fileline(self, frame):
  195. code = frame.f_code
  196. filename = code.co_filename
  197. lineno = frame.f_lineno
  198. return filename, lineno
  199. def cont(self):
  200. self.idb.set_continue()
  201. self.root.quit()
  202. def step(self):
  203. self.idb.set_step()
  204. self.root.quit()
  205. def next(self):
  206. self.idb.set_next(self.frame)
  207. self.root.quit()
  208. def ret(self):
  209. self.idb.set_return(self.frame)
  210. self.root.quit()
  211. def quit(self):
  212. self.idb.set_quit()
  213. self.root.quit()
  214. stackviewer = None
  215. def show_stack(self):
  216. if not self.stackviewer and self.vstack.get():
  217. self.stackviewer = sv = StackViewer(self.fstack, self.flist, self)
  218. if self.frame:
  219. stack, i = self.idb.get_stack(self.frame, None)
  220. sv.load_stack(stack, i)
  221. else:
  222. sv = self.stackviewer
  223. if sv and not self.vstack.get():
  224. self.stackviewer = None
  225. sv.close()
  226. self.fstack['height'] = 1
  227. def show_source(self):
  228. if self.vsource.get():
  229. self.sync_source_line()
  230. def show_frame(self, (frame, lineno)):
  231. self.frame = frame
  232. self.show_variables()
  233. localsviewer = None
  234. globalsviewer = None
  235. def show_locals(self):
  236. lv = self.localsviewer
  237. if self.vlocals.get():
  238. if not lv:
  239. self.localsviewer = NamespaceViewer(self.flocals, "Locals")
  240. else:
  241. if lv:
  242. self.localsviewer = None
  243. lv.close()
  244. self.flocals['height'] = 1
  245. self.show_variables()
  246. def show_globals(self):
  247. gv = self.globalsviewer
  248. if self.vglobals.get():
  249. if not gv:
  250. self.globalsviewer = NamespaceViewer(self.fglobals, "Globals")
  251. else:
  252. if gv:
  253. self.globalsviewer = None
  254. gv.close()
  255. self.fglobals['height'] = 1
  256. self.show_variables()
  257. def show_variables(self, force=0):
  258. lv = self.localsviewer
  259. gv = self.globalsviewer
  260. frame = self.frame
  261. if not frame:
  262. ldict = gdict = None
  263. else:
  264. ldict = frame.f_locals
  265. gdict = frame.f_globals
  266. if lv and gv and ldict is gdict:
  267. ldict = None
  268. if lv:
  269. lv.load_dict(ldict, force, self.pyshell.interp.rpcclt)
  270. if gv:
  271. gv.load_dict(gdict, force, self.pyshell.interp.rpcclt)
  272. def set_breakpoint_here(self, filename, lineno):
  273. self.idb.set_break(filename, lineno)
  274. def clear_breakpoint_here(self, filename, lineno):
  275. self.idb.clear_break(filename, lineno)
  276. def clear_file_breaks(self, filename):
  277. self.idb.clear_all_file_breaks(filename)
  278. def load_breakpoints(self):
  279. "Load PyShellEditorWindow breakpoints into subprocess debugger"
  280. pyshell_edit_windows = self.pyshell.flist.inversedict.keys()
  281. for editwin in pyshell_edit_windows:
  282. filename = editwin.io.filename
  283. try:
  284. for lineno in editwin.breakpoints:
  285. self.set_breakpoint_here(filename, lineno)
  286. except AttributeError:
  287. continue
  288. class StackViewer(ScrolledList):
  289. def __init__(self, master, flist, gui):
  290. if macosxSupport.runningAsOSXApp():
  291. # At least on with the stock AquaTk version on OSX 10.4 you'll
  292. # get an shaking GUI that eventually kills IDLE if the width
  293. # argument is specified.
  294. ScrolledList.__init__(self, master)
  295. else:
  296. ScrolledList.__init__(self, master, width=80)
  297. self.flist = flist
  298. self.gui = gui
  299. self.stack = []
  300. def load_stack(self, stack, index=None):
  301. self.stack = stack
  302. self.clear()
  303. for i in range(len(stack)):
  304. frame, lineno = stack[i]
  305. try:
  306. modname = frame.f_globals["__name__"]
  307. except:
  308. modname = "?"
  309. code = frame.f_code
  310. filename = code.co_filename
  311. funcname = code.co_name
  312. import linecache
  313. sourceline = linecache.getline(filename, lineno)
  314. import string
  315. sourceline = string.strip(sourceline)
  316. if funcname in ("?", "", None):
  317. item = "%s, line %d: %s" % (modname, lineno, sourceline)
  318. else:
  319. item = "%s.%s(), line %d: %s" % (modname, funcname,
  320. lineno, sourceline)
  321. if i == index:
  322. item = "> " + item
  323. self.append(item)
  324. if index is not None:
  325. self.select(index)
  326. def popup_event(self, event):
  327. "override base method"
  328. if self.stack:
  329. return ScrolledList.popup_event(self, event)
  330. def fill_menu(self):
  331. "override base method"
  332. menu = self.menu
  333. menu.add_command(label="Go to source line",
  334. command=self.goto_source_line)
  335. menu.add_command(label="Show stack frame",
  336. command=self.show_stack_frame)
  337. def on_select(self, index):
  338. "override base method"
  339. if 0 <= index < len(self.stack):
  340. self.gui.show_frame(self.stack[index])
  341. def on_double(self, index):
  342. "override base method"
  343. self.show_source(index)
  344. def goto_source_line(self):
  345. index = self.listbox.index("active")
  346. self.show_source(index)
  347. def show_stack_frame(self):
  348. index = self.listbox.index("active")
  349. if 0 <= index < len(self.stack):
  350. self.gui.show_frame(self.stack[index])
  351. def show_source(self, index):
  352. if not (0 <= index < len(self.stack)):
  353. return
  354. frame, lineno = self.stack[index]
  355. code = frame.f_code
  356. filename = code.co_filename
  357. if os.path.isfile(filename):
  358. edit = self.flist.open(filename)
  359. if edit:
  360. edit.gotoline(lineno)
  361. class NamespaceViewer:
  362. def __init__(self, master, title, dict=None):
  363. width = 0
  364. height = 40
  365. if dict:
  366. height = 20*len(dict) # XXX 20 == observed height of Entry widget
  367. self.master = master
  368. self.title = title
  369. import repr
  370. self.repr = repr.Repr()
  371. self.repr.maxstring = 60
  372. self.repr.maxother = 60
  373. self.frame = frame = Frame(master)
  374. self.frame.pack(expand=1, fill="both")
  375. self.label = Label(frame, text=title, borderwidth=2, relief="groove")
  376. self.label.pack(fill="x")
  377. self.vbar = vbar = Scrollbar(frame, name="vbar")
  378. vbar.pack(side="right", fill="y")
  379. self.canvas = canvas = Canvas(frame,
  380. height=min(300, max(40, height)),
  381. scrollregion=(0, 0, width, height))
  382. canvas.pack(side="left", fill="both", expand=1)
  383. vbar["command"] = canvas.yview
  384. canvas["yscrollcommand"] = vbar.set
  385. self.subframe = subframe = Frame(canvas)
  386. self.sfid = canvas.create_window(0, 0, window=subframe, anchor="nw")
  387. self.load_dict(dict)
  388. dict = -1
  389. def load_dict(self, dict, force=0, rpc_client=None):
  390. if dict is self.dict and not force:
  391. return
  392. subframe = self.subframe
  393. frame = self.frame
  394. for c in subframe.children.values():
  395. c.destroy()
  396. self.dict = None
  397. if not dict:
  398. l = Label(subframe, text="None")
  399. l.grid(row=0, column=0)
  400. else:
  401. names = dict.keys()
  402. names.sort()
  403. row = 0
  404. for name in names:
  405. value = dict[name]
  406. svalue = self.repr.repr(value) # repr(value)
  407. # Strip extra quotes caused by calling repr on the (already)
  408. # repr'd value sent across the RPC interface:
  409. if rpc_client:
  410. svalue = svalue[1:-1]
  411. l = Label(subframe, text=name)
  412. l.grid(row=row, column=0, sticky="nw")
  413. l = Entry(subframe, width=0, borderwidth=0)
  414. l.insert(0, svalue)
  415. l.grid(row=row, column=1, sticky="nw")
  416. row = row+1
  417. self.dict = dict
  418. # XXX Could we use a <Configure> callback for the following?
  419. subframe.update_idletasks() # Alas!
  420. width = subframe.winfo_reqwidth()
  421. height = subframe.winfo_reqheight()
  422. canvas = self.canvas
  423. self.canvas["scrollregion"] = (0, 0, width, height)
  424. if height > 300:
  425. canvas["height"] = 300
  426. frame.pack(expand=1)
  427. else:
  428. canvas["height"] = height
  429. frame.pack(expand=0)
  430. def close(self):
  431. self.frame.destroy()