##// END OF EJS Templates
Raise repr limit for strings to 80 characters (from 30)....
Fernando Perez -
Show More
@@ -1,509 +1,525 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Pdb debugger class.
4 4
5 5 Modified from the standard pdb.Pdb class to avoid including readline, so that
6 6 the command line completion of other programs which include this isn't
7 7 damaged.
8 8
9 9 In the future, this class will be expanded with improvements over the standard
10 10 pdb.
11 11
12 12 The code in this file is mainly lifted out of cmd.py in Python 2.2, with minor
13 13 changes. Licensing should therefore be under the standard Python terms. For
14 14 details on the PSF (Python Software Foundation) standard license, see:
15 15
16 16 http://www.python.org/2.2.3/license.html"""
17 17
18 18 #*****************************************************************************
19 19 #
20 20 # This file is licensed under the PSF license.
21 21 #
22 22 # Copyright (C) 2001 Python Software Foundation, www.python.org
23 23 # Copyright (C) 2005-2006 Fernando Perez. <fperez@colorado.edu>
24 24 #
25 25 #
26 26 #*****************************************************************************
27 27
28 28 import bdb
29 29 import linecache
30 30 import sys
31 31
32 32 from IPython.utils import PyColorize
33 33 from IPython.core import ipapi
34 34 from IPython.utils import coloransi, io
35 35 from IPython.core.excolors import exception_colors
36 36
37 37 # See if we can use pydb.
38 38 has_pydb = False
39 39 prompt = 'ipdb> '
40 40 #We have to check this directly from sys.argv, config struct not yet available
41 41 if '--pydb' in sys.argv:
42 42 try:
43 43 import pydb
44 44 if hasattr(pydb.pydb, "runl") and pydb.version>'1.17':
45 45 # Version 1.17 is broken, and that's what ships with Ubuntu Edgy, so we
46 46 # better protect against it.
47 47 has_pydb = True
48 48 except ImportError:
49 49 print "Pydb (http://bashdb.sourceforge.net/pydb/) does not seem to be available"
50 50
51 51 if has_pydb:
52 52 from pydb import Pdb as OldPdb
53 53 #print "Using pydb for %run -d and post-mortem" #dbg
54 54 prompt = 'ipydb> '
55 55 else:
56 56 from pdb import Pdb as OldPdb
57 57
58 58 # Allow the set_trace code to operate outside of an ipython instance, even if
59 59 # it does so with some limitations. The rest of this support is implemented in
60 60 # the Tracer constructor.
61 61 def BdbQuit_excepthook(et,ev,tb):
62 62 if et==bdb.BdbQuit:
63 63 print 'Exiting Debugger.'
64 64 else:
65 65 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
66 66
67 67 def BdbQuit_IPython_excepthook(self,et,ev,tb,tb_offset=None):
68 68 print 'Exiting Debugger.'
69 69
70 70
71 71 class Tracer(object):
72 72 """Class for local debugging, similar to pdb.set_trace.
73 73
74 74 Instances of this class, when called, behave like pdb.set_trace, but
75 75 providing IPython's enhanced capabilities.
76 76
77 77 This is implemented as a class which must be initialized in your own code
78 78 and not as a standalone function because we need to detect at runtime
79 79 whether IPython is already active or not. That detection is done in the
80 80 constructor, ensuring that this code plays nicely with a running IPython,
81 81 while functioning acceptably (though with limitations) if outside of it.
82 82 """
83 83
84 84 def __init__(self,colors=None):
85 85 """Create a local debugger instance.
86 86
87 87 :Parameters:
88 88
89 89 - `colors` (None): a string containing the name of the color scheme to
90 90 use, it must be one of IPython's valid color schemes. If not given, the
91 91 function will default to the current IPython scheme when running inside
92 92 IPython, and to 'NoColor' otherwise.
93 93
94 94 Usage example:
95 95
96 96 from IPython.core.debugger import Tracer; debug_here = Tracer()
97 97
98 98 ... later in your code
99 99 debug_here() # -> will open up the debugger at that point.
100 100
101 101 Once the debugger activates, you can use all of its regular commands to
102 102 step through code, set breakpoints, etc. See the pdb documentation
103 103 from the Python standard library for usage details.
104 104 """
105 105
106 106 try:
107 107 ip = get_ipython()
108 108 except NameError:
109 109 # Outside of ipython, we set our own exception hook manually
110 110 BdbQuit_excepthook.excepthook_ori = sys.excepthook
111 111 sys.excepthook = BdbQuit_excepthook
112 112 def_colors = 'NoColor'
113 113 try:
114 114 # Limited tab completion support
115 115 import readline
116 116 readline.parse_and_bind('tab: complete')
117 117 except ImportError:
118 118 pass
119 119 else:
120 120 # In ipython, we use its custom exception handler mechanism
121 121 def_colors = ip.colors
122 122 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
123 123
124 124 if colors is None:
125 125 colors = def_colors
126
127 # The stdlib debugger internally uses a modified repr from the `repr`
128 # module, that limits the length of printed strings to a hardcoded
129 # limit of 30 characters. That much trimming is too aggressive, let's
130 # at least raise that limit to 80 chars, which should be enough for
131 # most interactive uses.
132 try:
133 from repr import aRepr
134 aRepr.maxstring = 80
135 except:
136 # This is only a user-facing convenience, so any error we encounter
137 # here can be warned about but can be otherwise ignored. These
138 # printouts will tell us about problems if this API changes
139 import traceback
140 traceback.print_exc()
141
126 142 self.debugger = Pdb(colors)
127 143
128 144 def __call__(self):
129 145 """Starts an interactive debugger at the point where called.
130 146
131 147 This is similar to the pdb.set_trace() function from the std lib, but
132 148 using IPython's enhanced debugger."""
133 149
134 150 self.debugger.set_trace(sys._getframe().f_back)
135 151
136 152
137 153 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
138 154 """Make new_fn have old_fn's doc string. This is particularly useful
139 155 for the do_... commands that hook into the help system.
140 156 Adapted from from a comp.lang.python posting
141 157 by Duncan Booth."""
142 158 def wrapper(*args, **kw):
143 159 return new_fn(*args, **kw)
144 160 if old_fn.__doc__:
145 161 wrapper.__doc__ = old_fn.__doc__ + additional_text
146 162 return wrapper
147 163
148 164
149 165 def _file_lines(fname):
150 166 """Return the contents of a named file as a list of lines.
151 167
152 168 This function never raises an IOError exception: if the file can't be
153 169 read, it simply returns an empty list."""
154 170
155 171 try:
156 172 outfile = open(fname)
157 173 except IOError:
158 174 return []
159 175 else:
160 176 out = outfile.readlines()
161 177 outfile.close()
162 178 return out
163 179
164 180
165 181 class Pdb(OldPdb):
166 182 """Modified Pdb class, does not load readline."""
167 183
168 184 def __init__(self,color_scheme='NoColor',completekey=None,
169 185 stdin=None, stdout=None):
170 186
171 187 # Parent constructor:
172 188 if has_pydb and completekey is None:
173 189 OldPdb.__init__(self,stdin=stdin,stdout=io.stdout)
174 190 else:
175 191 OldPdb.__init__(self,completekey,stdin,stdout)
176 192
177 193 self.prompt = prompt # The default prompt is '(Pdb)'
178 194
179 195 # IPython changes...
180 196 self.is_pydb = has_pydb
181 197
182 198 self.shell = ipapi.get()
183 199
184 200 if self.is_pydb:
185 201
186 202 # interactiveshell.py's ipalias seems to want pdb's checkline
187 203 # which located in pydb.fn
188 204 import pydb.fns
189 205 self.checkline = lambda filename, lineno: \
190 206 pydb.fns.checkline(self, filename, lineno)
191 207
192 208 self.curframe = None
193 209 self.do_restart = self.new_do_restart
194 210
195 211 self.old_all_completions = self.shell.Completer.all_completions
196 212 self.shell.Completer.all_completions=self.all_completions
197 213
198 214 self.do_list = decorate_fn_with_doc(self.list_command_pydb,
199 215 OldPdb.do_list)
200 216 self.do_l = self.do_list
201 217 self.do_frame = decorate_fn_with_doc(self.new_do_frame,
202 218 OldPdb.do_frame)
203 219
204 220 self.aliases = {}
205 221
206 222 # Create color table: we copy the default one from the traceback
207 223 # module and add a few attributes needed for debugging
208 224 self.color_scheme_table = exception_colors()
209 225
210 226 # shorthands
211 227 C = coloransi.TermColors
212 228 cst = self.color_scheme_table
213 229
214 230 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
215 231 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
216 232
217 233 cst['Linux'].colors.breakpoint_enabled = C.LightRed
218 234 cst['Linux'].colors.breakpoint_disabled = C.Red
219 235
220 236 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
221 237 cst['LightBG'].colors.breakpoint_disabled = C.Red
222 238
223 239 self.set_colors(color_scheme)
224 240
225 241 # Add a python parser so we can syntax highlight source while
226 242 # debugging.
227 243 self.parser = PyColorize.Parser()
228 244
229 245 def set_colors(self, scheme):
230 246 """Shorthand access to the color table scheme selector method."""
231 247 self.color_scheme_table.set_active_scheme(scheme)
232 248
233 249 def interaction(self, frame, traceback):
234 250 self.shell.set_completer_frame(frame)
235 251 OldPdb.interaction(self, frame, traceback)
236 252
237 253 def new_do_up(self, arg):
238 254 OldPdb.do_up(self, arg)
239 255 self.shell.set_completer_frame(self.curframe)
240 256 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
241 257
242 258 def new_do_down(self, arg):
243 259 OldPdb.do_down(self, arg)
244 260 self.shell.set_completer_frame(self.curframe)
245 261
246 262 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
247 263
248 264 def new_do_frame(self, arg):
249 265 OldPdb.do_frame(self, arg)
250 266 self.shell.set_completer_frame(self.curframe)
251 267
252 268 def new_do_quit(self, arg):
253 269
254 270 if hasattr(self, 'old_all_completions'):
255 271 self.shell.Completer.all_completions=self.old_all_completions
256 272
257 273
258 274 return OldPdb.do_quit(self, arg)
259 275
260 276 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
261 277
262 278 def new_do_restart(self, arg):
263 279 """Restart command. In the context of ipython this is exactly the same
264 280 thing as 'quit'."""
265 281 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
266 282 return self.do_quit(arg)
267 283
268 284 def postloop(self):
269 285 self.shell.set_completer_frame(None)
270 286
271 287 def print_stack_trace(self):
272 288 try:
273 289 for frame_lineno in self.stack:
274 290 self.print_stack_entry(frame_lineno, context = 5)
275 291 except KeyboardInterrupt:
276 292 pass
277 293
278 294 def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ',
279 295 context = 3):
280 296 #frame, lineno = frame_lineno
281 297 print >>io.stdout, self.format_stack_entry(frame_lineno, '', context)
282 298
283 299 # vds: >>
284 300 frame, lineno = frame_lineno
285 301 filename = frame.f_code.co_filename
286 302 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
287 303 # vds: <<
288 304
289 305 def format_stack_entry(self, frame_lineno, lprefix=': ', context = 3):
290 306 import linecache, repr
291 307
292 308 ret = []
293 309
294 310 Colors = self.color_scheme_table.active_colors
295 311 ColorsNormal = Colors.Normal
296 312 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
297 313 tpl_call = '%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
298 314 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
299 315 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
300 316 ColorsNormal)
301 317
302 318 frame, lineno = frame_lineno
303 319
304 320 return_value = ''
305 321 if '__return__' in frame.f_locals:
306 322 rv = frame.f_locals['__return__']
307 323 #return_value += '->'
308 324 return_value += repr.repr(rv) + '\n'
309 325 ret.append(return_value)
310 326
311 327 #s = filename + '(' + `lineno` + ')'
312 328 filename = self.canonic(frame.f_code.co_filename)
313 329 link = tpl_link % filename
314 330
315 331 if frame.f_code.co_name:
316 332 func = frame.f_code.co_name
317 333 else:
318 334 func = "<lambda>"
319 335
320 336 call = ''
321 337 if func != '?':
322 338 if '__args__' in frame.f_locals:
323 339 args = repr.repr(frame.f_locals['__args__'])
324 340 else:
325 341 args = '()'
326 342 call = tpl_call % (func, args)
327 343
328 344 # The level info should be generated in the same format pdb uses, to
329 345 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
330 346 if frame is self.curframe:
331 347 ret.append('> ')
332 348 else:
333 349 ret.append(' ')
334 350 ret.append('%s(%s)%s\n' % (link,lineno,call))
335 351
336 352 start = lineno - 1 - context//2
337 353 lines = linecache.getlines(filename)
338 354 start = max(start, 0)
339 355 start = min(start, len(lines) - context)
340 356 lines = lines[start : start + context]
341 357
342 358 for i,line in enumerate(lines):
343 359 show_arrow = (start + 1 + i == lineno)
344 360 linetpl = (frame is self.curframe or show_arrow) \
345 361 and tpl_line_em \
346 362 or tpl_line
347 363 ret.append(self.__format_line(linetpl, filename,
348 364 start + 1 + i, line,
349 365 arrow = show_arrow) )
350 366
351 367 return ''.join(ret)
352 368
353 369 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
354 370 bp_mark = ""
355 371 bp_mark_color = ""
356 372
357 373 scheme = self.color_scheme_table.active_scheme_name
358 374 new_line, err = self.parser.format2(line, 'str', scheme)
359 375 if not err: line = new_line
360 376
361 377 bp = None
362 378 if lineno in self.get_file_breaks(filename):
363 379 bps = self.get_breaks(filename, lineno)
364 380 bp = bps[-1]
365 381
366 382 if bp:
367 383 Colors = self.color_scheme_table.active_colors
368 384 bp_mark = str(bp.number)
369 385 bp_mark_color = Colors.breakpoint_enabled
370 386 if not bp.enabled:
371 387 bp_mark_color = Colors.breakpoint_disabled
372 388
373 389 numbers_width = 7
374 390 if arrow:
375 391 # This is the line with the error
376 392 pad = numbers_width - len(str(lineno)) - len(bp_mark)
377 393 if pad >= 3:
378 394 marker = '-'*(pad-3) + '-> '
379 395 elif pad == 2:
380 396 marker = '> '
381 397 elif pad == 1:
382 398 marker = '>'
383 399 else:
384 400 marker = ''
385 401 num = '%s%s' % (marker, str(lineno))
386 402 line = tpl_line % (bp_mark_color + bp_mark, num, line)
387 403 else:
388 404 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
389 405 line = tpl_line % (bp_mark_color + bp_mark, num, line)
390 406
391 407 return line
392 408
393 409 def list_command_pydb(self, arg):
394 410 """List command to use if we have a newer pydb installed"""
395 411 filename, first, last = OldPdb.parse_list_cmd(self, arg)
396 412 if filename is not None:
397 413 self.print_list_lines(filename, first, last)
398 414
399 415 def print_list_lines(self, filename, first, last):
400 416 """The printing (as opposed to the parsing part of a 'list'
401 417 command."""
402 418 try:
403 419 Colors = self.color_scheme_table.active_colors
404 420 ColorsNormal = Colors.Normal
405 421 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
406 422 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
407 423 src = []
408 424 for lineno in range(first, last+1):
409 425 line = linecache.getline(filename, lineno)
410 426 if not line:
411 427 break
412 428
413 429 if lineno == self.curframe.f_lineno:
414 430 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
415 431 else:
416 432 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
417 433
418 434 src.append(line)
419 435 self.lineno = lineno
420 436
421 437 print >>io.stdout, ''.join(src)
422 438
423 439 except KeyboardInterrupt:
424 440 pass
425 441
426 442 def do_list(self, arg):
427 443 self.lastcmd = 'list'
428 444 last = None
429 445 if arg:
430 446 try:
431 447 x = eval(arg, {}, {})
432 448 if type(x) == type(()):
433 449 first, last = x
434 450 first = int(first)
435 451 last = int(last)
436 452 if last < first:
437 453 # Assume it's a count
438 454 last = first + last
439 455 else:
440 456 first = max(1, int(x) - 5)
441 457 except:
442 458 print '*** Error in argument:', `arg`
443 459 return
444 460 elif self.lineno is None:
445 461 first = max(1, self.curframe.f_lineno - 5)
446 462 else:
447 463 first = self.lineno + 1
448 464 if last is None:
449 465 last = first + 10
450 466 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
451 467
452 468 # vds: >>
453 469 lineno = first
454 470 filename = self.curframe.f_code.co_filename
455 471 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
456 472 # vds: <<
457 473
458 474 do_l = do_list
459 475
460 476 def do_pdef(self, arg):
461 477 """The debugger interface to magic_pdef"""
462 478 namespaces = [('Locals', self.curframe.f_locals),
463 479 ('Globals', self.curframe.f_globals)]
464 480 self.shell.magic_pdef(arg, namespaces=namespaces)
465 481
466 482 def do_pdoc(self, arg):
467 483 """The debugger interface to magic_pdoc"""
468 484 namespaces = [('Locals', self.curframe.f_locals),
469 485 ('Globals', self.curframe.f_globals)]
470 486 self.shell.magic_pdoc(arg, namespaces=namespaces)
471 487
472 488 def do_pinfo(self, arg):
473 489 """The debugger equivalant of ?obj"""
474 490 namespaces = [('Locals', self.curframe.f_locals),
475 491 ('Globals', self.curframe.f_globals)]
476 492 self.shell.magic_pinfo("pinfo %s" % arg, namespaces=namespaces)
477 493
478 494 def checkline(self, filename, lineno):
479 495 """Check whether specified line seems to be executable.
480 496
481 497 Return `lineno` if it is, 0 if not (e.g. a docstring, comment, blank
482 498 line or EOF). Warning: testing is not comprehensive.
483 499 """
484 500 #######################################################################
485 501 # XXX Hack! Use python-2.5 compatible code for this call, because with
486 502 # all of our changes, we've drifted from the pdb api in 2.6. For now,
487 503 # changing:
488 504 #
489 505 #line = linecache.getline(filename, lineno, self.curframe.f_globals)
490 506 # to:
491 507 #
492 508 line = linecache.getline(filename, lineno)
493 509 #
494 510 # does the trick. But in reality, we need to fix this by reconciling
495 511 # our updates with the new Pdb APIs in Python 2.6.
496 512 #
497 513 # End hack. The rest of this method is copied verbatim from 2.6 pdb.py
498 514 #######################################################################
499 515
500 516 if not line:
501 517 print >>self.stdout, 'End of file'
502 518 return 0
503 519 line = line.strip()
504 520 # Don't allow setting breakpoint at a blank line
505 521 if (not line or (line[0] == '#') or
506 522 (line[:3] == '"""') or line[:3] == "'''"):
507 523 print >>self.stdout, '*** Blank or comment'
508 524 return 0
509 525 return lineno
General Comments 0
You need to be logged in to leave comments. Login now