cpython/Mac/Tools/IDE/PyDebugger.py

888 lines
25 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import sys
import bdb
import types
import os
import W
import WASTEconst
import PyBrowser
import Qd
import Evt
import Lists
import MacOS
_filenames = {}
SIMPLE_TYPES = (
types.NoneType,
types.IntType,
types.LongType,
types.FloatType,
types.ComplexType,
types.StringType
)
class Debugger(bdb.Bdb):
def __init__(self, title = 'Debugger'):
bdb.Bdb.__init__(self)
self.closed = 1
self.title = title
self.breaksviewer = None
self.reset()
self.tracing = 0
self.tracingmonitortime = Evt.TickCount()
self.editors = {}
prefs = W.getapplication().getprefs()
if prefs.debugger:
for file, breaks in prefs.debugger.breaks.items():
for b in breaks:
self.set_break(file, b)
self.bounds, self.horpanes, self.verpanes = prefs.debugger.windowsettings
self.tracemagic = prefs.debugger.tracemagic
else:
self.breaks = {}
self.horpanes = (0.4, 0.6)
self.verpanes = (0.3, 0.35, 0.35)
self.bounds = (600, 400)
self.tracemagic = 0
self.laststacksel = None
def reset(self):
self.currentframe = None
self.file = None
self.laststack = None
self.reason = 'Not running'
self.continuewithoutdebugger = 0
bdb.Bdb.reset(self)
self.forget()
def start(self, bottomframe = None, running = 0):
W.getapplication().DebuggerQuit = bdb.BdbQuit
import Menu
Menu.HiliteMenu(0)
if self.closed:
self.setupwidgets(self.title)
self.closed = 0
if not self.w.parent.debugger_quitting:
self.w.select()
raise W.AlertError, 'There is another debugger session busy.'
self.reset()
self.botframe = bottomframe
if running:
self.set_continue()
self.reason = 'Runningƒ'
self.setstate('running')
else:
self.set_step()
self.reason = 'stopped'
self.setstate('stopped')
sys.settrace(self.trace_dispatch)
def stop(self):
self.set_quit()
if self.w.parent:
self.exit_mainloop()
self.resetwidgets()
def set_continue_without_debugger(self):
sys.settrace(None)
self.set_quit()
self.clear_tracefuncs()
self.continuewithoutdebugger = 1
if hasattr(self, "w") and self.w.parent:
self.exit_mainloop()
self.resetwidgets()
def clear_tracefuncs(self):
try:
raise 'spam'
except:
pass
frame = sys.exc_traceback.tb_frame
while frame is not None:
del frame.f_trace
frame = frame.f_back
def postmortem(self, exc_type, exc_value, traceback):
if self.closed:
self.setupwidgets(self.title)
self.closed = 0
if not self.w.parent.debugger_quitting:
raise W.AlertError, 'There is another debugger session busy.'
self.reset()
if traceback:
self.botframe = traceback.tb_frame
while traceback.tb_next <> None:
traceback = traceback.tb_next
frame = traceback.tb_frame
else:
self.botframe = None
frame = None
self.w.panes.bottom.buttons.killbutton.enable(1)
self.reason = '(dead) ' + self.formatexception(exc_type, exc_value)
self.w.select()
self.setup(frame, traceback)
self.setstate('dead')
self.showstack(self.curindex)
self.showframe(self.curindex)
def setupwidgets(self, title):
self.w = w = W.Window(self.bounds, title, minsize = (500, 300))
w.panes = W.HorizontalPanes((8, 4, -8, -8), self.horpanes)
w.panes.browserpanes = browserpanes = W.VerticalPanes(None, self.verpanes)
browserpanes.stacklist = W.Group(None)
browserpanes.stacklist.title = W.TextBox((4, 0, 0, 12), 'Stack')
browserpanes.stacklist.stack = W.List((0, 16, 0, 0), callback = self.do_stack, flags = Lists.lOnlyOne)
browserpanes.locals = W.Group(None)
browserpanes.locals.title = W.TextBox((4, 0, 0, 12), 'Local variables')
browserpanes.locals.browser = PyBrowser.BrowserWidget((0, 16, 0, 0))
browserpanes.globals = W.Group(None)
browserpanes.globals.title = W.TextBox((4, 0, 0, 12), 'Global variables')
browserpanes.globals.browser = PyBrowser.BrowserWidget((0, 16, 0, 0))
w.panes.bottom = bottom = W.Group(None)
bottom.src = src = W.Group((0, 52, 0, 0))
source = SourceViewer((1, 1, -15, -15), readonly = 1, debugger = self)
src.optionsmenu = W.PopupMenu((-16, 0, 16, 16), [])
src.optionsmenu.bind('<click>', self.makeoptionsmenu)
src._barx = W.Scrollbar((0, -16, -15, 16), source.hscroll, max = 32767)
src._bary = W.Scrollbar((-16, 15, 16, -15), source.vscroll, max = 32767)
src.source = source
src.frame = W.Frame((0, 0, -15, -15))
bottom.tracingmonitor = TracingMonitor((0, 23, 6, 6))
bottom.state = W.TextBox((12, 20, 0, 16), self.reason)
bottom.srctitle = W.TextBox((12, 36, 0, 14))
bottom.buttons = buttons = W.Group((12, 0, 0, 16))
buttons.runbutton = W.Button((0, 0, 50, 16), "Run", self.do_run)
buttons.stopbutton = W.Button((58, 0, 50, 16), "Stop", self.do_stop)
buttons.killbutton = W.Button((116, 0, 50, 16), "Kill", self.do_kill)
buttons.line = W.VerticalLine((173, 0, 0, 0))
buttons.stepbutton = W.Button((181, 0, 50, 16), "Step", self.do_step)
buttons.stepinbutton = W.Button((239, 0, 50, 16), "Step in", self.do_stepin)
buttons.stepoutbutton = W.Button((297, 0, 50, 16), "Step out", self.do_stepout)
w.bind('cmdr', buttons.runbutton.push)
w.bind('cmd.', buttons.stopbutton.push)
w.bind('cmdk', buttons.killbutton.push)
w.bind('cmds', buttons.stepbutton.push)
w.bind('cmdt', buttons.stepinbutton.push)
w.bind('cmdu', buttons.stepoutbutton.push)
w.bind('<close>', self.close)
w.open()
w.xxx___select(w.panes.bottom.src.source)
def makeoptionsmenu(self):
options = [('Clear breakpoints', self.w.panes.bottom.src.source.clearbreakpoints),
('Clear all breakpoints', self.clear_all_breaks),
('Edit breakpointsƒ', self.edit_breaks), '-',
(self.tracemagic and
'Disable __magic__ tracing' or 'Enable __magic__ tracing', self.togglemagic)]
self.w.panes.bottom.src.optionsmenu.set(options)
def edit_breaks(self):
if self.breaksviewer:
self.breaksviewer.select()
else:
self.breaksviewer = BreakpointsViewer(self)
def togglemagic(self):
self.tracemagic = not self.tracemagic
def setstate(self, state):
self.w.panes.bottom.tracingmonitor.reset()
self.w.panes.bottom.state.set(self.reason)
buttons = self.w.panes.bottom.buttons
if state == 'stopped':
buttons.runbutton.enable(1)
buttons.stopbutton.enable(0)
buttons.killbutton.enable(1)
buttons.stepbutton.enable(1)
buttons.stepinbutton.enable(1)
buttons.stepoutbutton.enable(1)
elif state == 'running':
buttons.runbutton.enable(0)
buttons.stopbutton.enable(1)
buttons.killbutton.enable(1)
buttons.stepbutton.enable(0)
buttons.stepinbutton.enable(0)
buttons.stepoutbutton.enable(0)
elif state == 'idle':
buttons.runbutton.enable(0)
buttons.stopbutton.enable(0)
buttons.killbutton.enable(0)
buttons.stepbutton.enable(0)
buttons.stepinbutton.enable(0)
buttons.stepoutbutton.enable(0)
elif state == 'dead':
buttons.runbutton.enable(0)
buttons.stopbutton.enable(0)
buttons.killbutton.enable(1)
buttons.stepbutton.enable(0)
buttons.stepinbutton.enable(0)
buttons.stepoutbutton.enable(0)
else:
print 'unknown state:', state
def resetwidgets(self):
self.reason = ''
self.w.panes.bottom.srctitle.set('')
self.w.panes.bottom.src.source.set('')
self.w.panes.browserpanes.stacklist.stack.set([])
self.w.panes.browserpanes.locals.browser.set({})
self.w.panes.browserpanes.globals.browser.set({})
self.setstate('idle')
# W callbacks
def close(self):
self.set_quit()
self.exit_mainloop()
self.closed = 1
self.unregister_editor(self.w.panes.bottom.src.source,
self.w.panes.bottom.src.source.file)
self.horpanes = self.w.panes.getpanesizes()
self.verpanes = self.w.panes.browserpanes.getpanesizes()
self.bounds = self.w.getbounds()
prefs = W.getapplication().getprefs()
prefs.debugger.breaks = self.breaks
prefs.debugger.windowsettings = self.bounds, self.horpanes, self.verpanes
prefs.debugger.tracemagic = self.tracemagic
prefs.save()
# stack list callback
def do_stack(self, isdbl):
sel = self.w.panes.browserpanes.stacklist.stack.getselection()
if isdbl:
if sel:
frame, lineno = self.stack[sel[0] + 1]
filename = frame.f_code.co_filename
editor = self.w._parentwindow.parent.openscript(filename, lineno)
if self.breaks.has_key(filename):
editor.showbreakpoints(1)
else:
if sel and sel <> self.laststacksel:
self.showframe(sel[0] + 1)
self.laststacksel = sel
def geteditor(self, filename):
if filename[:1] == '<' and filename[-1:] == '>':
editor = W.getapplication().getscript(filename[1:-1])
else:
editor = W.getapplication().getscript(filename)
return editor
# button callbacks
def do_run(self):
self.running()
self.set_continue()
self.exit_mainloop()
def do_stop(self):
self.set_step()
def do_kill(self):
self.set_quit()
self.exit_mainloop()
self.resetwidgets()
def do_step(self):
self.running()
self.set_next(self.curframe)
self.exit_mainloop()
def do_stepin(self):
self.running()
self.set_step()
self.exit_mainloop()
def do_stepout(self):
self.running()
self.set_return(self.curframe)
self.exit_mainloop()
def running(self):
W.SetCursor('watch')
self.reason = 'Runningƒ'
self.setstate('running')
#self.w.panes.bottom.src.source.set('')
#self.w.panes.browserpanes.stacklist.stack.set([])
#self.w.panes.browserpanes.locals.browser.set({})
#self.w.panes.browserpanes.globals.browser.set({})
def exit_mainloop(self):
self.w.parent.debugger_quitting = 1
#
def showframe(self, stackindex):
(frame, lineno) = self.stack[stackindex]
W.SetCursor('watch')
filename = frame.f_code.co_filename
if filename <> self.file:
editor = self.geteditor(filename)
if editor:
self.w.panes.bottom.src.source.set(editor.get(), filename)
else:
try:
f = open(filename, 'rb')
data = f.read()
f.close()
except IOError:
if filename[-3:] == '.py':
import imp
modname = os.path.basename(filename)[:-3]
try:
f, filename, (suff, mode, dummy) = imp.find_module(modname)
except ImportError:
self.w.panes.bottom.src.source.set('canÕt find file')
else:
if f:
f.close()
if f and suff == '.py':
f = open(filename, 'rb')
data = f.read()
f.close()
self.w.panes.bottom.src.source.set(data, filename)
else:
self.w.panes.bottom.src.source.set('canÕt find file')
else:
self.w.panes.bottom.src.source.set('canÕt find file')
else:
self.w.panes.bottom.src.source.set(data, filename)
self.file = filename
self.w.panes.bottom.srctitle.set('Source: ' + filename + ((lineno > 0) and (' (line %d)' % lineno) or ' '))
self.goto_line(lineno)
self.lineno = lineno
self.showvars((frame, lineno))
def showvars(self, (frame, lineno)):
if frame.f_locals is not frame.f_globals:
locals = frame.f_locals
else:
locals = {'Same as Globals':''}
filteredlocals = {}
for key, value in locals.items():
# empty key is magic for Python 1.4; '.' is magic for 1.5...
if not key or key[0] <> '.':
filteredlocals[key] = value
self.w.panes.browserpanes.locals.browser.set(filteredlocals)
self.w.panes.browserpanes.globals.browser.set(frame.f_globals)
def showstack(self, stackindex):
stack = []
for frame, lineno in self.stack[1:]:
filename = frame.f_code.co_filename
try:
filename = _filenames[filename]
except KeyError:
if filename[:1] + filename[-1:] <> '<>':
filename = os.path.basename(filename)
_filenames[frame.f_code.co_filename] = filename
funcname = frame.f_code.co_name
if funcname == '?':
funcname = '<toplevel>'
stack.append(filename + ': ' + funcname)
if stack <> self.laststack:
self.w.panes.browserpanes.stacklist.stack.set(stack)
self.laststack = stack
sel = [stackindex - 1]
self.w.panes.browserpanes.stacklist.stack.setselection(sel)
self.laststacksel = sel
def goto_line(self, lineno):
if lineno > 0:
self.w.panes.bottom.src.source.selectline(lineno - 1)
else:
self.w.panes.bottom.src.source.setselection(0, 0)
# bdb entry points
# def user_call(self, frame, argument_list):
# self.reason = 'Calling'
# self.interaction(frame, None)
def user_line(self, frame):
# This function is called when we stop or break at this line
self.reason = 'Stopped'
self.interaction(frame, None)
def user_return(self, frame, return_value):
# This function is called when a return trap is set here
fname = frame.f_code.co_name
if fname <> '?':
self.reason = 'Returning from %s()' % frame.f_code.co_name
frame.f_locals['__return__'] = return_value
elif frame.f_back is self.botframe:
self.reason = 'Done'
else:
self.reason = 'Returning'
self.interaction(frame, None, 1)
def user_exception(self, frame, (exc_type, exc_value, exc_traceback)):
# This function is called when we stop or break at this line
self.reason = self.formatexception(exc_type, exc_value)
self.interaction(frame, exc_traceback)
def formatexception(self, exc_type, exc_value):
if exc_type == SyntaxError:
try:
value, (filename, lineno, charno, line) = exc_value
except:
pass
else:
return str(exc_type) + ': ' + str(value)
if type(exc_type) == types.ClassType:
nice = exc_type.__name__
else:
nice = str(exc_type)
value = str(exc_value)
if exc_value and value:
nice = nice + ": " + value
return nice
def forget(self):
self.stack = []
self.curindex = 0
self.curframe = None
def setup(self, f, t, isreturning = 0):
self.forget()
self.stack, self.curindex = self.get_stack(f, t)
self.curframe = self.stack[self.curindex - isreturning][0]
def interaction(self, frame, traceback, isreturning = 0):
saveport = Qd.GetPort()
self.w.select()
try:
self.setup(frame, traceback, isreturning)
self.setstate('stopped')
stackindex = self.curindex
if isreturning:
if frame.f_back is not self.botframe:
stackindex = stackindex - 1
self.showstack(stackindex)
self.showframe(stackindex)
self.w.parent.debugger_mainloop()
self.forget()
finally:
Qd.SetPort(saveport)
# bdb customization
def trace_dispatch(self, frame, event, arg, TickCount = Evt.TickCount):
if TickCount() - self.tracingmonitortime > 15:
self.tracingmonitortime = TickCount()
self.w.panes.bottom.tracingmonitor.toggle()
try:
try:
MacOS.EnableAppswitch(0)
if self.quitting:
# returning None is not enough, a former BdbQuit exception
# might have been eaten by the print statement
raise bdb.BdbQuit
if event == 'line':
return self.dispatch_line(frame)
if event == 'call':
return self.dispatch_call(frame, arg)
if event == 'return':
return self.dispatch_return(frame, arg)
if event == 'exception':
return self.dispatch_exception(frame, arg)
print 'bdb.Bdb.dispatch: unknown debugging event:', `event`
return self.trace_dispatch
finally:
MacOS.EnableAppswitch(-1)
except KeyboardInterrupt:
self.set_step()
return self.trace_dispatch
except bdb.BdbQuit:
if self.continuewithoutdebugger:
self.clear_tracefuncs()
return
else:
raise bdb.BdbQuit
except:
print 'XXX Exception during debugger interaction.', \
self.formatexception(sys.exc_type, sys.exc_value)
import traceback
traceback.print_exc()
return self.trace_dispatch
def dispatch_call(self, frame, arg):
if not self.tracemagic and \
frame.f_code.co_name[:2] == '__' == frame.f_code.co_name[-2:] and \
frame.f_code.co_name <> '__init__':
return
if self.botframe is None:
# First call of dispatch since reset()
self.botframe = frame.f_back # xxx !!! added f_back
return self.trace_dispatch
if not (self.stop_here(frame) or self.break_anywhere(frame)):
# No need to trace this function
return # None
self.user_call(frame, arg)
if self.quitting:
raise bdb.BdbQuit
return self.trace_dispatch
def set_continue(self):
# Don't stop except at breakpoints or when finished
self.stopframe = self.botframe
self.returnframe = None
self.quitting = 0
# unlike in bdb/pdb, there's a chance that breakpoints change
# *while* a program (this program ;-) is running. It's actually quite likely.
# So we don't delete frame.f_trace until the bottom frame if there are no breakpoints.
def set_break(self, filename, lineno):
if not self.breaks.has_key(filename):
self.breaks[filename] = []
list = self.breaks[filename]
if lineno in list:
return 'There is already a breakpoint there!'
list.append(lineno)
list.sort() # I want to keep them neatly sorted; easier for drawing
if hasattr(bdb, "Breakpoint"):
# 1.5.2b1 specific
bp = bdb.Breakpoint(filename, lineno, 0, None)
self.update_breaks(filename)
def clear_break(self, filename, lineno):
bdb.Bdb.clear_break(self, filename, lineno)
self.update_breaks(filename)
def clear_all_file_breaks(self, filename):
bdb.Bdb.clear_all_file_breaks(self, filename)
self.update_breaks(filename)
def clear_all_breaks(self):
bdb.Bdb.clear_all_breaks(self)
for editors in self.editors.values():
for editor in editors:
editor.drawbreakpoints()
# special
def toggle_break(self, filename, lineno):
if self.get_break(filename, lineno):
self.clear_break(filename, lineno)
else:
self.set_break(filename, lineno)
def clear_breaks_above(self, filename, above):
if not self.breaks.has_key(filename):
return 'There are no breakpoints in that file!'
for lineno in self.breaks[filename][:]:
if lineno > above:
self.breaks[filename].remove(lineno)
if not self.breaks[filename]:
del self.breaks[filename]
# editor stuff
def update_breaks(self, filename):
if self.breaksviewer:
self.breaksviewer.update()
if self.editors.has_key(filename):
for editor in self.editors[filename]:
if editor._debugger: # XXX
editor.drawbreakpoints()
else:
print 'xxx dead editor!'
def update_allbreaks(self):
if self.breaksviewer:
self.breaksviewer.update()
for filename in self.breaks.keys():
if self.editors.has_key(filename):
for editor in self.editors[filename]:
if editor._debugger: # XXX
editor.drawbreakpoints()
else:
print 'xxx dead editor!'
def register_editor(self, editor, filename):
if not filename:
return
if not self.editors.has_key(filename):
self.editors[filename] = [editor]
elif editor not in self.editors[filename]:
self.editors[filename].append(editor)
def unregister_editor(self, editor, filename):
if not filename:
return
try:
self.editors[filename].remove(editor)
if not self.editors[filename]:
del self.editors[filename]
# if this was an untitled window, clear the breaks.
if filename[:1] == '<' and filename[-1:] == '>' and \
self.breaks.has_key(filename):
self.clear_all_file_breaks(filename)
except (KeyError, ValueError):
pass
class SourceViewer(W.PyEditor):
def __init__(self, *args, **kwargs):
apply(W.PyEditor.__init__, (self,) + args, kwargs)
self.bind('<click>', self.clickintercept)
def clickintercept(self, point, modifiers):
if self._parentwindow._currentwidget <> self and not self.pt_in_breaks(point):
self._parentwindow.xxx___select(self)
return 1
def _getviewrect(self):
l, t, r, b = self._bounds
if self._debugger:
return (l + 12, t + 2, r - 1, b - 2)
else:
return (l + 5, t + 2, r - 1, b - 2)
def select(self, onoff, isclick = 0):
if W.SelectableWidget.select(self, onoff):
return
self.SetPort()
#if onoff:
# self.ted.WEActivate()
#else:
# self.ted.WEDeactivate()
self.drawselframe(onoff)
def drawselframe(self, onoff):
pass
class BreakpointsViewer:
def __init__(self, debugger):
self.debugger = debugger
import Lists
self.w = W.Window((300, 250), 'Breakpoints', minsize = (200, 200))
self.w.panes = W.HorizontalPanes((8, 8, -8, -32), (0.3, 0.7))
self.w.panes.files = W.List(None, callback = self.filehit) #, flags = Lists.lOnlyOne)
self.w.panes.gr = W.Group(None)
self.w.panes.gr.breaks = W.List((0, 0, -130, 0), callback = self.linehit) #, flags = Lists.lOnlyOne)
self.w.panes.gr.openbutton = W.Button((-80, 4, 0, 16), 'Viewƒ', self.openbuttonhit)
self.w.panes.gr.deletebutton = W.Button((-80, 28, 0, 16), 'Delete', self.deletebuttonhit)
self.w.bind('<close>', self.close)
self.w.bind('backspace', self.w.panes.gr.deletebutton.push)
self.setup()
self.w.open()
self.w.panes.gr.openbutton.enable(0)
self.w.panes.gr.deletebutton.enable(0)
self.curfile = None
def deletebuttonhit(self):
if self.w._currentwidget == self.w.panes.files:
self.del_filename()
else:
self.del_number()
self.checkbuttons()
def del_number(self):
if self.curfile is None:
return
sel = self.w.panes.gr.breaks.getselectedobjects()
for lineno in sel:
self.debugger.clear_break(self.curfile, lineno)
def del_filename(self):
sel = self.w.panes.files.getselectedobjects()
for filename in sel:
self.debugger.clear_all_file_breaks(filename)
self.debugger.update_allbreaks()
def setup(self):
files = self.debugger.breaks.keys()
files.sort()
self.w.panes.files.set(files)
def close(self):
self.debugger.breaksviewer = None
self.debugger = None
def update(self):
sel = self.w.panes.files.getselectedobjects()
self.setup()
self.w.panes.files.setselectedobjects(sel)
sel = self.w.panes.files.getselection()
if len(sel) == 0 and self.curfile:
self.w.panes.files.setselectedobjects([self.curfile])
self.filehit(0)
def select(self):
self.w.select()
def selectfile(self, file):
self.w.panes.files.setselectedobjects([file])
self.filehit(0)
def openbuttonhit(self):
self.filehit(1)
def filehit(self, isdbl):
sel = self.w.panes.files.getselectedobjects()
if isdbl:
for filename in sel:
lineno = None
if filename == self.curfile:
linesel = self.w.panes.gr.breaks.getselectedobjects()
if linesel:
lineno = linesel[-1]
elif self.w.panes.gr.breaks:
lineno = self.w.panes.gr.breaks[0]
editor = self.w._parentwindow.parent.openscript(filename, lineno)
editor.showbreakpoints(1)
return
if len(sel) == 1:
file = sel[0]
filebreaks = self.debugger.breaks[file][:]
if self.curfile == file:
linesel = self.w.panes.gr.breaks.getselectedobjects()
self.w.panes.gr.breaks.set(filebreaks)
if self.curfile == file:
self.w.panes.gr.breaks.setselectedobjects(linesel)
self.curfile = file
else:
if len(sel) <> 0:
self.curfile = None
self.w.panes.gr.breaks.set([])
self.checkbuttons()
def linehit(self, isdbl):
if isdbl:
files = self.w.panes.files.getselectedobjects()
if len(files) <> 1:
return
filename = files[0]
linenos = self.w.panes.gr.breaks.getselectedobjects()
if not linenos:
return
lineno = linenos[-1]
editor = self.w._parentwindow.parent.openscript(filename, lineno)
editor.showbreakpoints(1)
self.checkbuttons()
def checkbuttons(self):
if self.w.panes.files.getselection():
self.w.panes.gr.openbutton.enable(1)
self.w._parentwindow.setdefaultbutton(self.w.panes.gr.openbutton)
if self.w._currentwidget == self.w.panes.files:
if self.w.panes.files.getselection():
self.w.panes.gr.deletebutton.enable(1)
else:
self.w.panes.gr.deletebutton.enable(0)
else:
if self.w.panes.gr.breaks.getselection():
self.w.panes.gr.deletebutton.enable(1)
else:
self.w.panes.gr.deletebutton.enable(0)
else:
self.w.panes.gr.openbutton.enable(0)
self.w.panes.gr.deletebutton.enable(0)
class TracingMonitor(W.Widget):
def __init__(self, *args, **kwargs):
apply(W.Widget.__init__, (self,) + args, kwargs)
self.state = 0
def toggle(self):
if hasattr(self, "_parentwindow") and self._parentwindow is not None:
self.state = self.state % 2 + 1
port = Qd.GetPort()
self.SetPort()
self.draw()
Qd.SetPort(port)
def reset(self):
if self._parentwindow:
self.state = 0
port = Qd.GetPort()
self.SetPort()
self.draw()
Qd.SetPort(port)
def draw(self, visRgn = None):
if self.state == 2:
Qd.PaintOval(self._bounds)
else:
Qd.EraseOval(self._bounds)
# convenience funcs
def postmortem(exc_type, exc_value, tb):
d = getdebugger()
d.postmortem(exc_type, exc_value, tb)
def start(bottomframe = None):
d = getdebugger()
d.start(bottomframe)
def startfromhere():
d = getdebugger()
try:
raise 'spam'
except:
frame = sys.exc_traceback.tb_frame.f_back
d.start(frame)
def startfrombottom():
d = getdebugger()
d.start(_getbottomframe(), 1)
def stop():
d = getdebugger()
d.stop()
def cont():
sys.settrace(None)
d = getdebugger()
d.set_continue_without_debugger()
def _getbottomframe():
try:
raise 'spam'
except:
pass
frame = sys.exc_traceback.tb_frame
while 1:
if frame.f_code.co_name == 'mainloop' or frame.f_back is None:
break
frame = frame.f_back
return frame
_debugger = None
def getdebugger():
if not __debug__:
raise W.AlertError, "CanÕt debug in Optimize bytecode” mode.\r(see Default startup options” in EditPythonPreferences)"
global _debugger
if _debugger is None:
_debugger = Debugger()
return _debugger