##// END OF EJS Templates
move ulinecache.getlines function call to linecache.getlines()
Srinivas Reddy Thatiparthy -
Show More
@@ -1,610 +1,611 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 functools
30 30 import inspect
31 import linecache
31 32 import sys
32 33 import warnings
33 34
34 35 from IPython import get_ipython
35 from IPython.utils import PyColorize, ulinecache
36 from IPython.utils import PyColorize
36 37 from IPython.utils import coloransi, py3compat
37 38 from IPython.core.excolors import exception_colors
38 39 from IPython.testing.skipdoctest import skip_doctest
39 40
40 41
41 42 prompt = 'ipdb> '
42 43
43 44 #We have to check this directly from sys.argv, config struct not yet available
44 45 from pdb import Pdb as OldPdb
45 46
46 47 # Allow the set_trace code to operate outside of an ipython instance, even if
47 48 # it does so with some limitations. The rest of this support is implemented in
48 49 # the Tracer constructor.
49 50
50 51 def make_arrow(pad):
51 52 """generate the leading arrow in front of traceback or debugger"""
52 53 if pad >= 2:
53 54 return '-'*(pad-2) + '> '
54 55 elif pad == 1:
55 56 return '>'
56 57 return ''
57 58
58 59
59 60 def BdbQuit_excepthook(et, ev, tb, excepthook=None):
60 61 """Exception hook which handles `BdbQuit` exceptions.
61 62
62 63 All other exceptions are processed using the `excepthook`
63 64 parameter.
64 65 """
65 66 warnings.warn("`BdbQuit_excepthook` is deprecated since version 5.1",
66 67 DeprecationWarning, stacklevel=2)
67 68 if et==bdb.BdbQuit:
68 69 print('Exiting Debugger.')
69 70 elif excepthook is not None:
70 71 excepthook(et, ev, tb)
71 72 else:
72 73 # Backwards compatibility. Raise deprecation warning?
73 74 BdbQuit_excepthook.excepthook_ori(et,ev,tb)
74 75
75 76
76 77 def BdbQuit_IPython_excepthook(self,et,ev,tb,tb_offset=None):
77 78 warnings.warn(
78 79 "`BdbQuit_IPython_excepthook` is deprecated since version 5.1",
79 80 DeprecationWarning, stacklevel=2)
80 81 print('Exiting Debugger.')
81 82
82 83
83 84 class Tracer(object):
84 85 """
85 86 DEPRECATED
86 87
87 88 Class for local debugging, similar to pdb.set_trace.
88 89
89 90 Instances of this class, when called, behave like pdb.set_trace, but
90 91 providing IPython's enhanced capabilities.
91 92
92 93 This is implemented as a class which must be initialized in your own code
93 94 and not as a standalone function because we need to detect at runtime
94 95 whether IPython is already active or not. That detection is done in the
95 96 constructor, ensuring that this code plays nicely with a running IPython,
96 97 while functioning acceptably (though with limitations) if outside of it.
97 98 """
98 99
99 100 @skip_doctest
100 101 def __init__(self, colors=None):
101 102 """
102 103 DEPRECATED
103 104
104 105 Create a local debugger instance.
105 106
106 107 Parameters
107 108 ----------
108 109
109 110 colors : str, optional
110 111 The name of the color scheme to use, it must be one of IPython's
111 112 valid color schemes. If not given, the function will default to
112 113 the current IPython scheme when running inside IPython, and to
113 114 'NoColor' otherwise.
114 115
115 116 Examples
116 117 --------
117 118 ::
118 119
119 120 from IPython.core.debugger import Tracer; debug_here = Tracer()
120 121
121 122 Later in your code::
122 123
123 124 debug_here() # -> will open up the debugger at that point.
124 125
125 126 Once the debugger activates, you can use all of its regular commands to
126 127 step through code, set breakpoints, etc. See the pdb documentation
127 128 from the Python standard library for usage details.
128 129 """
129 130 warnings.warn("`Tracer` is deprecated since version 5.1, directly use "
130 131 "`IPython.core.debugger.Pdb.set_trace()`",
131 132 DeprecationWarning, stacklevel=2)
132 133
133 134 ip = get_ipython()
134 135 if ip is None:
135 136 # Outside of ipython, we set our own exception hook manually
136 137 sys.excepthook = functools.partial(BdbQuit_excepthook,
137 138 excepthook=sys.excepthook)
138 139 def_colors = 'NoColor'
139 140 else:
140 141 # In ipython, we use its custom exception handler mechanism
141 142 def_colors = ip.colors
142 143 ip.set_custom_exc((bdb.BdbQuit,), BdbQuit_IPython_excepthook)
143 144
144 145 if colors is None:
145 146 colors = def_colors
146 147
147 148 # The stdlib debugger internally uses a modified repr from the `repr`
148 149 # module, that limits the length of printed strings to a hardcoded
149 150 # limit of 30 characters. That much trimming is too aggressive, let's
150 151 # at least raise that limit to 80 chars, which should be enough for
151 152 # most interactive uses.
152 153 try:
153 154 try:
154 155 from reprlib import aRepr # Py 3
155 156 except ImportError:
156 157 from repr import aRepr # Py 2
157 158 aRepr.maxstring = 80
158 159 except:
159 160 # This is only a user-facing convenience, so any error we encounter
160 161 # here can be warned about but can be otherwise ignored. These
161 162 # printouts will tell us about problems if this API changes
162 163 import traceback
163 164 traceback.print_exc()
164 165
165 166 self.debugger = Pdb(colors)
166 167
167 168 def __call__(self):
168 169 """Starts an interactive debugger at the point where called.
169 170
170 171 This is similar to the pdb.set_trace() function from the std lib, but
171 172 using IPython's enhanced debugger."""
172 173
173 174 self.debugger.set_trace(sys._getframe().f_back)
174 175
175 176
176 177 def decorate_fn_with_doc(new_fn, old_fn, additional_text=""):
177 178 """Make new_fn have old_fn's doc string. This is particularly useful
178 179 for the ``do_...`` commands that hook into the help system.
179 180 Adapted from from a comp.lang.python posting
180 181 by Duncan Booth."""
181 182 def wrapper(*args, **kw):
182 183 return new_fn(*args, **kw)
183 184 if old_fn.__doc__:
184 185 wrapper.__doc__ = old_fn.__doc__ + additional_text
185 186 return wrapper
186 187
187 188
188 189 def _file_lines(fname):
189 190 """Return the contents of a named file as a list of lines.
190 191
191 192 This function never raises an IOError exception: if the file can't be
192 193 read, it simply returns an empty list."""
193 194
194 195 try:
195 196 outfile = open(fname)
196 197 except IOError:
197 198 return []
198 199 else:
199 200 out = outfile.readlines()
200 201 outfile.close()
201 202 return out
202 203
203 204
204 205 class Pdb(OldPdb):
205 206 """Modified Pdb class, does not load readline.
206 207
207 208 for a standalone version that uses prompt_toolkit, see
208 209 `IPython.terminal.debugger.TerminalPdb` and
209 210 `IPython.terminal.debugger.set_trace()`
210 211 """
211 212
212 213 def __init__(self, color_scheme=None, completekey=None,
213 214 stdin=None, stdout=None, context=5):
214 215
215 216 # Parent constructor:
216 217 try:
217 218 self.context = int(context)
218 219 if self.context <= 0:
219 220 raise ValueError("Context must be a positive integer")
220 221 except (TypeError, ValueError):
221 222 raise ValueError("Context must be a positive integer")
222 223
223 224 OldPdb.__init__(self, completekey, stdin, stdout)
224 225
225 226 # IPython changes...
226 227 self.shell = get_ipython()
227 228
228 229 if self.shell is None:
229 230 save_main = sys.modules['__main__']
230 231 # No IPython instance running, we must create one
231 232 from IPython.terminal.interactiveshell import \
232 233 TerminalInteractiveShell
233 234 self.shell = TerminalInteractiveShell.instance()
234 235 # needed by any code which calls __import__("__main__") after
235 236 # the debugger was entered. See also #9941.
236 237 sys.modules['__main__'] = save_main
237 238
238 239 if color_scheme is not None:
239 240 warnings.warn(
240 241 "The `color_scheme` argument is deprecated since version 5.1",
241 242 DeprecationWarning, stacklevel=2)
242 243 else:
243 244 color_scheme = self.shell.colors
244 245
245 246 self.aliases = {}
246 247
247 248 # Create color table: we copy the default one from the traceback
248 249 # module and add a few attributes needed for debugging
249 250 self.color_scheme_table = exception_colors()
250 251
251 252 # shorthands
252 253 C = coloransi.TermColors
253 254 cst = self.color_scheme_table
254 255
255 256 cst['NoColor'].colors.prompt = C.NoColor
256 257 cst['NoColor'].colors.breakpoint_enabled = C.NoColor
257 258 cst['NoColor'].colors.breakpoint_disabled = C.NoColor
258 259
259 260 cst['Linux'].colors.prompt = C.Green
260 261 cst['Linux'].colors.breakpoint_enabled = C.LightRed
261 262 cst['Linux'].colors.breakpoint_disabled = C.Red
262 263
263 264 cst['LightBG'].colors.prompt = C.Blue
264 265 cst['LightBG'].colors.breakpoint_enabled = C.LightRed
265 266 cst['LightBG'].colors.breakpoint_disabled = C.Red
266 267
267 268 cst['Neutral'].colors.prompt = C.Blue
268 269 cst['Neutral'].colors.breakpoint_enabled = C.LightRed
269 270 cst['Neutral'].colors.breakpoint_disabled = C.Red
270 271
271 272
272 273 # Add a python parser so we can syntax highlight source while
273 274 # debugging.
274 275 self.parser = PyColorize.Parser(style=color_scheme)
275 276 self.set_colors(color_scheme)
276 277
277 278 # Set the prompt - the default prompt is '(Pdb)'
278 279 self.prompt = prompt
279 280
280 281 def set_colors(self, scheme):
281 282 """Shorthand access to the color table scheme selector method."""
282 283 self.color_scheme_table.set_active_scheme(scheme)
283 284 self.parser.style = scheme
284 285
285 286 def interaction(self, frame, traceback):
286 287 try:
287 288 OldPdb.interaction(self, frame, traceback)
288 289 except KeyboardInterrupt:
289 290 sys.stdout.write('\n' + self.shell.get_exception_only())
290 291
291 292 def new_do_up(self, arg):
292 293 OldPdb.do_up(self, arg)
293 294 do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up)
294 295
295 296 def new_do_down(self, arg):
296 297 OldPdb.do_down(self, arg)
297 298
298 299 do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down)
299 300
300 301 def new_do_frame(self, arg):
301 302 OldPdb.do_frame(self, arg)
302 303
303 304 def new_do_quit(self, arg):
304 305
305 306 if hasattr(self, 'old_all_completions'):
306 307 self.shell.Completer.all_completions=self.old_all_completions
307 308
308 309 return OldPdb.do_quit(self, arg)
309 310
310 311 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
311 312
312 313 def new_do_restart(self, arg):
313 314 """Restart command. In the context of ipython this is exactly the same
314 315 thing as 'quit'."""
315 316 self.msg("Restart doesn't make sense here. Using 'quit' instead.")
316 317 return self.do_quit(arg)
317 318
318 319 def print_stack_trace(self, context=None):
319 320 if context is None:
320 321 context = self.context
321 322 try:
322 323 context=int(context)
323 324 if context <= 0:
324 325 raise ValueError("Context must be a positive integer")
325 326 except (TypeError, ValueError):
326 327 raise ValueError("Context must be a positive integer")
327 328 try:
328 329 for frame_lineno in self.stack:
329 330 self.print_stack_entry(frame_lineno, context=context)
330 331 except KeyboardInterrupt:
331 332 pass
332 333
333 334 def print_stack_entry(self,frame_lineno, prompt_prefix='\n-> ',
334 335 context=None):
335 336 if context is None:
336 337 context = self.context
337 338 try:
338 339 context=int(context)
339 340 if context <= 0:
340 341 raise ValueError("Context must be a positive integer")
341 342 except (TypeError, ValueError):
342 343 raise ValueError("Context must be a positive integer")
343 344 print(self.format_stack_entry(frame_lineno, '', context))
344 345
345 346 # vds: >>
346 347 frame, lineno = frame_lineno
347 348 filename = frame.f_code.co_filename
348 349 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
349 350 # vds: <<
350 351
351 352 def format_stack_entry(self, frame_lineno, lprefix=': ', context=None):
352 353 if context is None:
353 354 context = self.context
354 355 try:
355 356 context=int(context)
356 357 if context <= 0:
357 358 print("Context must be a positive integer")
358 359 except (TypeError, ValueError):
359 360 print("Context must be a positive integer")
360 361 try:
361 362 import reprlib # Py 3
362 363 except ImportError:
363 364 import repr as reprlib # Py 2
364 365
365 366 ret = []
366 367
367 368 Colors = self.color_scheme_table.active_colors
368 369 ColorsNormal = Colors.Normal
369 370 tpl_link = u'%s%%s%s' % (Colors.filenameEm, ColorsNormal)
370 371 tpl_call = u'%s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal)
371 372 tpl_line = u'%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
372 373 tpl_line_em = u'%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
373 374 ColorsNormal)
374 375
375 376 frame, lineno = frame_lineno
376 377
377 378 return_value = ''
378 379 if '__return__' in frame.f_locals:
379 380 rv = frame.f_locals['__return__']
380 381 #return_value += '->'
381 382 return_value += reprlib.repr(rv) + '\n'
382 383 ret.append(return_value)
383 384
384 385 #s = filename + '(' + `lineno` + ')'
385 386 filename = self.canonic(frame.f_code.co_filename)
386 387 link = tpl_link % py3compat.cast_unicode(filename)
387 388
388 389 if frame.f_code.co_name:
389 390 func = frame.f_code.co_name
390 391 else:
391 392 func = "<lambda>"
392 393
393 394 call = ''
394 395 if func != '?':
395 396 if '__args__' in frame.f_locals:
396 397 args = reprlib.repr(frame.f_locals['__args__'])
397 398 else:
398 399 args = '()'
399 400 call = tpl_call % (func, args)
400 401
401 402 # The level info should be generated in the same format pdb uses, to
402 403 # avoid breaking the pdbtrack functionality of python-mode in *emacs.
403 404 if frame is self.curframe:
404 405 ret.append('> ')
405 406 else:
406 407 ret.append(' ')
407 408 ret.append(u'%s(%s)%s\n' % (link,lineno,call))
408 409
409 410 start = lineno - 1 - context//2
410 lines = ulinecache.getlines(filename)
411 lines = linecache.getlines(filename)
411 412 start = min(start, len(lines) - context)
412 413 start = max(start, 0)
413 414 lines = lines[start : start + context]
414 415
415 416 for i,line in enumerate(lines):
416 417 show_arrow = (start + 1 + i == lineno)
417 418 linetpl = (frame is self.curframe or show_arrow) \
418 419 and tpl_line_em \
419 420 or tpl_line
420 421 ret.append(self.__format_line(linetpl, filename,
421 422 start + 1 + i, line,
422 423 arrow = show_arrow) )
423 424 return ''.join(ret)
424 425
425 426 def __format_line(self, tpl_line, filename, lineno, line, arrow = False):
426 427 bp_mark = ""
427 428 bp_mark_color = ""
428 429
429 430 new_line, err = self.parser.format2(line, 'str')
430 431 if not err:
431 432 line = new_line
432 433
433 434 bp = None
434 435 if lineno in self.get_file_breaks(filename):
435 436 bps = self.get_breaks(filename, lineno)
436 437 bp = bps[-1]
437 438
438 439 if bp:
439 440 Colors = self.color_scheme_table.active_colors
440 441 bp_mark = str(bp.number)
441 442 bp_mark_color = Colors.breakpoint_enabled
442 443 if not bp.enabled:
443 444 bp_mark_color = Colors.breakpoint_disabled
444 445
445 446 numbers_width = 7
446 447 if arrow:
447 448 # This is the line with the error
448 449 pad = numbers_width - len(str(lineno)) - len(bp_mark)
449 450 num = '%s%s' % (make_arrow(pad), str(lineno))
450 451 else:
451 452 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
452 453
453 454 return tpl_line % (bp_mark_color + bp_mark, num, line)
454 455
455 456
456 457 def print_list_lines(self, filename, first, last):
457 458 """The printing (as opposed to the parsing part of a 'list'
458 459 command."""
459 460 try:
460 461 Colors = self.color_scheme_table.active_colors
461 462 ColorsNormal = Colors.Normal
462 463 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
463 464 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal)
464 465 src = []
465 466 if filename == "<string>" and hasattr(self, "_exec_filename"):
466 467 filename = self._exec_filename
467 468
468 469 for lineno in range(first, last+1):
469 line = ulinecache.getline(filename, lineno)
470 line = linecache.getline(filename, lineno)
470 471 if not line:
471 472 break
472 473
473 474 if lineno == self.curframe.f_lineno:
474 475 line = self.__format_line(tpl_line_em, filename, lineno, line, arrow = True)
475 476 else:
476 477 line = self.__format_line(tpl_line, filename, lineno, line, arrow = False)
477 478
478 479 src.append(line)
479 480 self.lineno = lineno
480 481
481 482 print(''.join(src))
482 483
483 484 except KeyboardInterrupt:
484 485 pass
485 486
486 487 def do_list(self, arg):
487 488 self.lastcmd = 'list'
488 489 last = None
489 490 if arg:
490 491 try:
491 492 x = eval(arg, {}, {})
492 493 if type(x) == type(()):
493 494 first, last = x
494 495 first = int(first)
495 496 last = int(last)
496 497 if last < first:
497 498 # Assume it's a count
498 499 last = first + last
499 500 else:
500 501 first = max(1, int(x) - 5)
501 502 except:
502 503 print('*** Error in argument:', repr(arg))
503 504 return
504 505 elif self.lineno is None:
505 506 first = max(1, self.curframe.f_lineno - 5)
506 507 else:
507 508 first = self.lineno + 1
508 509 if last is None:
509 510 last = first + 10
510 511 self.print_list_lines(self.curframe.f_code.co_filename, first, last)
511 512
512 513 # vds: >>
513 514 lineno = first
514 515 filename = self.curframe.f_code.co_filename
515 516 self.shell.hooks.synchronize_with_editor(filename, lineno, 0)
516 517 # vds: <<
517 518
518 519 do_l = do_list
519 520
520 521 def getsourcelines(self, obj):
521 522 lines, lineno = inspect.findsource(obj)
522 523 if inspect.isframe(obj) and obj.f_globals is obj.f_locals:
523 524 # must be a module frame: do not try to cut a block out of it
524 525 return lines, 1
525 526 elif inspect.ismodule(obj):
526 527 return lines, 1
527 528 return inspect.getblock(lines[lineno:]), lineno+1
528 529
529 530 def do_longlist(self, arg):
530 531 self.lastcmd = 'longlist'
531 532 try:
532 533 lines, lineno = self.getsourcelines(self.curframe)
533 534 except OSError as err:
534 535 self.error(err)
535 536 return
536 537 last = lineno + len(lines)
537 538 self.print_list_lines(self.curframe.f_code.co_filename, lineno, last)
538 539 do_ll = do_longlist
539 540
540 541 def do_pdef(self, arg):
541 542 """Print the call signature for any callable object.
542 543
543 544 The debugger interface to %pdef"""
544 545 namespaces = [('Locals', self.curframe.f_locals),
545 546 ('Globals', self.curframe.f_globals)]
546 547 self.shell.find_line_magic('pdef')(arg, namespaces=namespaces)
547 548
548 549 def do_pdoc(self, arg):
549 550 """Print the docstring for an object.
550 551
551 552 The debugger interface to %pdoc."""
552 553 namespaces = [('Locals', self.curframe.f_locals),
553 554 ('Globals', self.curframe.f_globals)]
554 555 self.shell.find_line_magic('pdoc')(arg, namespaces=namespaces)
555 556
556 557 def do_pfile(self, arg):
557 558 """Print (or run through pager) the file where an object is defined.
558 559
559 560 The debugger interface to %pfile.
560 561 """
561 562 namespaces = [('Locals', self.curframe.f_locals),
562 563 ('Globals', self.curframe.f_globals)]
563 564 self.shell.find_line_magic('pfile')(arg, namespaces=namespaces)
564 565
565 566 def do_pinfo(self, arg):
566 567 """Provide detailed information about an object.
567 568
568 569 The debugger interface to %pinfo, i.e., obj?."""
569 570 namespaces = [('Locals', self.curframe.f_locals),
570 571 ('Globals', self.curframe.f_globals)]
571 572 self.shell.find_line_magic('pinfo')(arg, namespaces=namespaces)
572 573
573 574 def do_pinfo2(self, arg):
574 575 """Provide extra detailed information about an object.
575 576
576 577 The debugger interface to %pinfo2, i.e., obj??."""
577 578 namespaces = [('Locals', self.curframe.f_locals),
578 579 ('Globals', self.curframe.f_globals)]
579 580 self.shell.find_line_magic('pinfo2')(arg, namespaces=namespaces)
580 581
581 582 def do_psource(self, arg):
582 583 """Print (or run through pager) the source code for an object."""
583 584 namespaces = [('Locals', self.curframe.f_locals),
584 585 ('Globals', self.curframe.f_globals)]
585 586 self.shell.find_line_magic('psource')(arg, namespaces=namespaces)
586 587
587 588 def do_where(self, arg):
588 589 """w(here)
589 590 Print a stack trace, with the most recent frame at the bottom.
590 591 An arrow indicates the "current frame", which determines the
591 592 context of most commands. 'bt' is an alias for this command.
592 593
593 594 Take a number as argument as an (optional) number of context line to
594 595 print"""
595 596 if arg:
596 597 context = int(arg)
597 598 self.print_stack_trace(context)
598 599 else:
599 600 self.print_stack_trace()
600 601
601 602 do_w = do_where
602 603
603 604
604 605 def set_trace(frame=None):
605 606 """
606 607 Start debugging from `frame`.
607 608
608 609 If frame is not specified, debugging starts from caller's frame.
609 610 """
610 611 Pdb().set_trace(frame or sys._getframe().f_back)
General Comments 0
You need to be logged in to leave comments. Login now