Mercurial > cpython-lru_cache-weakref
annotate Mac/Tools/IDE/PyDebugger.py @ 27998:e27f58a50737 legacy-trunk
SF bug #690377: Dud footnote reference in distutils docs
| author | Raymond Hettinger <python@rcn.com> |
|---|---|
| date | Fri, 21 Feb 2003 02:47:09 +0000 |
| parents | caa245af7786 |
| children | 9e737d63f380 |
| rev | line source |
|---|---|
| 10047 | 1 import sys |
| 2 import bdb | |
| 3 import types | |
| 4 import os | |
| 5 | |
| 6 import W | |
| 7 import WASTEconst | |
| 8 import PyBrowser | |
|
19488
42b2f1936254
Import the MacOS toolbox modules from the Carbon package.
Jack Jansen <jack.jansen@cwi.nl>
parents:
18176
diff
changeset
|
9 from Carbon import Qd |
|
42b2f1936254
Import the MacOS toolbox modules from the Carbon package.
Jack Jansen <jack.jansen@cwi.nl>
parents:
18176
diff
changeset
|
10 from Carbon import Evt |
|
42b2f1936254
Import the MacOS toolbox modules from the Carbon package.
Jack Jansen <jack.jansen@cwi.nl>
parents:
18176
diff
changeset
|
11 from Carbon import Lists |
| 10047 | 12 import MacOS |
| 13 _filenames = {} | |
| 14 | |
| 15 SIMPLE_TYPES = ( | |
| 16 types.NoneType, | |
| 17 types.IntType, | |
| 18 types.LongType, | |
| 19 types.FloatType, | |
| 20 types.ComplexType, | |
| 21 types.StringType | |
| 22 ) | |
| 23 | |
| 24 | |
| 25 class Debugger(bdb.Bdb): | |
| 26 | |
| 27 def __init__(self, title = 'Debugger'): | |
| 28 bdb.Bdb.__init__(self) | |
| 29 self.closed = 1 | |
| 30 self.title = title | |
| 31 self.breaksviewer = None | |
| 32 self.reset() | |
| 33 self.tracing = 0 | |
| 34 self.tracingmonitortime = Evt.TickCount() | |
| 35 self.editors = {} | |
| 36 | |
| 37 prefs = W.getapplication().getprefs() | |
| 38 if prefs.debugger: | |
| 39 for file, breaks in prefs.debugger.breaks.items(): | |
| 40 for b in breaks: | |
| 41 self.set_break(file, b) | |
| 42 self.bounds, self.horpanes, self.verpanes = prefs.debugger.windowsettings | |
| 43 self.tracemagic = prefs.debugger.tracemagic | |
| 44 else: | |
| 45 self.breaks = {} | |
| 46 self.horpanes = (0.4, 0.6) | |
| 47 self.verpanes = (0.3, 0.35, 0.35) | |
| 48 self.bounds = (600, 400) | |
| 49 self.tracemagic = 0 | |
| 50 self.laststacksel = None | |
| 51 | |
|
18176
cc7631fbf7f9
Override bdb's canonic() method with a no-op: with bdb's version we couldn't edit breakpoints in file-less ("Untitled" script windows). Besides, we did't need it as we always use full path names anyway.
Just van Rossum <just@letterror.com>
parents:
18167
diff
changeset
|
52 def canonic(self, filename): |
|
cc7631fbf7f9
Override bdb's canonic() method with a no-op: with bdb's version we couldn't edit breakpoints in file-less ("Untitled" script windows). Besides, we did't need it as we always use full path names anyway.
Just van Rossum <just@letterror.com>
parents:
18167
diff
changeset
|
53 # override: the provided canonic() method breaks our |
|
cc7631fbf7f9
Override bdb's canonic() method with a no-op: with bdb's version we couldn't edit breakpoints in file-less ("Untitled" script windows). Besides, we did't need it as we always use full path names anyway.
Just van Rossum <just@letterror.com>
parents:
18167
diff
changeset
|
54 # file-less Untitled windows |
|
cc7631fbf7f9
Override bdb's canonic() method with a no-op: with bdb's version we couldn't edit breakpoints in file-less ("Untitled" script windows). Besides, we did't need it as we always use full path names anyway.
Just van Rossum <just@letterror.com>
parents:
18167
diff
changeset
|
55 return filename |
|
cc7631fbf7f9
Override bdb's canonic() method with a no-op: with bdb's version we couldn't edit breakpoints in file-less ("Untitled" script windows). Besides, we did't need it as we always use full path names anyway.
Just van Rossum <just@letterror.com>
parents:
18167
diff
changeset
|
56 |
| 10047 | 57 def reset(self): |
| 58 self.currentframe = None | |
| 59 self.file = None | |
| 60 self.laststack = None | |
| 61 self.reason = 'Not running' | |
| 62 self.continuewithoutdebugger = 0 | |
| 63 bdb.Bdb.reset(self) | |
| 64 self.forget() | |
| 65 | |
| 66 def start(self, bottomframe = None, running = 0): | |
| 67 W.getapplication().DebuggerQuit = bdb.BdbQuit | |
|
19488
42b2f1936254
Import the MacOS toolbox modules from the Carbon package.
Jack Jansen <jack.jansen@cwi.nl>
parents:
18176
diff
changeset
|
68 from Carbon import Menu |
| 10047 | 69 Menu.HiliteMenu(0) |
| 70 if self.closed: | |
| 71 self.setupwidgets(self.title) | |
| 72 self.closed = 0 | |
| 73 if not self.w.parent.debugger_quitting: | |
| 74 self.w.select() | |
| 75 raise W.AlertError, 'There is another debugger session busy.' | |
| 76 self.reset() | |
| 77 self.botframe = bottomframe | |
| 78 if running: | |
| 79 self.set_continue() | |
|
18167
c5ac6f055c62
Some long overdue maintainance. Made all IDE sources 7-bit-clean, to avoid any further encoding conversion troubles.
Just van Rossum <just@letterror.com>
parents:
17845
diff
changeset
|
80 self.reason = 'Running\xc9' |
| 10047 | 81 self.setstate('running') |
| 82 else: | |
| 83 self.set_step() | |
| 84 self.reason = 'stopped' | |
| 85 self.setstate('stopped') | |
| 86 sys.settrace(self.trace_dispatch) | |
| 87 | |
| 88 def stop(self): | |
| 89 self.set_quit() | |
| 90 if self.w.parent: | |
| 91 self.exit_mainloop() | |
| 92 self.resetwidgets() | |
| 93 | |
| 94 def set_continue_without_debugger(self): | |
| 95 sys.settrace(None) | |
| 96 self.set_quit() | |
| 97 self.clear_tracefuncs() | |
| 98 self.continuewithoutdebugger = 1 | |
|
11324
c1b725b1a144
minor cleanup, avoiding rare traceback (jvr)
Just van Rossum <just@lettererror.com>
parents:
10087
diff
changeset
|
99 if hasattr(self, "w") and self.w.parent: |
| 10047 | 100 self.exit_mainloop() |
| 101 self.resetwidgets() | |
| 102 | |
| 103 def clear_tracefuncs(self): | |
| 104 try: | |
| 105 raise 'spam' | |
| 106 except: | |
| 107 pass | |
| 108 frame = sys.exc_traceback.tb_frame | |
| 109 while frame is not None: | |
| 110 del frame.f_trace | |
| 111 frame = frame.f_back | |
| 112 | |
| 113 def postmortem(self, exc_type, exc_value, traceback): | |
| 114 if self.closed: | |
| 115 self.setupwidgets(self.title) | |
| 116 self.closed = 0 | |
| 117 if not self.w.parent.debugger_quitting: | |
| 118 raise W.AlertError, 'There is another debugger session busy.' | |
| 119 self.reset() | |
| 120 if traceback: | |
| 121 self.botframe = traceback.tb_frame | |
| 122 while traceback.tb_next <> None: | |
| 123 traceback = traceback.tb_next | |
| 124 frame = traceback.tb_frame | |
| 125 else: | |
| 126 self.botframe = None | |
| 127 frame = None | |
| 128 self.w.panes.bottom.buttons.killbutton.enable(1) | |
| 129 self.reason = '(dead) ' + self.formatexception(exc_type, exc_value) | |
| 130 self.w.select() | |
| 131 self.setup(frame, traceback) | |
| 132 self.setstate('dead') | |
| 133 self.showstack(self.curindex) | |
| 134 self.showframe(self.curindex) | |
| 135 | |
| 136 def setupwidgets(self, title): | |
| 137 self.w = w = W.Window(self.bounds, title, minsize = (500, 300)) | |
| 138 | |
| 139 w.panes = W.HorizontalPanes((8, 4, -8, -8), self.horpanes) | |
| 140 | |
| 141 w.panes.browserpanes = browserpanes = W.VerticalPanes(None, self.verpanes) | |
| 142 | |
| 143 browserpanes.stacklist = W.Group(None) | |
| 144 browserpanes.stacklist.title = W.TextBox((4, 0, 0, 12), 'Stack') | |
| 145 browserpanes.stacklist.stack = W.List((0, 16, 0, 0), callback = self.do_stack, flags = Lists.lOnlyOne) | |
| 146 | |
| 147 browserpanes.locals = W.Group(None) | |
| 148 browserpanes.locals.title = W.TextBox((4, 0, 0, 12), 'Local variables') | |
| 149 browserpanes.locals.browser = PyBrowser.BrowserWidget((0, 16, 0, 0)) | |
| 150 | |
| 151 browserpanes.globals = W.Group(None) | |
| 152 browserpanes.globals.title = W.TextBox((4, 0, 0, 12), 'Global variables') | |
| 153 browserpanes.globals.browser = PyBrowser.BrowserWidget((0, 16, 0, 0)) | |
| 154 | |
| 155 w.panes.bottom = bottom = W.Group(None) | |
| 156 bottom.src = src = W.Group((0, 52, 0, 0)) | |
| 157 source = SourceViewer((1, 1, -15, -15), readonly = 1, debugger = self) | |
| 158 src.optionsmenu = W.PopupMenu((-16, 0, 16, 16), []) | |
| 159 src.optionsmenu.bind('<click>', self.makeoptionsmenu) | |
| 160 | |
| 161 src._barx = W.Scrollbar((0, -16, -15, 16), source.hscroll, max = 32767) | |
| 162 src._bary = W.Scrollbar((-16, 15, 16, -15), source.vscroll, max = 32767) | |
| 163 src.source = source | |
| 164 src.frame = W.Frame((0, 0, -15, -15)) | |
| 165 | |
| 166 bottom.tracingmonitor = TracingMonitor((0, 23, 6, 6)) | |
| 167 bottom.state = W.TextBox((12, 20, 0, 16), self.reason) | |
| 168 | |
| 169 bottom.srctitle = W.TextBox((12, 36, 0, 14)) | |
| 170 bottom.buttons = buttons = W.Group((12, 0, 0, 16)) | |
| 171 | |
| 172 buttons.runbutton = W.Button((0, 0, 50, 16), "Run", self.do_run) | |
| 173 buttons.stopbutton = W.Button((58, 0, 50, 16), "Stop", self.do_stop) | |
| 174 buttons.killbutton = W.Button((116, 0, 50, 16), "Kill", self.do_kill) | |
| 175 buttons.line = W.VerticalLine((173, 0, 0, 0)) | |
|
26650
caa245af7786
Tweaked some button sizes to make them look better on OSX.
Jack Jansen <jack.jansen@cwi.nl>
parents:
25238
diff
changeset
|
176 buttons.stepbutton = W.Button((181, 0, 60, 16), "Step", self.do_step) |
|
caa245af7786
Tweaked some button sizes to make them look better on OSX.
Jack Jansen <jack.jansen@cwi.nl>
parents:
25238
diff
changeset
|
177 buttons.stepinbutton = W.Button((249, 0, 60, 16), "Step in", self.do_stepin) |
|
caa245af7786
Tweaked some button sizes to make them look better on OSX.
Jack Jansen <jack.jansen@cwi.nl>
parents:
25238
diff
changeset
|
178 buttons.stepoutbutton = W.Button((317, 0, 60, 16), "Step out", self.do_stepout) |
| 10047 | 179 |
| 180 w.bind('cmdr', buttons.runbutton.push) | |
| 181 w.bind('cmd.', buttons.stopbutton.push) | |
| 182 w.bind('cmdk', buttons.killbutton.push) | |
| 183 w.bind('cmds', buttons.stepbutton.push) | |
| 184 w.bind('cmdt', buttons.stepinbutton.push) | |
| 185 w.bind('cmdu', buttons.stepoutbutton.push) | |
| 186 | |
| 187 w.bind('<close>', self.close) | |
| 188 | |
| 189 w.open() | |
| 190 w.xxx___select(w.panes.bottom.src.source) | |
| 191 | |
| 192 def makeoptionsmenu(self): | |
| 193 options = [('Clear breakpoints', self.w.panes.bottom.src.source.clearbreakpoints), | |
| 194 ('Clear all breakpoints', self.clear_all_breaks), | |
|
18167
c5ac6f055c62
Some long overdue maintainance. Made all IDE sources 7-bit-clean, to avoid any further encoding conversion troubles.
Just van Rossum <just@letterror.com>
parents:
17845
diff
changeset
|
195 ('Edit breakpoints\xc9', self.edit_breaks), '-', |
| 10047 | 196 (self.tracemagic and |
| 197 'Disable __magic__ tracing' or 'Enable __magic__ tracing', self.togglemagic)] | |
| 198 self.w.panes.bottom.src.optionsmenu.set(options) | |
| 199 | |
| 200 def edit_breaks(self): | |
| 201 if self.breaksviewer: | |
| 202 self.breaksviewer.select() | |
| 203 else: | |
| 204 self.breaksviewer = BreakpointsViewer(self) | |
| 205 | |
| 206 def togglemagic(self): | |
| 207 self.tracemagic = not self.tracemagic | |
| 208 | |
| 209 def setstate(self, state): | |
| 210 self.w.panes.bottom.tracingmonitor.reset() | |
| 211 self.w.panes.bottom.state.set(self.reason) | |
| 212 buttons = self.w.panes.bottom.buttons | |
| 213 if state == 'stopped': | |
| 214 buttons.runbutton.enable(1) | |
| 215 buttons.stopbutton.enable(0) | |
| 216 buttons.killbutton.enable(1) | |
| 217 buttons.stepbutton.enable(1) | |
| 218 buttons.stepinbutton.enable(1) | |
| 219 buttons.stepoutbutton.enable(1) | |
| 220 elif state == 'running': | |
| 221 buttons.runbutton.enable(0) | |
| 222 buttons.stopbutton.enable(1) | |
| 223 buttons.killbutton.enable(1) | |
| 224 buttons.stepbutton.enable(0) | |
| 225 buttons.stepinbutton.enable(0) | |
| 226 buttons.stepoutbutton.enable(0) | |
| 227 elif state == 'idle': | |
| 228 buttons.runbutton.enable(0) | |
| 229 buttons.stopbutton.enable(0) | |
| 230 buttons.killbutton.enable(0) | |
| 231 buttons.stepbutton.enable(0) | |
| 232 buttons.stepinbutton.enable(0) | |
| 233 buttons.stepoutbutton.enable(0) | |
| 234 elif state == 'dead': | |
| 235 buttons.runbutton.enable(0) | |
| 236 buttons.stopbutton.enable(0) | |
| 237 buttons.killbutton.enable(1) | |
| 238 buttons.stepbutton.enable(0) | |
| 239 buttons.stepinbutton.enable(0) | |
| 240 buttons.stepoutbutton.enable(0) | |
| 241 else: | |
| 242 print 'unknown state:', state | |
| 243 | |
| 244 def resetwidgets(self): | |
| 245 self.reason = '' | |
| 246 self.w.panes.bottom.srctitle.set('') | |
| 247 self.w.panes.bottom.src.source.set('') | |
| 248 self.w.panes.browserpanes.stacklist.stack.set([]) | |
| 249 self.w.panes.browserpanes.locals.browser.set({}) | |
| 250 self.w.panes.browserpanes.globals.browser.set({}) | |
| 251 self.setstate('idle') | |
| 252 | |
| 253 # W callbacks | |
| 254 | |
| 255 def close(self): | |
| 256 self.set_quit() | |
| 257 self.exit_mainloop() | |
| 258 self.closed = 1 | |
| 259 | |
| 260 self.unregister_editor(self.w.panes.bottom.src.source, | |
| 261 self.w.panes.bottom.src.source.file) | |
| 262 self.horpanes = self.w.panes.getpanesizes() | |
| 263 self.verpanes = self.w.panes.browserpanes.getpanesizes() | |
| 264 self.bounds = self.w.getbounds() | |
| 265 prefs = W.getapplication().getprefs() | |
| 266 prefs.debugger.breaks = self.breaks | |
| 267 prefs.debugger.windowsettings = self.bounds, self.horpanes, self.verpanes | |
| 268 prefs.debugger.tracemagic = self.tracemagic | |
| 269 prefs.save() | |
| 270 | |
| 271 # stack list callback | |
| 272 | |
| 273 def do_stack(self, isdbl): | |
| 274 sel = self.w.panes.browserpanes.stacklist.stack.getselection() | |
| 275 if isdbl: | |
| 276 if sel: | |
| 277 frame, lineno = self.stack[sel[0] + 1] | |
| 278 filename = frame.f_code.co_filename | |
| 279 editor = self.w._parentwindow.parent.openscript(filename, lineno) | |
| 280 if self.breaks.has_key(filename): | |
| 281 editor.showbreakpoints(1) | |
| 282 else: | |
| 283 if sel and sel <> self.laststacksel: | |
| 284 self.showframe(sel[0] + 1) | |
| 285 self.laststacksel = sel | |
| 286 | |
| 287 def geteditor(self, filename): | |
| 288 if filename[:1] == '<' and filename[-1:] == '>': | |
| 289 editor = W.getapplication().getscript(filename[1:-1]) | |
| 290 else: | |
| 291 editor = W.getapplication().getscript(filename) | |
| 292 return editor | |
| 293 | |
| 294 # button callbacks | |
| 295 | |
| 296 def do_run(self): | |
| 297 self.running() | |
| 298 self.set_continue() | |
| 299 self.exit_mainloop() | |
| 300 | |
| 301 def do_stop(self): | |
| 302 self.set_step() | |
| 303 | |
| 304 def do_kill(self): | |
| 305 self.set_quit() | |
| 306 self.exit_mainloop() | |
| 307 self.resetwidgets() | |
| 308 | |
| 309 def do_step(self): | |
| 310 self.running() | |
| 311 self.set_next(self.curframe) | |
| 312 self.exit_mainloop() | |
| 313 | |
| 314 def do_stepin(self): | |
| 315 self.running() | |
| 316 self.set_step() | |
| 317 self.exit_mainloop() | |
| 318 | |
| 319 def do_stepout(self): | |
| 320 self.running() | |
| 321 self.set_return(self.curframe) | |
| 322 self.exit_mainloop() | |
| 323 | |
| 324 def running(self): | |
| 325 W.SetCursor('watch') | |
|
18167
c5ac6f055c62
Some long overdue maintainance. Made all IDE sources 7-bit-clean, to avoid any further encoding conversion troubles.
Just van Rossum <just@letterror.com>
parents:
17845
diff
changeset
|
326 self.reason = 'Running\xc9' |
| 10047 | 327 self.setstate('running') |
| 328 #self.w.panes.bottom.src.source.set('') | |
| 329 #self.w.panes.browserpanes.stacklist.stack.set([]) | |
| 330 #self.w.panes.browserpanes.locals.browser.set({}) | |
| 331 #self.w.panes.browserpanes.globals.browser.set({}) | |
| 332 | |
| 333 def exit_mainloop(self): | |
| 334 self.w.parent.debugger_quitting = 1 | |
| 335 | |
| 336 # | |
| 337 | |
| 338 def showframe(self, stackindex): | |
| 339 (frame, lineno) = self.stack[stackindex] | |
| 340 W.SetCursor('watch') | |
| 341 filename = frame.f_code.co_filename | |
| 342 if filename <> self.file: | |
| 343 editor = self.geteditor(filename) | |
| 344 if editor: | |
| 345 self.w.panes.bottom.src.source.set(editor.get(), filename) | |
| 346 else: | |
| 347 try: | |
|
25238
778f7221f955
Mode rU for universal newlines, not rT. Spotted by Guido.
Jack Jansen <jack.jansen@cwi.nl>
parents:
25223
diff
changeset
|
348 f = open(filename, 'rU') |
| 10047 | 349 data = f.read() |
| 350 f.close() | |
| 351 except IOError: | |
| 352 if filename[-3:] == '.py': | |
| 353 import imp | |
| 354 modname = os.path.basename(filename)[:-3] | |
| 355 try: | |
| 356 f, filename, (suff, mode, dummy) = imp.find_module(modname) | |
| 357 except ImportError: | |
|
18167
c5ac6f055c62
Some long overdue maintainance. Made all IDE sources 7-bit-clean, to avoid any further encoding conversion troubles.
Just van Rossum <just@letterror.com>
parents:
17845
diff
changeset
|
358 self.w.panes.bottom.src.source.set("can't find file") |
| 10047 | 359 else: |
| 360 if f: | |
| 361 f.close() | |
| 362 if f and suff == '.py': | |
|
25238
778f7221f955
Mode rU for universal newlines, not rT. Spotted by Guido.
Jack Jansen <jack.jansen@cwi.nl>
parents:
25223
diff
changeset
|
363 f = open(filename, 'rU') |
| 10047 | 364 data = f.read() |
| 365 f.close() | |
| 366 self.w.panes.bottom.src.source.set(data, filename) | |
| 367 else: | |
|
18167
c5ac6f055c62
Some long overdue maintainance. Made all IDE sources 7-bit-clean, to avoid any further encoding conversion troubles.
Just van Rossum <just@letterror.com>
parents:
17845
diff
changeset
|
368 self.w.panes.bottom.src.source.set("can't find file") |
| 10047 | 369 else: |
|
18167
c5ac6f055c62
Some long overdue maintainance. Made all IDE sources 7-bit-clean, to avoid any further encoding conversion troubles.
Just van Rossum <just@letterror.com>
parents:
17845
diff
changeset
|
370 self.w.panes.bottom.src.source.set("can't find file") |
| 10047 | 371 else: |
|
25223
2b1701cd4566
The debugger source view only understood mac-style linefeeds. Fixed.
Jack Jansen <jack.jansen@cwi.nl>
parents:
21772
diff
changeset
|
372 data = data.replace('\n', '\r') |
| 10047 | 373 self.w.panes.bottom.src.source.set(data, filename) |
| 374 self.file = filename | |
| 375 self.w.panes.bottom.srctitle.set('Source: ' + filename + ((lineno > 0) and (' (line %d)' % lineno) or ' ')) | |
| 376 self.goto_line(lineno) | |
| 377 self.lineno = lineno | |
| 378 self.showvars((frame, lineno)) | |
| 379 | |
| 380 def showvars(self, (frame, lineno)): | |
| 381 if frame.f_locals is not frame.f_globals: | |
| 382 locals = frame.f_locals | |
| 383 else: | |
| 384 locals = {'Same as Globals':''} | |
| 385 filteredlocals = {} | |
| 386 for key, value in locals.items(): | |
| 387 # empty key is magic for Python 1.4; '.' is magic for 1.5... | |
| 388 if not key or key[0] <> '.': | |
| 389 filteredlocals[key] = value | |
| 390 self.w.panes.browserpanes.locals.browser.set(filteredlocals) | |
| 391 self.w.panes.browserpanes.globals.browser.set(frame.f_globals) | |
| 392 | |
| 393 def showstack(self, stackindex): | |
| 394 stack = [] | |
| 395 for frame, lineno in self.stack[1:]: | |
| 396 filename = frame.f_code.co_filename | |
| 397 try: | |
| 398 filename = _filenames[filename] | |
| 399 except KeyError: | |
| 400 if filename[:1] + filename[-1:] <> '<>': | |
| 401 filename = os.path.basename(filename) | |
| 402 _filenames[frame.f_code.co_filename] = filename | |
| 403 funcname = frame.f_code.co_name | |
| 404 if funcname == '?': | |
| 405 funcname = '<toplevel>' | |
| 406 stack.append(filename + ': ' + funcname) | |
| 407 if stack <> self.laststack: | |
| 408 self.w.panes.browserpanes.stacklist.stack.set(stack) | |
| 409 self.laststack = stack | |
| 410 sel = [stackindex - 1] | |
| 411 self.w.panes.browserpanes.stacklist.stack.setselection(sel) | |
| 412 self.laststacksel = sel | |
| 413 | |
| 414 def goto_line(self, lineno): | |
| 415 if lineno > 0: | |
| 416 self.w.panes.bottom.src.source.selectline(lineno - 1) | |
| 417 else: | |
| 418 self.w.panes.bottom.src.source.setselection(0, 0) | |
| 419 | |
| 420 # bdb entry points | |
| 421 | |
| 422 # def user_call(self, frame, argument_list): | |
| 423 # self.reason = 'Calling' | |
| 424 # self.interaction(frame, None) | |
| 425 | |
| 426 def user_line(self, frame): | |
| 427 # This function is called when we stop or break at this line | |
| 428 self.reason = 'Stopped' | |
| 429 self.interaction(frame, None) | |
| 430 | |
| 431 def user_return(self, frame, return_value): | |
| 432 # This function is called when a return trap is set here | |
| 433 fname = frame.f_code.co_name | |
| 434 if fname <> '?': | |
| 435 self.reason = 'Returning from %s()' % frame.f_code.co_name | |
| 436 frame.f_locals['__return__'] = return_value | |
| 437 elif frame.f_back is self.botframe: | |
| 438 self.reason = 'Done' | |
| 439 else: | |
| 440 self.reason = 'Returning' | |
| 441 self.interaction(frame, None, 1) | |
| 442 | |
| 443 def user_exception(self, frame, (exc_type, exc_value, exc_traceback)): | |
| 444 # This function is called when we stop or break at this line | |
| 445 self.reason = self.formatexception(exc_type, exc_value) | |
| 446 self.interaction(frame, exc_traceback) | |
| 447 | |
| 448 def formatexception(self, exc_type, exc_value): | |
| 449 if exc_type == SyntaxError: | |
| 450 try: | |
| 451 value, (filename, lineno, charno, line) = exc_value | |
| 452 except: | |
| 453 pass | |
| 454 else: | |
| 455 return str(exc_type) + ': ' + str(value) | |
| 456 if type(exc_type) == types.ClassType: | |
| 457 nice = exc_type.__name__ | |
| 458 else: | |
| 459 nice = str(exc_type) | |
| 460 value = str(exc_value) | |
| 461 if exc_value and value: | |
| 462 nice = nice + ": " + value | |
| 463 return nice | |
| 464 | |
| 465 def forget(self): | |
| 466 self.stack = [] | |
| 467 self.curindex = 0 | |
| 468 self.curframe = None | |
| 469 | |
| 470 def setup(self, f, t, isreturning = 0): | |
| 471 self.forget() | |
| 472 self.stack, self.curindex = self.get_stack(f, t) | |
| 473 self.curframe = self.stack[self.curindex - isreturning][0] | |
| 474 | |
| 475 def interaction(self, frame, traceback, isreturning = 0): | |
| 476 saveport = Qd.GetPort() | |
| 477 self.w.select() | |
| 478 try: | |
| 479 self.setup(frame, traceback, isreturning) | |
| 480 self.setstate('stopped') | |
| 481 stackindex = self.curindex | |
| 482 if isreturning: | |
| 483 if frame.f_back is not self.botframe: | |
| 484 stackindex = stackindex - 1 | |
| 485 self.showstack(stackindex) | |
| 486 self.showframe(stackindex) | |
| 487 self.w.parent.debugger_mainloop() | |
| 488 self.forget() | |
| 489 finally: | |
| 490 Qd.SetPort(saveport) | |
| 491 | |
| 492 # bdb customization | |
| 493 | |
| 494 def trace_dispatch(self, frame, event, arg, TickCount = Evt.TickCount): | |
| 495 if TickCount() - self.tracingmonitortime > 15: | |
| 496 self.tracingmonitortime = TickCount() | |
| 497 self.w.panes.bottom.tracingmonitor.toggle() | |
| 498 try: | |
| 499 try: | |
|
21772
ec750e37671b
Changes by Donovan Preston (and a few minor ones by me) to make IDE run under
Jack Jansen <jack.jansen@cwi.nl>
parents:
21013
diff
changeset
|
500 if hasattr(MacOS, 'EnableAppswitch'): |
|
ec750e37671b
Changes by Donovan Preston (and a few minor ones by me) to make IDE run under
Jack Jansen <jack.jansen@cwi.nl>
parents:
21013
diff
changeset
|
501 MacOS.EnableAppswitch(0) |
| 10047 | 502 if self.quitting: |
| 503 # returning None is not enough, a former BdbQuit exception | |
| 504 # might have been eaten by the print statement | |
| 505 raise bdb.BdbQuit | |
| 506 if event == 'line': | |
| 507 return self.dispatch_line(frame) | |
| 508 if event == 'call': | |
| 509 return self.dispatch_call(frame, arg) | |
| 510 if event == 'return': | |
| 511 return self.dispatch_return(frame, arg) | |
| 512 if event == 'exception': | |
| 513 return self.dispatch_exception(frame, arg) | |
| 514 print 'bdb.Bdb.dispatch: unknown debugging event:', `event` | |
| 515 return self.trace_dispatch | |
| 516 finally: | |
|
21772
ec750e37671b
Changes by Donovan Preston (and a few minor ones by me) to make IDE run under
Jack Jansen <jack.jansen@cwi.nl>
parents:
21013
diff
changeset
|
517 if hasattr(MacOS, 'EnableAppswitch'): |
|
ec750e37671b
Changes by Donovan Preston (and a few minor ones by me) to make IDE run under
Jack Jansen <jack.jansen@cwi.nl>
parents:
21013
diff
changeset
|
518 MacOS.EnableAppswitch(-1) |
| 10047 | 519 except KeyboardInterrupt: |
| 520 self.set_step() | |
| 521 return self.trace_dispatch | |
| 522 except bdb.BdbQuit: | |
| 523 if self.continuewithoutdebugger: | |
| 524 self.clear_tracefuncs() | |
| 525 return | |
| 526 else: | |
| 527 raise bdb.BdbQuit | |
| 528 except: | |
| 529 print 'XXX Exception during debugger interaction.', \ | |
| 530 self.formatexception(sys.exc_type, sys.exc_value) | |
| 531 import traceback | |
| 532 traceback.print_exc() | |
| 533 return self.trace_dispatch | |
| 534 | |
| 535 def dispatch_call(self, frame, arg): | |
| 536 if not self.tracemagic and \ | |
| 537 frame.f_code.co_name[:2] == '__' == frame.f_code.co_name[-2:] and \ | |
| 538 frame.f_code.co_name <> '__init__': | |
| 539 return | |
| 540 if self.botframe is None: | |
| 541 # First call of dispatch since reset() | |
| 542 self.botframe = frame.f_back # xxx !!! added f_back | |
| 543 return self.trace_dispatch | |
| 544 if not (self.stop_here(frame) or self.break_anywhere(frame)): | |
| 545 # No need to trace this function | |
| 546 return # None | |
| 547 self.user_call(frame, arg) | |
| 548 if self.quitting: | |
| 549 raise bdb.BdbQuit | |
| 550 return self.trace_dispatch | |
| 551 | |
| 552 def set_continue(self): | |
| 553 # Don't stop except at breakpoints or when finished | |
| 554 self.stopframe = self.botframe | |
| 555 self.returnframe = None | |
| 556 self.quitting = 0 | |
| 557 # unlike in bdb/pdb, there's a chance that breakpoints change | |
| 558 # *while* a program (this program ;-) is running. It's actually quite likely. | |
| 559 # So we don't delete frame.f_trace until the bottom frame if there are no breakpoints. | |
| 560 | |
| 561 def set_break(self, filename, lineno): | |
| 562 if not self.breaks.has_key(filename): | |
| 563 self.breaks[filename] = [] | |
| 564 list = self.breaks[filename] | |
| 565 if lineno in list: | |
| 566 return 'There is already a breakpoint there!' | |
| 567 list.append(lineno) | |
| 568 list.sort() # I want to keep them neatly sorted; easier for drawing | |
| 569 if hasattr(bdb, "Breakpoint"): | |
| 570 # 1.5.2b1 specific | |
| 571 bp = bdb.Breakpoint(filename, lineno, 0, None) | |
| 572 self.update_breaks(filename) | |
| 573 | |
| 574 def clear_break(self, filename, lineno): | |
| 575 bdb.Bdb.clear_break(self, filename, lineno) | |
| 576 self.update_breaks(filename) | |
| 577 | |
| 578 def clear_all_file_breaks(self, filename): | |
| 579 bdb.Bdb.clear_all_file_breaks(self, filename) | |
| 580 self.update_breaks(filename) | |
| 581 | |
| 582 def clear_all_breaks(self): | |
| 583 bdb.Bdb.clear_all_breaks(self) | |
| 584 for editors in self.editors.values(): | |
| 585 for editor in editors: | |
| 586 editor.drawbreakpoints() | |
| 587 | |
| 588 # special | |
| 589 | |
| 590 def toggle_break(self, filename, lineno): | |
| 591 if self.get_break(filename, lineno): | |
| 592 self.clear_break(filename, lineno) | |
| 593 else: | |
| 594 self.set_break(filename, lineno) | |
| 595 | |
| 596 def clear_breaks_above(self, filename, above): | |
| 597 if not self.breaks.has_key(filename): | |
| 598 return 'There are no breakpoints in that file!' | |
| 599 for lineno in self.breaks[filename][:]: | |
| 600 if lineno > above: | |
| 601 self.breaks[filename].remove(lineno) | |
| 602 if not self.breaks[filename]: | |
| 603 del self.breaks[filename] | |
| 604 | |
| 605 # editor stuff | |
| 606 | |
| 607 def update_breaks(self, filename): | |
| 608 if self.breaksviewer: | |
| 609 self.breaksviewer.update() | |
| 610 if self.editors.has_key(filename): | |
| 611 for editor in self.editors[filename]: | |
| 612 if editor._debugger: # XXX | |
| 613 editor.drawbreakpoints() | |
| 614 else: | |
| 615 print 'xxx dead editor!' | |
| 616 | |
| 617 def update_allbreaks(self): | |
| 618 if self.breaksviewer: | |
| 619 self.breaksviewer.update() | |
| 620 for filename in self.breaks.keys(): | |
| 621 if self.editors.has_key(filename): | |
| 622 for editor in self.editors[filename]: | |
| 623 if editor._debugger: # XXX | |
| 624 editor.drawbreakpoints() | |
| 625 else: | |
| 626 print 'xxx dead editor!' | |
| 627 | |
| 628 def register_editor(self, editor, filename): | |
| 629 if not filename: | |
| 630 return | |
| 631 if not self.editors.has_key(filename): | |
| 632 self.editors[filename] = [editor] | |
| 633 elif editor not in self.editors[filename]: | |
| 634 self.editors[filename].append(editor) | |
| 635 | |
| 636 def unregister_editor(self, editor, filename): | |
| 637 if not filename: | |
| 638 return | |
| 639 try: | |
| 640 self.editors[filename].remove(editor) | |
| 641 if not self.editors[filename]: | |
| 642 del self.editors[filename] | |
| 643 # if this was an untitled window, clear the breaks. | |
| 644 if filename[:1] == '<' and filename[-1:] == '>' and \ | |
| 645 self.breaks.has_key(filename): | |
| 646 self.clear_all_file_breaks(filename) | |
| 647 except (KeyError, ValueError): | |
| 648 pass | |
| 649 | |
| 650 | |
| 651 class SourceViewer(W.PyEditor): | |
| 652 | |
| 653 def __init__(self, *args, **kwargs): | |
| 654 apply(W.PyEditor.__init__, (self,) + args, kwargs) | |
| 655 self.bind('<click>', self.clickintercept) | |
| 656 | |
| 657 def clickintercept(self, point, modifiers): | |
| 658 if self._parentwindow._currentwidget <> self and not self.pt_in_breaks(point): | |
| 659 self._parentwindow.xxx___select(self) | |
| 660 return 1 | |
| 661 | |
| 662 def _getviewrect(self): | |
| 663 l, t, r, b = self._bounds | |
| 664 if self._debugger: | |
| 665 return (l + 12, t + 2, r - 1, b - 2) | |
| 666 else: | |
| 667 return (l + 5, t + 2, r - 1, b - 2) | |
| 668 | |
| 669 def select(self, onoff, isclick = 0): | |
| 670 if W.SelectableWidget.select(self, onoff): | |
| 671 return | |
| 672 self.SetPort() | |
| 673 #if onoff: | |
| 674 # self.ted.WEActivate() | |
| 675 #else: | |
| 676 # self.ted.WEDeactivate() | |
| 677 self.drawselframe(onoff) | |
| 678 | |
| 679 def drawselframe(self, onoff): | |
| 680 pass | |
| 681 | |
| 682 | |
| 683 class BreakpointsViewer: | |
| 684 | |
| 685 def __init__(self, debugger): | |
| 686 self.debugger = debugger | |
| 687 self.w = W.Window((300, 250), 'Breakpoints', minsize = (200, 200)) | |
| 688 self.w.panes = W.HorizontalPanes((8, 8, -8, -32), (0.3, 0.7)) | |
| 689 self.w.panes.files = W.List(None, callback = self.filehit) #, flags = Lists.lOnlyOne) | |
| 690 self.w.panes.gr = W.Group(None) | |
| 691 self.w.panes.gr.breaks = W.List((0, 0, -130, 0), callback = self.linehit) #, flags = Lists.lOnlyOne) | |
|
18167
c5ac6f055c62
Some long overdue maintainance. Made all IDE sources 7-bit-clean, to avoid any further encoding conversion troubles.
Just van Rossum <just@letterror.com>
parents:
17845
diff
changeset
|
692 self.w.panes.gr.openbutton = W.Button((-80, 4, 0, 16), 'View\xc9', self.openbuttonhit) |
| 10047 | 693 self.w.panes.gr.deletebutton = W.Button((-80, 28, 0, 16), 'Delete', self.deletebuttonhit) |
| 694 | |
| 695 self.w.bind('<close>', self.close) | |
| 696 self.w.bind('backspace', self.w.panes.gr.deletebutton.push) | |
| 697 | |
| 698 self.setup() | |
| 699 self.w.open() | |
| 700 self.w.panes.gr.openbutton.enable(0) | |
| 701 self.w.panes.gr.deletebutton.enable(0) | |
| 702 self.curfile = None | |
| 703 | |
| 704 def deletebuttonhit(self): | |
| 705 if self.w._currentwidget == self.w.panes.files: | |
| 706 self.del_filename() | |
| 707 else: | |
| 708 self.del_number() | |
| 709 self.checkbuttons() | |
| 710 | |
| 711 def del_number(self): | |
| 712 if self.curfile is None: | |
| 713 return | |
| 714 sel = self.w.panes.gr.breaks.getselectedobjects() | |
| 715 for lineno in sel: | |
| 716 self.debugger.clear_break(self.curfile, lineno) | |
| 717 | |
| 718 def del_filename(self): | |
| 719 sel = self.w.panes.files.getselectedobjects() | |
| 720 for filename in sel: | |
| 721 self.debugger.clear_all_file_breaks(filename) | |
| 722 self.debugger.update_allbreaks() | |
| 723 | |
| 724 def setup(self): | |
| 725 files = self.debugger.breaks.keys() | |
| 726 files.sort() | |
| 727 self.w.panes.files.set(files) | |
| 728 | |
| 729 def close(self): | |
| 730 self.debugger.breaksviewer = None | |
| 731 self.debugger = None | |
| 732 | |
| 733 def update(self): | |
| 734 sel = self.w.panes.files.getselectedobjects() | |
| 735 self.setup() | |
| 736 self.w.panes.files.setselectedobjects(sel) | |
| 737 sel = self.w.panes.files.getselection() | |
| 738 if len(sel) == 0 and self.curfile: | |
| 739 self.w.panes.files.setselectedobjects([self.curfile]) | |
| 740 self.filehit(0) | |
| 741 | |
| 742 def select(self): | |
| 743 self.w.select() | |
| 744 | |
| 745 def selectfile(self, file): | |
| 746 self.w.panes.files.setselectedobjects([file]) | |
| 747 self.filehit(0) | |
| 748 | |
| 749 def openbuttonhit(self): | |
| 750 self.filehit(1) | |
| 751 | |
| 752 def filehit(self, isdbl): | |
| 753 sel = self.w.panes.files.getselectedobjects() | |
| 754 if isdbl: | |
| 755 for filename in sel: | |
| 756 lineno = None | |
| 757 if filename == self.curfile: | |
| 758 linesel = self.w.panes.gr.breaks.getselectedobjects() | |
| 759 if linesel: | |
| 760 lineno = linesel[-1] | |
| 761 elif self.w.panes.gr.breaks: | |
| 762 lineno = self.w.panes.gr.breaks[0] | |
| 763 editor = self.w._parentwindow.parent.openscript(filename, lineno) | |
| 764 editor.showbreakpoints(1) | |
| 765 return | |
| 766 if len(sel) == 1: | |
| 767 file = sel[0] | |
| 768 filebreaks = self.debugger.breaks[file][:] | |
| 769 if self.curfile == file: | |
| 770 linesel = self.w.panes.gr.breaks.getselectedobjects() | |
| 771 self.w.panes.gr.breaks.set(filebreaks) | |
| 772 if self.curfile == file: | |
| 773 self.w.panes.gr.breaks.setselectedobjects(linesel) | |
| 774 self.curfile = file | |
| 775 else: | |
| 776 if len(sel) <> 0: | |
| 777 self.curfile = None | |
| 778 self.w.panes.gr.breaks.set([]) | |
| 779 self.checkbuttons() | |
| 780 | |
| 781 def linehit(self, isdbl): | |
| 782 if isdbl: | |
| 783 files = self.w.panes.files.getselectedobjects() | |
| 784 if len(files) <> 1: | |
| 785 return | |
| 786 filename = files[0] | |
| 787 linenos = self.w.panes.gr.breaks.getselectedobjects() | |
| 788 if not linenos: | |
| 789 return | |
| 790 lineno = linenos[-1] | |
| 791 editor = self.w._parentwindow.parent.openscript(filename, lineno) | |
| 792 editor.showbreakpoints(1) | |
| 793 self.checkbuttons() | |
| 794 | |
| 795 def checkbuttons(self): | |
| 796 if self.w.panes.files.getselection(): | |
| 797 self.w.panes.gr.openbutton.enable(1) | |
| 798 self.w._parentwindow.setdefaultbutton(self.w.panes.gr.openbutton) | |
| 799 if self.w._currentwidget == self.w.panes.files: | |
| 800 if self.w.panes.files.getselection(): | |
| 801 self.w.panes.gr.deletebutton.enable(1) | |
| 802 else: | |
| 803 self.w.panes.gr.deletebutton.enable(0) | |
| 804 else: | |
| 805 if self.w.panes.gr.breaks.getselection(): | |
| 806 self.w.panes.gr.deletebutton.enable(1) | |
| 807 else: | |
| 808 self.w.panes.gr.deletebutton.enable(0) | |
| 809 else: | |
| 810 self.w.panes.gr.openbutton.enable(0) | |
| 811 self.w.panes.gr.deletebutton.enable(0) | |
| 812 | |
| 813 | |
| 814 class TracingMonitor(W.Widget): | |
| 815 | |
| 816 def __init__(self, *args, **kwargs): | |
| 817 apply(W.Widget.__init__, (self,) + args, kwargs) | |
| 818 self.state = 0 | |
| 819 | |
| 820 def toggle(self): | |
| 821 if hasattr(self, "_parentwindow") and self._parentwindow is not None: | |
| 822 self.state = self.state % 2 + 1 | |
| 823 port = Qd.GetPort() | |
| 824 self.SetPort() | |
| 825 self.draw() | |
| 826 Qd.SetPort(port) | |
| 827 | |
| 828 def reset(self): | |
| 829 if self._parentwindow: | |
| 830 self.state = 0 | |
| 831 port = Qd.GetPort() | |
| 832 self.SetPort() | |
| 833 self.draw() | |
| 834 Qd.SetPort(port) | |
| 835 | |
| 836 def draw(self, visRgn = None): | |
| 837 if self.state == 2: | |
| 838 Qd.PaintOval(self._bounds) | |
| 839 else: | |
| 840 Qd.EraseOval(self._bounds) | |
| 841 | |
| 842 | |
| 843 # convenience funcs | |
| 844 | |
| 845 def postmortem(exc_type, exc_value, tb): | |
| 846 d = getdebugger() | |
| 847 d.postmortem(exc_type, exc_value, tb) | |
| 848 | |
| 849 def start(bottomframe = None): | |
| 850 d = getdebugger() | |
| 851 d.start(bottomframe) | |
| 852 | |
| 853 def startfromhere(): | |
| 854 d = getdebugger() | |
| 855 try: | |
| 856 raise 'spam' | |
| 857 except: | |
| 858 frame = sys.exc_traceback.tb_frame.f_back | |
| 859 d.start(frame) | |
| 860 | |
| 861 def startfrombottom(): | |
| 862 d = getdebugger() | |
| 863 d.start(_getbottomframe(), 1) | |
| 864 | |
| 865 def stop(): | |
| 866 d = getdebugger() | |
| 867 d.stop() | |
| 868 | |
| 869 def cont(): | |
| 870 sys.settrace(None) | |
| 871 d = getdebugger() | |
| 872 d.set_continue_without_debugger() | |
| 873 | |
| 874 def _getbottomframe(): | |
| 875 try: | |
| 876 raise 'spam' | |
| 877 except: | |
| 878 pass | |
| 879 frame = sys.exc_traceback.tb_frame | |
| 880 while 1: | |
| 881 if frame.f_code.co_name == 'mainloop' or frame.f_back is None: | |
| 882 break | |
| 883 frame = frame.f_back | |
| 884 return frame | |
| 885 | |
| 886 _debugger = None | |
| 887 | |
| 888 def getdebugger(): | |
| 889 if not __debug__: | |
|
18167
c5ac6f055c62
Some long overdue maintainance. Made all IDE sources 7-bit-clean, to avoid any further encoding conversion troubles.
Just van Rossum <just@letterror.com>
parents:
17845
diff
changeset
|
890 raise W.AlertError, "Can't debug in \"Optimize bytecode\" mode.\r(see \"Default startup options\" in EditPythonPreferences)" |
| 10047 | 891 global _debugger |
| 892 if _debugger is None: | |
| 893 _debugger = Debugger() | |
| 894 return _debugger |
