At the release of 1.0.1.
[python/dscho.git] / Lib / pdb.py
blob64451d5f4e8c3179c84e15e579f4bbdbd79d220a
1 # pdb.py -- finally, a Python debugger!
3 # (See pdb.doc for documentation.)
5 import string
6 import sys
7 import linecache
8 import cmd
9 import bdb
10 import repr
13 class Pdb(bdb.Bdb, cmd.Cmd):
15 def __init__(self):
16 bdb.Bdb.__init__(self)
17 cmd.Cmd.__init__(self)
18 self.prompt = '(Pdb) '
20 def reset(self):
21 bdb.Bdb.reset(self)
22 self.forget()
24 def forget(self):
25 self.lineno = None
26 self.stack = []
27 self.curindex = 0
28 self.curframe = None
30 def setup(self, f, t):
31 self.forget()
32 self.stack, self.curindex = self.get_stack(f, t)
33 self.curframe = self.stack[self.curindex][0]
35 # Override Bdb methods (except user_call, for now)
37 def user_line(self, frame):
38 # This function is called when we stop or break at this line
39 self.interaction(frame, None)
41 def user_return(self, frame, return_value):
42 # This function is called when a return trap is set here
43 frame.f_locals['__return__'] = return_value
44 print '--Return--'
45 self.interaction(frame, None)
47 def user_exception(self, frame, (exc_type, exc_value, exc_traceback)):
48 # This function is called if an exception occurs,
49 # but only if we are to stop at or just below this level
50 frame.f_locals['__exception__'] = exc_type, exc_value
51 print exc_type + ':', repr.repr(exc_value)
52 self.interaction(frame, exc_traceback)
54 # General interaction function
56 def interaction(self, frame, traceback):
57 self.setup(frame, traceback)
58 self.print_stack_entry(self.stack[self.curindex])
59 self.cmdloop()
60 self.forget()
62 def default(self, line):
63 if line[:1] == '!': line = line[1:]
64 locals = self.curframe.f_locals
65 globals = self.curframe.f_globals
66 globals['__privileged__'] = 1
67 try:
68 exec(line + '\n', globals, locals)
69 except:
70 print '***', sys.exc_type + ':', sys.exc_value
72 # Command definitions, called by cmdloop()
73 # The argument is the remaining string on the command line
74 # Return true to exit from the command loop
76 do_h = cmd.Cmd.do_help
78 def do_break(self, arg):
79 if not arg:
80 print self.get_all_breaks() # XXX
81 return
82 try:
83 lineno = int(eval(arg))
84 except:
85 print '*** Error in argument:', `arg`
86 return
87 filename = self.curframe.f_code.co_filename
88 err = self.set_break(filename, lineno)
89 if err: print '***', err
90 do_b = do_break
92 def do_clear(self, arg):
93 if not arg:
94 try:
95 reply = raw_input('Clear all breaks? ')
96 except EOFError:
97 reply = 'no'
98 reply = string.lower(string.strip(reply))
99 if reply in ('y', 'yes'):
100 self.clear_all_breaks()
101 return
102 try:
103 lineno = int(eval(arg))
104 except:
105 print '*** Error in argument:', `arg`
106 return
107 filename = self.curframe.f_code.co_filename
108 err = self.clear_break(filename, lineno)
109 if err: print '***', err
110 do_cl = do_clear # 'c' is already an abbreviation for 'continue'
112 def do_where(self, arg):
113 self.print_stack_trace()
114 do_w = do_where
116 def do_up(self, arg):
117 if self.curindex == 0:
118 print '*** Oldest frame'
119 else:
120 self.curindex = self.curindex - 1
121 self.curframe = self.stack[self.curindex][0]
122 self.print_stack_entry(self.stack[self.curindex])
123 self.lineno = None
124 do_u = do_up
126 def do_down(self, arg):
127 if self.curindex + 1 == len(self.stack):
128 print '*** Newest frame'
129 else:
130 self.curindex = self.curindex + 1
131 self.curframe = self.stack[self.curindex][0]
132 self.print_stack_entry(self.stack[self.curindex])
133 self.lineno = None
134 do_d = do_down
136 def do_step(self, arg):
137 self.set_step()
138 return 1
139 do_s = do_step
141 def do_next(self, arg):
142 self.set_next(self.curframe)
143 return 1
144 do_n = do_next
146 def do_return(self, arg):
147 self.set_return(self.curframe)
148 return 1
149 do_r = do_return
151 def do_continue(self, arg):
152 self.set_continue()
153 return 1
154 do_c = do_cont = do_continue
156 def do_quit(self, arg):
157 self.set_quit()
158 return 1
159 do_q = do_quit
161 def do_args(self, arg):
162 if self.curframe.f_locals.has_key('__return__'):
163 print `self.curframe.f_locals['__return__']`
164 else:
165 print '*** Not arguments?!'
166 do_a = do_args
168 def do_retval(self, arg):
169 if self.curframe.f_locals.has_key('__return__'):
170 print self.curframe.f_locals['__return__']
171 else:
172 print '*** Not yet returned!'
173 do_rv = do_retval
175 def do_p(self, arg):
176 self.curframe.f_globals['__privileged__'] = 1
177 try:
178 value = eval(arg, self.curframe.f_globals, \
179 self.curframe.f_locals)
180 except:
181 print '***', sys.exc_type + ':', `sys.exc_value`
182 return
184 print `value`
186 def do_list(self, arg):
187 self.lastcmd = 'list'
188 last = None
189 if arg:
190 try:
191 x = eval(arg, {}, {})
192 if type(x) == type(()):
193 first, last = x
194 first = int(first)
195 last = int(last)
196 if last < first:
197 # Assume it's a count
198 last = first + last
199 else:
200 first = max(1, int(x) - 5)
201 except:
202 print '*** Error in argument:', `arg`
203 return
204 elif self.lineno is None:
205 first = max(1, self.curframe.f_lineno - 5)
206 else:
207 first = self.lineno + 1
208 if last == None:
209 last = first + 10
210 filename = self.curframe.f_code.co_filename
211 breaklist = self.get_file_breaks(filename)
212 try:
213 for lineno in range(first, last+1):
214 line = linecache.getline(filename, lineno)
215 if not line:
216 print '[EOF]'
217 break
218 else:
219 s = string.rjust(`lineno`, 3)
220 if len(s) < 4: s = s + ' '
221 if lineno in breaklist: s = s + 'B'
222 else: s = s + ' '
223 if lineno == self.curframe.f_lineno:
224 s = s + '->'
225 print s + '\t' + line,
226 self.lineno = lineno
227 except KeyboardInterrupt:
228 pass
229 do_l = do_list
231 def do_whatis(self, arg):
232 import codehack
233 try:
234 value = eval(arg, self.curframe.f_globals, \
235 self.curframe.f_locals)
236 except:
237 print '***', sys.exc_type + ':', `sys.exc_value`
238 return
239 code = None
240 # Is it a function?
241 try: code = value.func_code
242 except: pass
243 if code:
244 print 'Function', codehack.getcodename(code)
245 return
246 # Is it an instance method?
247 try: code = value.im_func.func_code
248 except: pass
249 if code:
250 print 'Method', codehack.getcodename(code)
251 return
252 # None of the above...
253 print type(value)
255 # Print a traceback starting at the top stack frame.
256 # The most recently entered frame is printed last;
257 # this is different from dbx and gdb, but consistent with
258 # the Python interpreter's stack trace.
259 # It is also consistent with the up/down commands (which are
260 # compatible with dbx and gdb: up moves towards 'main()'
261 # and down moves towards the most recent stack frame).
263 def print_stack_trace(self):
264 try:
265 for frame_lineno in self.stack:
266 self.print_stack_entry(frame_lineno)
267 except KeyboardInterrupt:
268 pass
270 def print_stack_entry(self, frame_lineno):
271 frame, lineno = frame_lineno
272 if frame is self.curframe:
273 print '>',
274 else:
275 print ' ',
276 print self.format_stack_entry(frame_lineno)
279 # Simplified interface
281 def run(statement):
282 Pdb().run(statement)
284 def runctx(statement, globals, locals):
285 Pdb().runctx(statement, globals, locals)
287 def runcall(*args):
288 apply(Pdb().runcall, args)
291 # Post-Mortem interface
293 def post_mortem(t):
294 p = Pdb()
295 p.reset()
296 while t.tb_next <> None: t = t.tb_next
297 p.interaction(t.tb_frame, t)
299 def pm():
300 import sys
301 post_mortem(sys.last_traceback)
304 # Main program for testing
306 TESTCMD = 'import x; x.main()'
308 def test():
309 import linecache
310 linecache.checkcache()
311 run(TESTCMD)
313 # print help
314 def help():
315 import os
316 for dirname in sys.path:
317 fullname = os.path.join(dirname, 'pdb.doc')
318 if os.path.exists(fullname):
319 sts = os.system('${PAGER-more} '+fullname)
320 if sts: print '*** Pager exit status:', sts
321 break
322 else:
323 print 'Sorry, can\'t find the help file "pdb.doc"',
324 print 'along the Python search path'