codekingpro/portable-devtools
115k
1# debugger.py2 3# A debugger for Pythonwin. Built from pdb.4 5# Mark Hammond (MHammond@skippinet.com.au) - Dec 94.6 7# usage:8# >>> import pywin.debugger9# >>> pywin.debugger.GetDebugger().run("command")10 11import bdb12import os13import pdb14import string15import sys16import traceback17import types18 19import commctrl20import pywin.docking.DockingBar21import win32api22import win32con23import win32ui24from pywin.framework import app, editor, interact, scriptutils25from pywin.framework.editor.color.coloreditor import MARKER_BREAKPOINT, MARKER_CURRENT26from pywin.mfc import afxres, dialog, object, window27from pywin.tools import browser, hierlist28 29# import win32traceutil30if win32ui.UNICODE:31 LVN_ENDLABELEDIT = commctrl.LVN_ENDLABELEDITW32else:33 LVN_ENDLABELEDIT = commctrl.LVN_ENDLABELEDITA34 35from .dbgcon import *36 37error = "pywin.debugger.error"38 39 40def SetInteractiveContext(globs, locs):41 if interact.edit is not None and interact.edit.currentView is not None:42 interact.edit.currentView.SetContext(globs, locs)43 44 45def _LineStateToMarker(ls):46 if ls == LINESTATE_CURRENT:47 return MARKER_CURRENT48 # elif ls == LINESTATE_CALLSTACK:49 # return MARKER_CALLSTACK50 return MARKER_BREAKPOINT51 52 53class HierListItem(browser.HLIPythonObject):54 pass55 56 57class HierFrameItem(HierListItem):58 def __init__(self, frame, debugger):59 HierListItem.__init__(self, frame, repr(frame))60 self.debugger = debugger61 62 def GetText(self):63 name = self.myobject.f_code.co_name64 if not name or name == "?":65 # See if locals has a '__name__' (ie, a module)66 if "__name__" in self.myobject.f_locals:67 name = str(self.myobject.f_locals["__name__"]) + " module"68 else:69 name = "<Debugger Context>"70 71 return "%s (%s:%d)" % (72 name,73 os.path.split(self.myobject.f_code.co_filename)[1],74 self.myobject.f_lineno,75 )76 77 def GetBitmapColumn(self):78 if self.debugger.curframe is self.myobject:79 return 780 else:81 return 882 83 def GetSubList(self):84 ret = []85 ret.append(HierFrameDict(self.myobject.f_locals, "Locals", 2))86 ret.append(HierFrameDict(self.myobject.f_globals, "Globals", 1))87 return ret88 89 def IsExpandable(self):90 return 191 92 def TakeDefaultAction(self):93 # Set the default frame to be this frame.94 self.debugger.set_cur_frame(self.myobject)95 return 196 97 98class HierFrameDict(browser.HLIDict):99 def __init__(self, dict, name, bitmapColumn):100 self.bitmapColumn = bitmapColumn101 browser.HLIDict.__init__(self, dict, name)102 103 def GetBitmapColumn(self):104 return self.bitmapColumn105 106 107class NoStackAvailableItem(HierListItem):108 def __init__(self, why):109 HierListItem.__init__(self, None, why)110 111 def IsExpandable(self):112 return 0113 114 def GetText(self):115 return self.name116 117 def GetBitmapColumn(self):118 return 8119 120 121class HierStackRoot(HierListItem):122 def __init__(self, debugger):123 HierListItem.__init__(self, debugger, None)124 self.last_stack = []125 126 ## def __del__(self):127 ## print "HierStackRoot dieing"128 def GetSubList(self):129 debugger = self.myobject130 # print self.debugger.stack, self.debugger.curframe131 ret = []132 if debugger.debuggerState == DBGSTATE_BREAK:133 stackUse = debugger.stack[:]134 stackUse.reverse()135 self.last_stack = []136 for frame, lineno in stackUse:137 self.last_stack.append((frame, lineno))138 if (139 frame is debugger.userbotframe140 ): # Dont bother showing frames below our bottom frame.141 break142 for frame, lineno in self.last_stack:143 ret.append(HierFrameItem(frame, debugger))144 ## elif debugger.debuggerState==DBGSTATE_NOT_DEBUGGING:145 ## ret.append(NoStackAvailableItem('<nothing is being debugged>'))146 ## else:147 ## ret.append(NoStackAvailableItem('<stack not available while running>'))148 return ret149 150 def GetText(self):151 return "root item"152 153 def IsExpandable(self):154 return 1155 156 157class HierListDebugger(hierlist.HierListWithItems):158 """Hier List of stack frames, breakpoints, whatever"""159 160 def __init__(self):161 hierlist.HierListWithItems.__init__(162 self, None, win32ui.IDB_DEBUGGER_HIER, None, win32api.RGB(255, 0, 0)163 )164 165 def Setup(self, debugger):166 root = HierStackRoot(debugger)167 self.AcceptRoot(root)168 169 170# def Refresh(self):171# self.Setup()172 173 174class DebuggerWindow(window.Wnd):175 def __init__(self, ob):176 window.Wnd.__init__(self, ob)177 self.debugger = None178 179 def Init(self, debugger):180 self.debugger = debugger181 182 def GetDefRect(self):183 defRect = app.LoadWindowSize("Debugger Windows\\" + self.title)184 if defRect[2] - defRect[0] == 0:185 defRect = 0, 0, 150, 150186 return defRect187 188 def OnDestroy(self, msg):189 newSize = self.GetWindowPlacement()[4]190 pywin.framework.app.SaveWindowSize("Debugger Windows\\" + self.title, newSize)191 return window.Wnd.OnDestroy(self, msg)192 193 def OnKeyDown(self, msg):194 key = msg[2]195 if key in (13, 27, 32):196 return 1197 if key in (46, 8): # delete/BS key198 self.DeleteSelected()199 return 0200 view = scriptutils.GetActiveView()201 try:202 firer = view.bindings.fire_key_event203 except AttributeError:204 firer = None205 if firer is not None:206 return firer(msg)207 else:208 return 1209 210 def DeleteSelected(self):211 win32api.MessageBeep()212 213 def EditSelected(self):214 win32api.MessageBeep()215 216 217class DebuggerStackWindow(DebuggerWindow):218 title = "Stack"219 220 def __init__(self):221 DebuggerWindow.__init__(self, win32ui.CreateTreeCtrl())222 self.list = HierListDebugger()223 self.listOK = 0224 225 def SaveState(self):226 self.list.DeleteAllItems()227 self.listOK = 0228 win32ui.WriteProfileVal(229 "Debugger Windows\\" + self.title, "Visible", self.IsWindowVisible()230 )231 232 def CreateWindow(self, parent):233 style = (234 win32con.WS_CHILD235 | win32con.WS_VISIBLE236 | win32con.WS_BORDER237 | commctrl.TVS_HASLINES238 | commctrl.TVS_LINESATROOT239 | commctrl.TVS_HASBUTTONS240 )241 self._obj_.CreateWindow(style, self.GetDefRect(), parent, win32ui.IDC_LIST1)242 self.HookMessage(self.OnKeyDown, win32con.WM_KEYDOWN)243 self.HookMessage(self.OnKeyDown, win32con.WM_SYSKEYDOWN)244 self.list.HierInit(parent, self)245 self.listOK = 0 # delayed setup246 # self.list.Setup()247 248 def RespondDebuggerState(self, state):249 assert self.debugger is not None, "Init not called"250 if not self.listOK:251 self.listOK = 1252 self.list.Setup(self.debugger)253 else:254 self.list.Refresh()255 256 def RespondDebuggerData(self):257 try:258 handle = self.GetChildItem(0)259 except win32ui.error:260 return # No items261 while 1:262 item = self.list.ItemFromHandle(handle)263 col = self.list.GetBitmapColumn(item)264 selCol = self.list.GetSelectedBitmapColumn(item)265 if selCol is None:266 selCol = col267 if self.list.GetItemImage(handle) != (col, selCol):268 self.list.SetItemImage(handle, col, selCol)269 try:270 handle = self.GetNextSiblingItem(handle)271 except win32ui.error:272 break273 274 275class DebuggerListViewWindow(DebuggerWindow):276 def __init__(self):277 DebuggerWindow.__init__(self, win32ui.CreateListCtrl())278 279 def CreateWindow(self, parent):280 list = self281 style = (282 win32con.WS_CHILD283 | win32con.WS_VISIBLE284 | win32con.WS_BORDER285 | commctrl.LVS_EDITLABELS286 | commctrl.LVS_REPORT287 )288 self._obj_.CreateWindow(style, self.GetDefRect(), parent, win32ui.IDC_LIST1)289 self.HookMessage(self.OnKeyDown, win32con.WM_KEYDOWN)290 self.HookMessage(self.OnKeyDown, win32con.WM_SYSKEYDOWN)291 list = self292 title, width = self.columns[0]293 itemDetails = (commctrl.LVCFMT_LEFT, width, title, 0)294 list.InsertColumn(0, itemDetails)295 col = 1296 for title, width in self.columns[1:]:297 col = col + 1298 itemDetails = (commctrl.LVCFMT_LEFT, width, title, 0)299 list.InsertColumn(col, itemDetails)300 parent.HookNotify(self.OnListEndLabelEdit, LVN_ENDLABELEDIT)301 parent.HookNotify(self.OnItemRightClick, commctrl.NM_RCLICK)302 parent.HookNotify(self.OnItemDoubleClick, commctrl.NM_DBLCLK)303 304 def RespondDebuggerData(self):305 pass306 307 def RespondDebuggerState(self, state):308 pass309 310 def EditSelected(self):311 try:312 sel = self.GetNextItem(-1, commctrl.LVNI_SELECTED)313 except win32ui.error:314 return315 self.EditLabel(sel)316 317 def OnKeyDown(self, msg):318 key = msg[2]319 # If someone starts typing, they probably are trying to edit the text!320 if chr(key) in string.ascii_uppercase:321 self.EditSelected()322 return 0323 return DebuggerWindow.OnKeyDown(self, msg)324 325 def OnItemDoubleClick(self, notify_data, extra):326 self.EditSelected()327 328 def OnItemRightClick(self, notify_data, extra):329 # First select the item we right-clicked on.330 pt = self.ScreenToClient(win32api.GetCursorPos())331 flags, hItem, subitem = self.HitTest(pt)332 if hItem == -1 or commctrl.TVHT_ONITEM & flags == 0:333 return None334 self.SetItemState(hItem, commctrl.LVIS_SELECTED, commctrl.LVIS_SELECTED)335 336 menu = win32ui.CreatePopupMenu()337 menu.AppendMenu(win32con.MF_STRING | win32con.MF_ENABLED, 1000, "Edit item")338 menu.AppendMenu(win32con.MF_STRING | win32con.MF_ENABLED, 1001, "Delete item")339 dockbar = self.GetParent()340 if dockbar.IsFloating():341 hook_parent = win32ui.GetMainFrame()342 else:343 hook_parent = self.GetParentFrame()344 hook_parent.HookCommand(self.OnEditItem, 1000)345 hook_parent.HookCommand(self.OnDeleteItem, 1001)346 menu.TrackPopupMenu(win32api.GetCursorPos()) # track at mouse position.347 return None348 349 def OnDeleteItem(self, command, code):350 self.DeleteSelected()351 352 def OnEditItem(self, command, code):353 self.EditSelected()354 355 356class DebuggerBreakpointsWindow(DebuggerListViewWindow):357 title = "Breakpoints"358 columns = [("Condition", 70), ("Location", 1024)]359 360 def SaveState(self):361 items = []362 for i in range(self.GetItemCount()):363 items.append(self.GetItemText(i, 0))364 items.append(self.GetItemText(i, 1))365 win32ui.WriteProfileVal(366 "Debugger Windows\\" + self.title, "BreakpointList", "\t".join(items)367 )368 win32ui.WriteProfileVal(369 "Debugger Windows\\" + self.title, "Visible", self.IsWindowVisible()370 )371 return 1372 373 def OnListEndLabelEdit(self, std, extra):374 item = extra[0]375 text = item[4]376 if text is None:377 return378 379 item_id = self.GetItem(item[0])[6]380 381 from bdb import Breakpoint382 383 for bplist in Breakpoint.bplist.values():384 for bp in bplist:385 if id(bp) == item_id:386 if text.strip().lower() == "none":387 text = None388 bp.cond = text389 break390 self.RespondDebuggerData()391 392 def DeleteSelected(self):393 try:394 num = self.GetNextItem(-1, commctrl.LVNI_SELECTED)395 item_id = self.GetItem(num)[6]396 from bdb import Breakpoint397 398 for bplist in list(Breakpoint.bplist.values()):399 for bp in bplist:400 if id(bp) == item_id:401 self.debugger.clear_break(bp.file, bp.line)402 break403 except win32ui.error:404 win32api.MessageBeep()405 self.RespondDebuggerData()406 407 def RespondDebuggerData(self):408 l = self409 l.DeleteAllItems()410 index = -1411 from bdb import Breakpoint412 413 for bplist in Breakpoint.bplist.values():414 for bp in bplist:415 baseName = os.path.split(bp.file)[1]416 cond = bp.cond417 item = index + 1, 0, 0, 0, str(cond), 0, id(bp)418 index = l.InsertItem(item)419 l.SetItemText(index, 1, "%s: %s" % (baseName, bp.line))420 421 422class DebuggerWatchWindow(DebuggerListViewWindow):423 title = "Watch"424 columns = [("Expression", 70), ("Value", 1024)]425 426 def CreateWindow(self, parent):427 DebuggerListViewWindow.CreateWindow(self, parent)428 items = win32ui.GetProfileVal(429 "Debugger Windows\\" + self.title, "Items", ""430 ).split("\t")431 index = -1432 for item in items:433 if item:434 index = self.InsertItem(index + 1, item)435 self.InsertItem(index + 1, "<New Item>")436 437 def SaveState(self):438 items = []439 for i in range(self.GetItemCount() - 1):440 items.append(self.GetItemText(i, 0))441 win32ui.WriteProfileVal(442 "Debugger Windows\\" + self.title, "Items", "\t".join(items)443 )444 win32ui.WriteProfileVal(445 "Debugger Windows\\" + self.title, "Visible", self.IsWindowVisible()446 )447 return 1448 449 def OnListEndLabelEdit(self, std, extra):450 item = extra[0]451 itemno = item[0]452 text = item[4]453 if text is None:454 return455 self.SetItemText(itemno, 0, text)456 if itemno == self.GetItemCount() - 1:457 self.InsertItem(itemno + 1, "<New Item>")458 self.RespondDebuggerState(self.debugger.debuggerState)459 460 def DeleteSelected(self):461 try:462 num = self.GetNextItem(-1, commctrl.LVNI_SELECTED)463 if num < self.GetItemCount() - 1: # We cant delete the last464 self.DeleteItem(num)465 except win32ui.error:466 win32api.MessageBeep()467 468 def RespondDebuggerState(self, state):469 globs = locs = None470 if state == DBGSTATE_BREAK:471 if self.debugger.curframe:472 globs = self.debugger.curframe.f_globals473 locs = self.debugger.curframe.f_locals474 elif state == DBGSTATE_NOT_DEBUGGING:475 import __main__476 477 globs = locs = __main__.__dict__478 for i in range(self.GetItemCount() - 1):479 text = self.GetItemText(i, 0)480 if globs is None:481 val = ""482 else:483 try:484 val = repr(eval(text, globs, locs))485 except SyntaxError:486 val = "Syntax Error"487 except:488 t, v, tb = sys.exc_info()489 val = traceback.format_exception_only(t, v)[0].strip()490 tb = None # prevent a cycle.491 self.SetItemText(i, 1, val)492 493 494def CreateDebuggerDialog(parent, klass):495 control = klass()496 control.CreateWindow(parent)497 return control498 499 500DebuggerDialogInfos = (501 (0xE810, DebuggerStackWindow, None),502 (0xE811, DebuggerBreakpointsWindow, (10, 10)),503 (0xE812, DebuggerWatchWindow, None),504)505 506 507# Prepare all the "control bars" for this package.508# If control bars are not all loaded when the toolbar-state functions are509# called, things go horribly wrong.510def PrepareControlBars(frame):511 style = (512 win32con.WS_CHILD513 | afxres.CBRS_SIZE_DYNAMIC514 | afxres.CBRS_TOP515 | afxres.CBRS_TOOLTIPS516 | afxres.CBRS_FLYBY517 )518 tbd = win32ui.CreateToolBar(frame, style, win32ui.ID_VIEW_TOOLBAR_DBG)519 tbd.ModifyStyle(0, commctrl.TBSTYLE_FLAT)520 tbd.LoadToolBar(win32ui.IDR_DEBUGGER)521 tbd.EnableDocking(afxres.CBRS_ALIGN_ANY)522 tbd.SetWindowText("Debugger")523 frame.DockControlBar(tbd)524 525 # and the other windows.526 for id, klass, float in DebuggerDialogInfos:527 try:528 frame.GetControlBar(id)529 exists = 1530 except win32ui.error:531 exists = 0532 if exists:533 continue534 bar = pywin.docking.DockingBar.DockingBar()535 style = win32con.WS_CHILD | afxres.CBRS_LEFT # don't create visible.536 bar.CreateWindow(537 frame,538 CreateDebuggerDialog,539 klass.title,540 id,541 style,542 childCreatorArgs=(klass,),543 )544 bar.SetBarStyle(545 bar.GetBarStyle()546 | afxres.CBRS_TOOLTIPS547 | afxres.CBRS_FLYBY548 | afxres.CBRS_SIZE_DYNAMIC549 )550 bar.EnableDocking(afxres.CBRS_ALIGN_ANY)551 if float is None:552 frame.DockControlBar(bar)553 else:554 frame.FloatControlBar(bar, float, afxres.CBRS_ALIGN_ANY)555 556 ## frame.ShowControlBar(bar, 0, 1)557 558 559SKIP_NONE = 0560SKIP_STEP = 1561SKIP_RUN = 2562 563debugger_parent = pdb.Pdb564 565 566class Debugger(debugger_parent):567 def __init__(self):568 self.inited = 0569 self.skipBotFrame = SKIP_NONE570 self.userbotframe = None571 self.frameShutdown = 0572 self.pumping = 0573 self.debuggerState = DBGSTATE_NOT_DEBUGGING # Assume so, anyway.574 self.shownLineCurrent = None # The last filename I highlighted.575 self.shownLineCallstack = None # The last filename I highlighted.576 self.last_cmd_debugged = ""577 self.abortClosed = 0578 self.isInitialBreakpoint = 0579 debugger_parent.__init__(self)580 581 # See if any break-points have been set in the editor582 for doc in editor.editorTemplate.GetDocumentList():583 lineNo = -1584 while 1:585 lineNo = doc.MarkerGetNext(lineNo + 1, MARKER_BREAKPOINT)586 if lineNo <= 0:587 break588 self.set_break(doc.GetPathName(), lineNo)589 590 self.reset()591 self.inForcedGUI = win32ui.GetApp().IsInproc()592 self.options = LoadDebuggerOptions()593 self.bAtException = self.bAtPostMortem = 0594 595 def __del__(self):596 self.close()597 598 def close(self, frameShutdown=0):599 # abortClose indicates if we have total shutdown600 # (ie, main window is dieing)601 if self.pumping:602 # Can stop pump here, as it only posts a message, and603 # returns immediately.604 if not self.StopDebuggerPump(): # User cancelled close.605 return 0606 # NOTE - from this point on the close can not be607 # stopped - the WM_QUIT message is already in the queue.608 self.frameShutdown = frameShutdown609 if not self.inited:610 return 1611 self.inited = 0612 613 SetInteractiveContext(None, None)614 615 frame = win32ui.GetMainFrame()616 # Hide the debuger toolbars (as they wont normally form part of the main toolbar state.617 for id, klass, float in DebuggerDialogInfos:618 try:619 tb = frame.GetControlBar(id)620 if tb.dialog is not None: # We may never have actually been shown.621 tb.dialog.SaveState()622 frame.ShowControlBar(tb, 0, 1)623 except win32ui.error:624 pass625 626 self._UnshowCurrentLine()627 self.set_quit()628 return 1629 630 def StopDebuggerPump(self):631 assert self.pumping, "Can't stop the debugger pump if Im not pumping!"632 # After stopping a pump, I may never return.633 if self.GUIAboutToFinishInteract():634 self.pumping = 0635 win32ui.StopDebuggerPump() # Posts a message, so we do return.636 return 1637 return 0638 639 def get_option(self, option):640 """Public interface into debugger options"""641 try:642 return self.options[option]643 except KeyError:644 raise error("Option %s is not a valid option" % option)645 646 def prep_run(self, cmd):647 pass648 649 def done_run(self, cmd=None):650 self.RespondDebuggerState(DBGSTATE_NOT_DEBUGGING)651 self.close()652 653 def canonic(self, fname):654 return os.path.abspath(fname).lower()655 656 def reset(self):657 debugger_parent.reset(self)658 self.userbotframe = None659 self.UpdateAllLineStates()660 self._UnshowCurrentLine()661 662 def setup(self, f, t):663 debugger_parent.setup(self, f, t)664 self.bAtException = t is not None665 666 def set_break(self, filename, lineno, temporary=0, cond=None):667 filename = self.canonic(filename)668 self.SetLineState(filename, lineno, LINESTATE_BREAKPOINT)669 return debugger_parent.set_break(self, filename, lineno, temporary, cond)670 671 def clear_break(self, filename, lineno):672 filename = self.canonic(filename)673 self.ResetLineState(filename, lineno, LINESTATE_BREAKPOINT)674 return debugger_parent.clear_break(self, filename, lineno)675 676 def cmdloop(self):677 if self.frameShutdown:678 return # App in the process of closing - never break in!679 self.GUIAboutToBreak()680 681 def print_stack_entry(self, frame):682 # We dont want a stack printed - our GUI is better :-)683 pass684 685 def user_return(self, frame, return_value):686 # Same as parent, just no "print"687 # This function is called when a return trap is set here688 frame.f_locals["__return__"] = return_value689 self.interaction(frame, None)690 691 def user_call(self, frame, args):692 # base class has an annoying 'print' that adds no value to us...693 if self.stop_here(frame):694 self.interaction(frame, None)695 696 def user_exception(self, frame, exc_info):697 # This function is called if an exception occurs,698 # but only if we are to stop at or just below this level699 (exc_type, exc_value, exc_traceback) = exc_info700 if self.get_option(OPT_STOP_EXCEPTIONS):701 frame.f_locals["__exception__"] = exc_type, exc_value702 print("Unhandled exception while debugging...")703 # on both py2k and py3k, we may be called with exc_value704 # being the args to the exception, or it may already be705 # instantiated (IOW, PyErr_Normalize() hasn't been706 # called on the args). In py2k this is fine, but in707 # py3k, traceback.print_exception fails. So on py3k708 # we instantiate an exception instance to print.709 if sys.version_info > (3,) and not isinstance(exc_value, BaseException):710 # they are args - may be a single item or already a tuple711 if not isinstance(exc_value, tuple):712 exc_value = (exc_value,)713 exc_value = exc_type(*exc_value)714 715 traceback.print_exception(exc_type, exc_value, exc_traceback)716 self.interaction(frame, exc_traceback)717 718 def user_line(self, frame):719 if frame.f_lineno == 0:720 return721 debugger_parent.user_line(self, frame)722 723 def stop_here(self, frame):724 if self.isInitialBreakpoint:725 self.isInitialBreakpoint = 0726 self.set_continue()727 return 0728 if frame is self.botframe and self.skipBotFrame == SKIP_RUN:729 self.set_continue()730 return 0731 if frame is self.botframe and self.skipBotFrame == SKIP_STEP:732 self.set_step()733 return 0734 return debugger_parent.stop_here(self, frame)735 736 def run(self, cmd, globals=None, locals=None, start_stepping=1):737 if not isinstance(cmd, (str, types.CodeType)):738 raise TypeError("Only strings can be run")739 self.last_cmd_debugged = cmd740 if start_stepping:741 self.isInitialBreakpoint = 0742 else:743 self.isInitialBreakpoint = 1744 try:745 if globals is None:746 import __main__747 748 globals = __main__.__dict__749 if locals is None:750 locals = globals751 self.reset()752 self.prep_run(cmd)753 sys.settrace(self.trace_dispatch)754 if type(cmd) != types.CodeType:755 cmd = cmd + "\n"756 try:757 try:758 if start_stepping:759 self.skipBotFrame = SKIP_STEP760 else:761 self.skipBotFrame = SKIP_RUN762 exec(cmd, globals, locals)763 except bdb.BdbQuit:764 pass765 finally:766 self.skipBotFrame = SKIP_NONE767 self.quitting = 1768 sys.settrace(None)769 770 finally:771 self.done_run(cmd)772 773 def runeval(self, expr, globals=None, locals=None):774 self.prep_run(expr)775 try:776 debugger_parent.runeval(self, expr, globals, locals)777 finally:778 self.done_run(expr)779 780 def runexec(self, what, globs=None, locs=None):781 self.reset()782 sys.settrace(self.trace_dispatch)783 try:784 try:785 exec(what, globs, locs)786 except bdb.BdbQuit:787 pass788 finally:789 self.quitting = 1790 sys.settrace(None)791 792 def do_set_step(self):793 if self.GUIAboutToRun():794 self.set_step()795 796 def do_set_next(self):797 if self.GUIAboutToRun():798 self.set_next(self.curframe)799 800 def do_set_return(self):801 if self.GUIAboutToRun():802 self.set_return(self.curframe)803 804 def do_set_continue(self):805 if self.GUIAboutToRun():806 self.set_continue()807 808 def set_quit(self):809 ok = 1810 if self.pumping:811 ok = self.StopDebuggerPump()812 if ok:813 debugger_parent.set_quit(self)814 815 def _dump_frame_(self, frame, name=None):816 if name is None:817 name = ""818 if frame:819 if frame.f_code and frame.f_code.co_filename:820 fname = os.path.split(frame.f_code.co_filename)[1]821 else:822 fname = "??"823 print(repr(name), fname, frame.f_lineno, frame)824 else:825 print(repr(name), "None")826 827 def set_trace(self):828 # Start debugging from _2_ levels up!829 try:830 1 + ""831 except:832 frame = sys.exc_info()[2].tb_frame.f_back.f_back833 self.reset()834 self.userbotframe = None835 while frame:836 # scriptutils.py creates a local variable with name837 # '_debugger_stop_frame_', and we dont go past it838 # (everything above this is Pythonwin framework code)839 if "_debugger_stop_frame_" in frame.f_locals:840 self.userbotframe = frame841 break842 843 frame.f_trace = self.trace_dispatch844 self.botframe = frame845 frame = frame.f_back846 self.set_step()847 sys.settrace(self.trace_dispatch)848 849 def set_cur_frame(self, frame):850 # Sets the "current" frame - ie, the frame with focus. This is the851 # frame on which "step out" etc actions are taken.852 # This may or may not be the top of the stack.853 assert frame is not None, "You must pass a valid frame"854 self.curframe = frame855 for f, index in self.stack:856 if f is frame:857 self.curindex = index858 break859 else:860 assert 0, "Can't find the frame in the stack."861 SetInteractiveContext(frame.f_globals, frame.f_locals)862 self.GUIRespondDebuggerData()863 self.ShowCurrentLine()864 865 def IsBreak(self):866 return self.debuggerState == DBGSTATE_BREAK867 868 def IsDebugging(self):869 return self.debuggerState != DBGSTATE_NOT_DEBUGGING870 871 def RespondDebuggerState(self, state):872 if state == self.debuggerState:873 return874 if state == DBGSTATE_NOT_DEBUGGING: # Debugger exists, but not doing anything875 title = ""876 elif state == DBGSTATE_RUNNING: # Code is running under the debugger.877 title = " - running"878 elif state == DBGSTATE_BREAK: # We are at a breakpoint or stepping or whatever.879 if self.bAtException:880 if self.bAtPostMortem:881 title = " - post mortem exception"882 else:883 title = " - exception"884 else:885 title = " - break"886 else:887 raise error("Invalid debugger state passed!")888 win32ui.GetMainFrame().SetWindowText(889 win32ui.LoadString(win32ui.IDR_MAINFRAME) + title890 )891 if self.debuggerState == DBGSTATE_QUITTING and state != DBGSTATE_NOT_DEBUGGING:892 print("Ignoring state change cos Im trying to stop!", state)893 return894 self.debuggerState = state895 try:896 frame = win32ui.GetMainFrame()897 except win32ui.error:898 frame = None899 if frame is not None:900 for id, klass, float in DebuggerDialogInfos:901 cb = win32ui.GetMainFrame().GetControlBar(id).dialog902 cb.RespondDebuggerState(state)903 # Tell each open editor window about the state transition904 for doc in editor.editorTemplate.GetDocumentList():905 doc.OnDebuggerStateChange(state)906 self.ShowCurrentLine()907 908 #909 # GUI debugger interface.910 #911 def GUICheckInit(self):912 if self.inited:913 return914 self.inited = 1915 frame = win32ui.GetMainFrame()916 917 # Ensure the debugger windows are attached to the debugger.918 for id, klass, float in DebuggerDialogInfos:919 w = frame.GetControlBar(id)920 w.dialog.Init(self)921 # Show toolbar if it was visible during last debug session922 # This would be better done using a CDockState, but that class is not wrapped yet923 if win32ui.GetProfileVal(924 "Debugger Windows\\" + w.dialog.title, "Visible", 0925 ):926 frame.ShowControlBar(w, 1, 1)927 928 # ALWAYS show debugging toolbar, regardless of saved state929 tb = frame.GetControlBar(win32ui.ID_VIEW_TOOLBAR_DBG)930 frame.ShowControlBar(tb, 1, 1)931 self.GUIRespondDebuggerData()932 933 # frame.RecalcLayout()934 935 def GetDebuggerBar(self, barName):936 frame = win32ui.GetMainFrame()937 for id, klass, float in DebuggerDialogInfos:938 if klass.title == barName:939 return frame.GetControlBar(id)940 assert 0, "Can't find a bar of that name!"941 942 def GUIRespondDebuggerData(self):943 if not self.inited: # GUI not inited - no toolbars etc.944 return945 946 for id, klass, float in DebuggerDialogInfos:947 cb = win32ui.GetMainFrame().GetControlBar(id).dialog948 cb.RespondDebuggerData()949 950 def GUIAboutToRun(self):951 if not self.StopDebuggerPump():952 return 0953 self._UnshowCurrentLine()954 self.RespondDebuggerState(DBGSTATE_RUNNING)955 SetInteractiveContext(None, None)956 return 1957 958 def GUIAboutToBreak(self):959 "Called as the GUI debugger is about to get context, and take control of the running program."960 self.GUICheckInit()961 self.RespondDebuggerState(DBGSTATE_BREAK)962 self.GUIAboutToInteract()963 if self.pumping:964 print("!!! Already pumping - outa here")965 return966 self.pumping = 1967 win32ui.StartDebuggerPump() # NOTE - This will NOT return until the user is finished interacting968 assert not self.pumping, "Should not be pumping once the pump has finished"969 if self.frameShutdown: # User shut down app while debugging970 win32ui.GetMainFrame().PostMessage(win32con.WM_CLOSE)971 972 def GUIAboutToInteract(self):973 "Called as the GUI is about to perform any interaction with the user"974 frame = win32ui.GetMainFrame()975 # Remember the enabled state of our main frame976 # may be disabled primarily if a modal dialog is displayed.977 # Only get at enabled via GetWindowLong.978 self.bFrameEnabled = frame.IsWindowEnabled()979 self.oldForeground = None980 fw = win32ui.GetForegroundWindow()981 if fw is not frame:982 self.oldForeground = fw983 # fw.EnableWindow(0) Leave enabled for now?984 self.oldFrameEnableState = frame.IsWindowEnabled()985 frame.EnableWindow(1)986 if self.inForcedGUI and not frame.IsWindowVisible():987 frame.ShowWindow(win32con.SW_SHOW)988 frame.UpdateWindow()989 if self.curframe:990 SetInteractiveContext(self.curframe.f_globals, self.curframe.f_locals)991 else:992 SetInteractiveContext(None, None)993 self.GUIRespondDebuggerData()994 995 def GUIAboutToFinishInteract(self):996 """Called as the GUI is about to finish any interaction with the user997 Returns non zero if we are allowed to stop interacting"""998 if self.oldForeground is not None:999 try:1000 win32ui.GetMainFrame().EnableWindow(self.oldFrameEnableState)1001 self.oldForeground.EnableWindow(1)1002 except win32ui.error:1003 # old window may be dead.1004 pass1005 # self.oldForeground.SetForegroundWindow() - fails??1006 if not self.inForcedGUI:1007 return 1 # Never a problem, and nothing else to do.1008 # If we are running a forced GUI, we may never get an opportunity1009 # to interact again. Therefore we perform a "SaveAll", to makesure that1010 # any documents are saved before leaving.1011 for template in win32ui.GetApp().GetDocTemplateList():1012 for doc in template.GetDocumentList():1013 if not doc.SaveModified():1014 return 01015 # All documents saved - now hide the app and debugger.1016 if self.get_option(OPT_HIDE):1017 frame = win32ui.GetMainFrame()1018 frame.ShowWindow(win32con.SW_HIDE)1019 return 11020 1021 #1022 # Pythonwin interface - all stuff to do with showing source files,1023 # changing line states etc.1024 #1025 def ShowLineState(self, fileName, lineNo, lineState):1026 # Set the state of a line, open if not already1027 self.ShowLineNo(fileName, lineNo)1028 self.SetLineState(fileName, lineNo, lineState)1029 1030 def SetLineState(self, fileName, lineNo, lineState):1031 # Set the state of a line if the document is open.1032 doc = editor.editorTemplate.FindOpenDocument(fileName)1033 if doc is not None:1034 marker = _LineStateToMarker(lineState)1035 if not doc.MarkerCheck(lineNo, marker):1036 doc.MarkerAdd(lineNo, marker)1037 1038 def ResetLineState(self, fileName, lineNo, lineState):1039 # Set the state of a line if the document is open.1040 doc = editor.editorTemplate.FindOpenDocument(fileName)1041 if doc is not None:1042 marker = _LineStateToMarker(lineState)1043 doc.MarkerDelete(lineNo, marker)1044 1045 def UpdateDocumentLineStates(self, doc):1046 # Show all lines in their special status color. If the doc is open1047 # all line states are reset.1048 doc.MarkerDeleteAll(MARKER_BREAKPOINT)1049 doc.MarkerDeleteAll(MARKER_CURRENT)1050 fname = self.canonic(doc.GetPathName())1051 # Now loop over all break-points1052 for line in self.breaks.get(fname, []):1053 doc.MarkerAdd(line, MARKER_BREAKPOINT)1054 # And the current line if in this document.1055 if self.shownLineCurrent and fname == self.shownLineCurrent[0]:1056 lineNo = self.shownLineCurrent[1]1057 if not doc.MarkerCheck(lineNo, MARKER_CURRENT):1058 doc.MarkerAdd(lineNo, MARKER_CURRENT)1059 1060 # if self.shownLineCallstack and fname == self.shownLineCallstack[0]:1061 # doc.MarkerAdd(self.shownLineCallstack[1], MARKER_CURRENT)1062 1063 def UpdateAllLineStates(self):1064 for doc in editor.editorTemplate.GetDocumentList():1065 self.UpdateDocumentLineStates(doc)1066 1067 def ShowCurrentLine(self):1068 # Show the current line. Only ever 1 current line - undoes last current1069 # The "Current Line" is self.curframe.1070 # The "Callstack Line" is the top of the stack.1071 # If current == callstack, only show as current.1072 self._UnshowCurrentLine() # un-highlight the old one.1073 if self.curframe:1074 fileName = self.canonic(self.curframe.f_code.co_filename)1075 lineNo = self.curframe.f_lineno1076 self.shownLineCurrent = fileName, lineNo1077 self.ShowLineState(fileName, lineNo, LINESTATE_CURRENT)1078 1079 def _UnshowCurrentLine(self):1080 "Unshow the current line, and forget it"1081 if self.shownLineCurrent is not None:1082 fname, lineno = self.shownLineCurrent1083 self.ResetLineState(fname, lineno, LINESTATE_CURRENT)1084 self.shownLineCurrent = None1085 1086 def ShowLineNo(self, filename, lineno):1087 wasOpen = editor.editorTemplate.FindOpenDocument(filename) is not None1088 if os.path.isfile(filename) and scriptutils.JumpToDocument(filename, lineno):1089 if not wasOpen:1090 doc = editor.editorTemplate.FindOpenDocument(filename)1091 if doc is not None:1092 self.UpdateDocumentLineStates(doc)1093 return 11094 return 01095 return 11096 else:1097 # Can't find the source file - linecache may have it?1098 import linecache1099 1100 line = linecache.getline(filename, lineno)1101 print(1102 "%s(%d): %s"1103 % (os.path.basename(filename), lineno, line[:-1].expandtabs(4))1104 )1105 return 01106 