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