1 # wdb.py -- a window-based Python debugger
4 # - don't fall out of bottom frame
8 from stdwinevents
import *
17 WdbDone
= 'wdb.WdbDone' # Exception to continue execution
20 class Wdb(bdb
.Bdb
, basewin
.BaseWindow
): # Window debugger
23 self
.sourcewindows
= {}
24 self
.framewindows
= {}
25 bdb
.Bdb
.__init
__(self
)
26 width
= WIDTH
*stdwin
.textwidth('0')
27 height
= HEIGHT
*stdwin
.lineheight()
28 stdwin
.setdefwinsize(width
, height
)
29 basewin
.BaseWindow
.__init
__(self
, '--Stack--')
33 if self
.closed
: raise RuntimeError, 'already closed'
42 for fn
in self
.sourcewindows
.keys():
43 self
.sourcewindows
[fn
].resetlineno()
45 def setup(self
, f
, t
):
47 self
.stack
, self
.curindex
= self
.get_stack(f
, t
)
48 self
.curframe
= self
.stack
[self
.curindex
][0]
49 # Build a list of current frames
51 for f
, i
in self
.stack
: cfl
.append(f
)
52 # Remove deactivated frame windows
53 for name
in self
.framewindows
.keys():
54 fw
= self
.framewindows
[name
]
55 if fw
.frame
not in cfl
: fw
.close()
56 else: fw
.refreshframe()
57 # Refresh the stack window
60 # Override Bdb methods (except user_call, for now)
62 def user_line(self
, frame
):
63 # This function is called when we stop or break at this line
64 self
.interaction(frame
, None)
66 def user_return(self
, frame
, return_value
):
67 # This function is called when a return trap is set here
68 frame
.f_locals
['__return__'] = return_value
69 self
.settitle('--Return--')
70 self
.interaction(frame
, None)
72 self
.settitle('--Stack--')
74 def user_exception(self
, frame
, (exc_type
, exc_value
, exc_traceback
)):
75 # This function is called if an exception occurs,
76 # but only if we are to stop at or just below this level
77 frame
.f_locals
['__exception__'] = exc_type
, exc_value
78 if type(exc_type
) == type(''):
79 exc_type_name
= exc_type
80 else: exc_type_name
= exc_type
.__name
__
81 self
.settitle(exc_type_name
+ ': ' + repr.repr(exc_value
))
83 self
.interaction(frame
, exc_traceback
)
85 self
.settitle('--Stack--')
89 def settitle(self
, title
):
90 self
.savetitle
= self
.win
.gettitle()
91 self
.win
.settitle(title
)
93 # General interaction function
95 def interaction(self
, frame
, traceback
):
98 self
.setup(frame
, traceback
)
105 # Functions whose name is do_X for some character X
106 # are callable directly from the keyboard.
109 if self
.curindex
== 0:
112 self
.curindex
= self
.curindex
- 1
113 self
.curframe
= self
.stack
[self
.curindex
][0]
118 if self
.curindex
+ 1 == len(self
.stack
):
121 self
.curindex
= self
.curindex
+ 1
122 self
.curframe
= self
.stack
[self
.curindex
][0]
132 self
.set_next(self
.curframe
)
137 self
.set_return(self
.curframe
)
141 def do_continue(self
):
144 do_c
= do_cont
= do_continue
152 fn
= self
.curframe
.f_code
.co_filename
153 if not self
.sourcewindows
.has_key(fn
):
156 self
.sourcewindows
[fn
] = wdbsrcwin
. \
157 DebuggerSourceWindow(self
, fn
)
161 w
= self
.sourcewindows
[fn
]
162 lineno
= self
.stack
[self
.curindex
][1]
168 name
= 'locals' + `self
.curframe`
[16:-1]
169 if self
.framewindows
.has_key(name
):
170 self
.framewindows
[name
].popup()
173 self
.framewindows
[name
] = \
174 wdbframewin
.FrameWindow(self
, \
176 self
.curframe
.f_locals
, name
)
179 def do_globalframe(self
):
180 name
= 'globals' + `self
.curframe`
[16:-1]
181 if self
.framewindows
.has_key(name
):
182 self
.framewindows
[name
].popup()
185 self
.framewindows
[name
] = \
186 wdbframewin
.FrameWindow(self
, \
188 self
.curframe
.f_globals
, name
)
189 do_g
= do_globalframe
191 # Link between the debugger and the window
193 def refreshstack(self
):
194 height
= stdwin
.lineheight() * (1 + len(self
.stack
))
195 self
.win
.setdocsize((0, height
))
196 self
.refreshall() # XXX be more subtle later
197 # Also pass the information on to the source windows
198 filename
= self
.curframe
.f_code
.co_filename
199 lineno
= self
.curframe
.f_lineno
200 for fn
in self
.sourcewindows
.keys():
201 w
= self
.sourcewindows
[fn
]
207 # The remaining methods override BaseWindow methods
211 basewin
.BaseWindow
.close(self
)
213 for key
in self
.sourcewindows
.keys():
214 self
.sourcewindows
[key
].close()
215 for key
in self
.framewindows
.keys():
216 self
.framewindows
[key
].close()
219 def char(self
, detail
):
221 func
= eval('self.do_' + detail
)
222 except (AttributeError, SyntaxError):
227 def command(self
, detail
):
230 elif detail
== WC_DOWN
:
233 def mouse_down(self
, detail
):
234 (h
, v
), clicks
, button
, mask
= detail
235 i
= v
/ stdwin
.lineheight()
236 if 0 <= i
< len(self
.stack
):
237 if i
!= self
.curindex
:
239 self
.curframe
= self
.stack
[self
.curindex
][0]
246 def draw(self
, detail
):
247 import linecache
, string
248 d
= self
.win
.begindrawing()
251 for f
, lineno
in self
.stack
:
252 fn
= f
.f_code
.co_filename
253 if f
is self
.curframe
:
257 s
= s
+ fn
+ '(' + `lineno`
+ ')'
258 s
= s
+ f
.f_code
.co_name
259 if f
.f_locals
.has_key('__args__'):
260 args
= f
.f_locals
['__args__']
262 s
= s
+ repr.repr(args
)
263 if f
.f_locals
.has_key('__return__'):
264 rv
= f
.f_locals
['__return__']
266 s
= s
+ repr.repr(rv
)
267 line
= linecache
.getline(fn
, lineno
)
268 if line
: s
= s
+ ': ' + string
.strip(line
)
270 v
= v
+ d
.lineheight()
275 # Simplified interface
277 def run(statement
, globals=None, locals=None):
279 try: x
.run(statement
, globals, locals)
282 def runeval(expression
, globals=None, locals=None):
284 try: return x
.runeval(expression
, globals, locals)
287 def runctx(statement
, globals, locals):
289 run(statement
, globals, locals)
293 try: return apply(x
.runcall
, args
)
299 # Post-Mortem interface
301 def post_mortem(traceback
):
304 x
.interaction(None, traceback
)
308 post_mortem(sys
.last_traceback
)
311 # Main program for testing
313 TESTCMD
= 'import x; x.main()'