##// END OF EJS Templates
Update a couple of iteration idioms....
Matthias Bussonnier -
Show More
@@ -1,1461 +1,1461
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Verbose and colourful traceback formatting.
4 4
5 5 **ColorTB**
6 6
7 7 I've always found it a bit hard to visually parse tracebacks in Python. The
8 8 ColorTB class is a solution to that problem. It colors the different parts of a
9 9 traceback in a manner similar to what you would expect from a syntax-highlighting
10 10 text editor.
11 11
12 12 Installation instructions for ColorTB::
13 13
14 14 import sys,ultratb
15 15 sys.excepthook = ultratb.ColorTB()
16 16
17 17 **VerboseTB**
18 18
19 19 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
20 20 of useful info when a traceback occurs. Ping originally had it spit out HTML
21 21 and intended it for CGI programmers, but why should they have all the fun? I
22 22 altered it to spit out colored text to the terminal. It's a bit overwhelming,
23 23 but kind of neat, and maybe useful for long-running programs that you believe
24 24 are bug-free. If a crash *does* occur in that type of program you want details.
25 25 Give it a shot--you'll love it or you'll hate it.
26 26
27 27 .. note::
28 28
29 29 The Verbose mode prints the variables currently visible where the exception
30 30 happened (shortening their strings if too long). This can potentially be
31 31 very slow, if you happen to have a huge data structure whose string
32 32 representation is complex to compute. Your computer may appear to freeze for
33 33 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
34 34 with Ctrl-C (maybe hitting it more than once).
35 35
36 36 If you encounter this kind of situation often, you may want to use the
37 37 Verbose_novars mode instead of the regular Verbose, which avoids formatting
38 38 variables (but otherwise includes the information and context given by
39 39 Verbose).
40 40
41 41 .. note::
42 42
43 43 The verbose mode print all variables in the stack, which means it can
44 44 potentially leak sensitive information like access keys, or unencryted
45 45 password.
46 46
47 47 Installation instructions for VerboseTB::
48 48
49 49 import sys,ultratb
50 50 sys.excepthook = ultratb.VerboseTB()
51 51
52 52 Note: Much of the code in this module was lifted verbatim from the standard
53 53 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
54 54
55 55 Color schemes
56 56 -------------
57 57
58 58 The colors are defined in the class TBTools through the use of the
59 59 ColorSchemeTable class. Currently the following exist:
60 60
61 61 - NoColor: allows all of this module to be used in any terminal (the color
62 62 escapes are just dummy blank strings).
63 63
64 64 - Linux: is meant to look good in a terminal like the Linux console (black
65 65 or very dark background).
66 66
67 67 - LightBG: similar to Linux but swaps dark/light colors to be more readable
68 68 in light background terminals.
69 69
70 70 - Neutral: a neutral color scheme that should be readable on both light and
71 71 dark background
72 72
73 73 You can implement other color schemes easily, the syntax is fairly
74 74 self-explanatory. Please send back new schemes you develop to the author for
75 75 possible inclusion in future releases.
76 76
77 77 Inheritance diagram:
78 78
79 79 .. inheritance-diagram:: IPython.core.ultratb
80 80 :parts: 3
81 81 """
82 82
83 83 #*****************************************************************************
84 84 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
85 85 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
86 86 #
87 87 # Distributed under the terms of the BSD License. The full license is in
88 88 # the file COPYING, distributed as part of this software.
89 89 #*****************************************************************************
90 90
91 91
92 92 import dis
93 93 import inspect
94 94 import keyword
95 95 import linecache
96 96 import os
97 97 import pydoc
98 98 import re
99 99 import sys
100 100 import time
101 101 import tokenize
102 102 import traceback
103 103 import types
104 104
105 105 try: # Python 2
106 106 generate_tokens = tokenize.generate_tokens
107 107 except AttributeError: # Python 3
108 108 generate_tokens = tokenize.tokenize
109 109
110 110 # For purposes of monkeypatching inspect to fix a bug in it.
111 111 from inspect import getsourcefile, getfile, getmodule, \
112 112 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
113 113
114 114 # IPython's own modules
115 115 from IPython import get_ipython
116 116 from IPython.core import debugger
117 117 from IPython.core.display_trap import DisplayTrap
118 118 from IPython.core.excolors import exception_colors
119 119 from IPython.utils import PyColorize
120 120 from IPython.utils import openpy
121 121 from IPython.utils import path as util_path
122 122 from IPython.utils import py3compat
123 123 from IPython.utils.data import uniq_stable
124 124 from IPython.utils.terminal import get_terminal_size
125 125 from logging import info, error
126 126
127 127 import IPython.utils.colorable as colorable
128 128
129 129 # Globals
130 130 # amount of space to put line numbers before verbose tracebacks
131 131 INDENT_SIZE = 8
132 132
133 133 # Default color scheme. This is used, for example, by the traceback
134 134 # formatter. When running in an actual IPython instance, the user's rc.colors
135 135 # value is used, but having a module global makes this functionality available
136 136 # to users of ultratb who are NOT running inside ipython.
137 137 DEFAULT_SCHEME = 'NoColor'
138 138
139 139 # ---------------------------------------------------------------------------
140 140 # Code begins
141 141
142 142 # Utility functions
143 143 def inspect_error():
144 144 """Print a message about internal inspect errors.
145 145
146 146 These are unfortunately quite common."""
147 147
148 148 error('Internal Python error in the inspect module.\n'
149 149 'Below is the traceback from this internal error.\n')
150 150
151 151
152 152 # This function is a monkeypatch we apply to the Python inspect module. We have
153 153 # now found when it's needed (see discussion on issue gh-1456), and we have a
154 154 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
155 155 # the monkeypatch is not applied. TK, Aug 2012.
156 156 def findsource(object):
157 157 """Return the entire source file and starting line number for an object.
158 158
159 159 The argument may be a module, class, method, function, traceback, frame,
160 160 or code object. The source code is returned as a list of all the lines
161 161 in the file and the line number indexes a line in that list. An IOError
162 162 is raised if the source code cannot be retrieved.
163 163
164 164 FIXED version with which we monkeypatch the stdlib to work around a bug."""
165 165
166 166 file = getsourcefile(object) or getfile(object)
167 167 # If the object is a frame, then trying to get the globals dict from its
168 168 # module won't work. Instead, the frame object itself has the globals
169 169 # dictionary.
170 170 globals_dict = None
171 171 if inspect.isframe(object):
172 172 # XXX: can this ever be false?
173 173 globals_dict = object.f_globals
174 174 else:
175 175 module = getmodule(object, file)
176 176 if module:
177 177 globals_dict = module.__dict__
178 178 lines = linecache.getlines(file, globals_dict)
179 179 if not lines:
180 180 raise IOError('could not get source code')
181 181
182 182 if ismodule(object):
183 183 return lines, 0
184 184
185 185 if isclass(object):
186 186 name = object.__name__
187 187 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
188 188 # make some effort to find the best matching class definition:
189 189 # use the one with the least indentation, which is the one
190 190 # that's most probably not inside a function definition.
191 191 candidates = []
192 for i in range(len(lines)):
193 match = pat.match(lines[i])
192 for i, line in enumerate(lines):
193 match = pat.match(line)
194 194 if match:
195 195 # if it's at toplevel, it's already the best one
196 if lines[i][0] == 'c':
196 if line[0] == 'c':
197 197 return lines, i
198 198 # else add whitespace to candidate list
199 199 candidates.append((match.group(1), i))
200 200 if candidates:
201 201 # this will sort by whitespace, and by line number,
202 202 # less whitespace first
203 203 candidates.sort()
204 204 return lines, candidates[0][1]
205 205 else:
206 206 raise IOError('could not find class definition')
207 207
208 208 if ismethod(object):
209 209 object = object.__func__
210 210 if isfunction(object):
211 211 object = object.__code__
212 212 if istraceback(object):
213 213 object = object.tb_frame
214 214 if isframe(object):
215 215 object = object.f_code
216 216 if iscode(object):
217 217 if not hasattr(object, 'co_firstlineno'):
218 218 raise IOError('could not find function definition')
219 219 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
220 220 pmatch = pat.match
221 221 # fperez - fix: sometimes, co_firstlineno can give a number larger than
222 222 # the length of lines, which causes an error. Safeguard against that.
223 223 lnum = min(object.co_firstlineno, len(lines)) - 1
224 224 while lnum > 0:
225 225 if pmatch(lines[lnum]):
226 226 break
227 227 lnum -= 1
228 228
229 229 return lines, lnum
230 230 raise IOError('could not find code object')
231 231
232 232
233 233 # This is a patched version of inspect.getargs that applies the (unmerged)
234 234 # patch for http://bugs.python.org/issue14611 by Stefano Taschini. This fixes
235 235 # https://github.com/ipython/ipython/issues/8205 and
236 236 # https://github.com/ipython/ipython/issues/8293
237 237 def getargs(co):
238 238 """Get information about the arguments accepted by a code object.
239 239
240 240 Three things are returned: (args, varargs, varkw), where 'args' is
241 241 a list of argument names (possibly containing nested lists), and
242 242 'varargs' and 'varkw' are the names of the * and ** arguments or None."""
243 243 if not iscode(co):
244 244 raise TypeError('{!r} is not a code object'.format(co))
245 245
246 246 nargs = co.co_argcount
247 247 names = co.co_varnames
248 248 args = list(names[:nargs])
249 249 step = 0
250 250
251 251 # The following acrobatics are for anonymous (tuple) arguments.
252 252 for i in range(nargs):
253 253 if args[i][:1] in ('', '.'):
254 254 stack, remain, count = [], [], []
255 255 while step < len(co.co_code):
256 256 op = ord(co.co_code[step])
257 257 step = step + 1
258 258 if op >= dis.HAVE_ARGUMENT:
259 259 opname = dis.opname[op]
260 260 value = ord(co.co_code[step]) + ord(co.co_code[step+1])*256
261 261 step = step + 2
262 262 if opname in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'):
263 263 remain.append(value)
264 264 count.append(value)
265 265 elif opname in ('STORE_FAST', 'STORE_DEREF'):
266 266 if op in dis.haslocal:
267 267 stack.append(co.co_varnames[value])
268 268 elif op in dis.hasfree:
269 269 stack.append((co.co_cellvars + co.co_freevars)[value])
270 270 # Special case for sublists of length 1: def foo((bar))
271 271 # doesn't generate the UNPACK_TUPLE bytecode, so if
272 272 # `remain` is empty here, we have such a sublist.
273 273 if not remain:
274 274 stack[0] = [stack[0]]
275 275 break
276 276 else:
277 277 remain[-1] = remain[-1] - 1
278 278 while remain[-1] == 0:
279 279 remain.pop()
280 280 size = count.pop()
281 281 stack[-size:] = [stack[-size:]]
282 282 if not remain:
283 283 break
284 284 remain[-1] = remain[-1] - 1
285 285 if not remain:
286 286 break
287 287 args[i] = stack[0]
288 288
289 289 varargs = None
290 290 if co.co_flags & inspect.CO_VARARGS:
291 291 varargs = co.co_varnames[nargs]
292 292 nargs = nargs + 1
293 293 varkw = None
294 294 if co.co_flags & inspect.CO_VARKEYWORDS:
295 295 varkw = co.co_varnames[nargs]
296 296 return inspect.Arguments(args, varargs, varkw)
297 297
298 298
299 299 # Monkeypatch inspect to apply our bugfix.
300 300 def with_patch_inspect(f):
301 301 """
302 302 Deprecated since IPython 6.0
303 303 decorator for monkeypatching inspect.findsource
304 304 """
305 305
306 306 def wrapped(*args, **kwargs):
307 307 save_findsource = inspect.findsource
308 308 save_getargs = inspect.getargs
309 309 inspect.findsource = findsource
310 310 inspect.getargs = getargs
311 311 try:
312 312 return f(*args, **kwargs)
313 313 finally:
314 314 inspect.findsource = save_findsource
315 315 inspect.getargs = save_getargs
316 316
317 317 return wrapped
318 318
319 319
320 320 def fix_frame_records_filenames(records):
321 321 """Try to fix the filenames in each record from inspect.getinnerframes().
322 322
323 323 Particularly, modules loaded from within zip files have useless filenames
324 324 attached to their code object, and inspect.getinnerframes() just uses it.
325 325 """
326 326 fixed_records = []
327 327 for frame, filename, line_no, func_name, lines, index in records:
328 328 # Look inside the frame's globals dictionary for __file__,
329 329 # which should be better. However, keep Cython filenames since
330 330 # we prefer the source filenames over the compiled .so file.
331 331 filename = py3compat.cast_unicode_py2(filename, "utf-8")
332 332 if not filename.endswith(('.pyx', '.pxd', '.pxi')):
333 333 better_fn = frame.f_globals.get('__file__', None)
334 334 if isinstance(better_fn, str):
335 335 # Check the type just in case someone did something weird with
336 336 # __file__. It might also be None if the error occurred during
337 337 # import.
338 338 filename = better_fn
339 339 fixed_records.append((frame, filename, line_no, func_name, lines, index))
340 340 return fixed_records
341 341
342 342
343 343 @with_patch_inspect
344 344 def _fixed_getinnerframes(etb, context=1, tb_offset=0):
345 345 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
346 346
347 347 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
348 348 # If the error is at the console, don't build any context, since it would
349 349 # otherwise produce 5 blank lines printed out (there is no file at the
350 350 # console)
351 351 rec_check = records[tb_offset:]
352 352 try:
353 353 rname = rec_check[0][1]
354 354 if rname == '<ipython console>' or rname.endswith('<string>'):
355 355 return rec_check
356 356 except IndexError:
357 357 pass
358 358
359 359 aux = traceback.extract_tb(etb)
360 360 assert len(records) == len(aux)
361 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
361 for i, (file, lnum, _, _) in enumerate(aux):
362 362 maybeStart = lnum - 1 - context // 2
363 363 start = max(maybeStart, 0)
364 364 end = start + context
365 365 lines = linecache.getlines(file)[start:end]
366 366 buf = list(records[i])
367 367 buf[LNUM_POS] = lnum
368 368 buf[INDEX_POS] = lnum - 1 - start
369 369 buf[LINES_POS] = lines
370 370 records[i] = tuple(buf)
371 371 return records[tb_offset:]
372 372
373 373 # Helper function -- largely belongs to VerboseTB, but we need the same
374 374 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
375 375 # can be recognized properly by ipython.el's py-traceback-line-re
376 376 # (SyntaxErrors have to be treated specially because they have no traceback)
377 377
378 378
379 379 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None, _line_format=(lambda x,_:x,None)):
380 380 numbers_width = INDENT_SIZE - 1
381 381 res = []
382 382 i = lnum - index
383 383
384 384 for line in lines:
385 385 line = py3compat.cast_unicode(line)
386 386
387 387 new_line, err = _line_format(line, 'str')
388 388 if not err: line = new_line
389 389
390 390 if i == lnum:
391 391 # This is the line with the error
392 392 pad = numbers_width - len(str(i))
393 393 num = '%s%s' % (debugger.make_arrow(pad), str(lnum))
394 394 line = '%s%s%s %s%s' % (Colors.linenoEm, num,
395 395 Colors.line, line, Colors.Normal)
396 396 else:
397 397 num = '%*s' % (numbers_width, i)
398 398 line = '%s%s%s %s' % (Colors.lineno, num,
399 399 Colors.Normal, line)
400 400
401 401 res.append(line)
402 402 if lvals and i == lnum:
403 403 res.append(lvals + '\n')
404 404 i = i + 1
405 405 return res
406 406
407 407 def is_recursion_error(etype, value, records):
408 408 try:
409 409 # RecursionError is new in Python 3.5
410 410 recursion_error_type = RecursionError
411 411 except NameError:
412 412 recursion_error_type = RuntimeError
413 413
414 414 # The default recursion limit is 1000, but some of that will be taken up
415 415 # by stack frames in IPython itself. >500 frames probably indicates
416 416 # a recursion error.
417 417 return (etype is recursion_error_type) \
418 418 and "recursion" in str(value).lower() \
419 419 and len(records) > 500
420 420
421 421 def find_recursion(etype, value, records):
422 422 """Identify the repeating stack frames from a RecursionError traceback
423 423
424 424 'records' is a list as returned by VerboseTB.get_records()
425 425
426 426 Returns (last_unique, repeat_length)
427 427 """
428 428 # This involves a bit of guesswork - we want to show enough of the traceback
429 429 # to indicate where the recursion is occurring. We guess that the innermost
430 430 # quarter of the traceback (250 frames by default) is repeats, and find the
431 431 # first frame (from in to out) that looks different.
432 432 if not is_recursion_error(etype, value, records):
433 433 return len(records), 0
434 434
435 435 # Select filename, lineno, func_name to track frames with
436 436 records = [r[1:4] for r in records]
437 437 inner_frames = records[-(len(records)//4):]
438 438 frames_repeated = set(inner_frames)
439 439
440 440 last_seen_at = {}
441 441 longest_repeat = 0
442 442 i = len(records)
443 443 for frame in reversed(records):
444 444 i -= 1
445 445 if frame not in frames_repeated:
446 446 last_unique = i
447 447 break
448 448
449 449 if frame in last_seen_at:
450 450 distance = last_seen_at[frame] - i
451 451 longest_repeat = max(longest_repeat, distance)
452 452
453 453 last_seen_at[frame] = i
454 454 else:
455 455 last_unique = 0 # The whole traceback was recursion
456 456
457 457 return last_unique, longest_repeat
458 458
459 459 #---------------------------------------------------------------------------
460 460 # Module classes
461 461 class TBTools(colorable.Colorable):
462 462 """Basic tools used by all traceback printer classes."""
463 463
464 464 # Number of frames to skip when reporting tracebacks
465 465 tb_offset = 0
466 466
467 467 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
468 468 # Whether to call the interactive pdb debugger after printing
469 469 # tracebacks or not
470 470 super(TBTools, self).__init__(parent=parent, config=config)
471 471 self.call_pdb = call_pdb
472 472
473 473 # Output stream to write to. Note that we store the original value in
474 474 # a private attribute and then make the public ostream a property, so
475 475 # that we can delay accessing sys.stdout until runtime. The way
476 476 # things are written now, the sys.stdout object is dynamically managed
477 477 # so a reference to it should NEVER be stored statically. This
478 478 # property approach confines this detail to a single location, and all
479 479 # subclasses can simply access self.ostream for writing.
480 480 self._ostream = ostream
481 481
482 482 # Create color table
483 483 self.color_scheme_table = exception_colors()
484 484
485 485 self.set_colors(color_scheme)
486 486 self.old_scheme = color_scheme # save initial value for toggles
487 487
488 488 if call_pdb:
489 489 self.pdb = debugger.Pdb()
490 490 else:
491 491 self.pdb = None
492 492
493 493 def _get_ostream(self):
494 494 """Output stream that exceptions are written to.
495 495
496 496 Valid values are:
497 497
498 498 - None: the default, which means that IPython will dynamically resolve
499 499 to sys.stdout. This ensures compatibility with most tools, including
500 500 Windows (where plain stdout doesn't recognize ANSI escapes).
501 501
502 502 - Any object with 'write' and 'flush' attributes.
503 503 """
504 504 return sys.stdout if self._ostream is None else self._ostream
505 505
506 506 def _set_ostream(self, val):
507 507 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
508 508 self._ostream = val
509 509
510 510 ostream = property(_get_ostream, _set_ostream)
511 511
512 512 def set_colors(self, *args, **kw):
513 513 """Shorthand access to the color table scheme selector method."""
514 514
515 515 # Set own color table
516 516 self.color_scheme_table.set_active_scheme(*args, **kw)
517 517 # for convenience, set Colors to the active scheme
518 518 self.Colors = self.color_scheme_table.active_colors
519 519 # Also set colors of debugger
520 520 if hasattr(self, 'pdb') and self.pdb is not None:
521 521 self.pdb.set_colors(*args, **kw)
522 522
523 523 def color_toggle(self):
524 524 """Toggle between the currently active color scheme and NoColor."""
525 525
526 526 if self.color_scheme_table.active_scheme_name == 'NoColor':
527 527 self.color_scheme_table.set_active_scheme(self.old_scheme)
528 528 self.Colors = self.color_scheme_table.active_colors
529 529 else:
530 530 self.old_scheme = self.color_scheme_table.active_scheme_name
531 531 self.color_scheme_table.set_active_scheme('NoColor')
532 532 self.Colors = self.color_scheme_table.active_colors
533 533
534 534 def stb2text(self, stb):
535 535 """Convert a structured traceback (a list) to a string."""
536 536 return '\n'.join(stb)
537 537
538 538 def text(self, etype, value, tb, tb_offset=None, context=5):
539 539 """Return formatted traceback.
540 540
541 541 Subclasses may override this if they add extra arguments.
542 542 """
543 543 tb_list = self.structured_traceback(etype, value, tb,
544 544 tb_offset, context)
545 545 return self.stb2text(tb_list)
546 546
547 547 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
548 548 context=5, mode=None):
549 549 """Return a list of traceback frames.
550 550
551 551 Must be implemented by each class.
552 552 """
553 553 raise NotImplementedError()
554 554
555 555
556 556 #---------------------------------------------------------------------------
557 557 class ListTB(TBTools):
558 558 """Print traceback information from a traceback list, with optional color.
559 559
560 560 Calling requires 3 arguments: (etype, evalue, elist)
561 561 as would be obtained by::
562 562
563 563 etype, evalue, tb = sys.exc_info()
564 564 if tb:
565 565 elist = traceback.extract_tb(tb)
566 566 else:
567 567 elist = None
568 568
569 569 It can thus be used by programs which need to process the traceback before
570 570 printing (such as console replacements based on the code module from the
571 571 standard library).
572 572
573 573 Because they are meant to be called without a full traceback (only a
574 574 list), instances of this class can't call the interactive pdb debugger."""
575 575
576 576 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
577 577 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
578 578 ostream=ostream, parent=parent,config=config)
579 579
580 580 def __call__(self, etype, value, elist):
581 581 self.ostream.flush()
582 582 self.ostream.write(self.text(etype, value, elist))
583 583 self.ostream.write('\n')
584 584
585 585 def structured_traceback(self, etype, value, elist, tb_offset=None,
586 586 context=5):
587 587 """Return a color formatted string with the traceback info.
588 588
589 589 Parameters
590 590 ----------
591 591 etype : exception type
592 592 Type of the exception raised.
593 593
594 594 value : object
595 595 Data stored in the exception
596 596
597 597 elist : list
598 598 List of frames, see class docstring for details.
599 599
600 600 tb_offset : int, optional
601 601 Number of frames in the traceback to skip. If not given, the
602 602 instance value is used (set in constructor).
603 603
604 604 context : int, optional
605 605 Number of lines of context information to print.
606 606
607 607 Returns
608 608 -------
609 609 String with formatted exception.
610 610 """
611 611 tb_offset = self.tb_offset if tb_offset is None else tb_offset
612 612 Colors = self.Colors
613 613 out_list = []
614 614 if elist:
615 615
616 616 if tb_offset and len(elist) > tb_offset:
617 617 elist = elist[tb_offset:]
618 618
619 619 out_list.append('Traceback %s(most recent call last)%s:' %
620 620 (Colors.normalEm, Colors.Normal) + '\n')
621 621 out_list.extend(self._format_list(elist))
622 622 # The exception info should be a single entry in the list.
623 623 lines = ''.join(self._format_exception_only(etype, value))
624 624 out_list.append(lines)
625 625
626 626 # Note: this code originally read:
627 627
628 628 ## for line in lines[:-1]:
629 629 ## out_list.append(" "+line)
630 630 ## out_list.append(lines[-1])
631 631
632 632 # This means it was indenting everything but the last line by a little
633 633 # bit. I've disabled this for now, but if we see ugliness somewhere we
634 634 # can restore it.
635 635
636 636 return out_list
637 637
638 638 def _format_list(self, extracted_list):
639 639 """Format a list of traceback entry tuples for printing.
640 640
641 641 Given a list of tuples as returned by extract_tb() or
642 642 extract_stack(), return a list of strings ready for printing.
643 643 Each string in the resulting list corresponds to the item with the
644 644 same index in the argument list. Each string ends in a newline;
645 645 the strings may contain internal newlines as well, for those items
646 646 whose source text line is not None.
647 647
648 648 Lifted almost verbatim from traceback.py
649 649 """
650 650
651 651 Colors = self.Colors
652 652 list = []
653 653 for filename, lineno, name, line in extracted_list[:-1]:
654 654 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
655 655 (Colors.filename, py3compat.cast_unicode_py2(filename, "utf-8"), Colors.Normal,
656 656 Colors.lineno, lineno, Colors.Normal,
657 657 Colors.name, py3compat.cast_unicode_py2(name, "utf-8"), Colors.Normal)
658 658 if line:
659 659 item += ' %s\n' % line.strip()
660 660 list.append(item)
661 661 # Emphasize the last entry
662 662 filename, lineno, name, line = extracted_list[-1]
663 663 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
664 664 (Colors.normalEm,
665 665 Colors.filenameEm, py3compat.cast_unicode_py2(filename, "utf-8"), Colors.normalEm,
666 666 Colors.linenoEm, lineno, Colors.normalEm,
667 667 Colors.nameEm, py3compat.cast_unicode_py2(name, "utf-8"), Colors.normalEm,
668 668 Colors.Normal)
669 669 if line:
670 670 item += '%s %s%s\n' % (Colors.line, line.strip(),
671 671 Colors.Normal)
672 672 list.append(item)
673 673 return list
674 674
675 675 def _format_exception_only(self, etype, value):
676 676 """Format the exception part of a traceback.
677 677
678 678 The arguments are the exception type and value such as given by
679 679 sys.exc_info()[:2]. The return value is a list of strings, each ending
680 680 in a newline. Normally, the list contains a single string; however,
681 681 for SyntaxError exceptions, it contains several lines that (when
682 682 printed) display detailed information about where the syntax error
683 683 occurred. The message indicating which exception occurred is the
684 684 always last string in the list.
685 685
686 686 Also lifted nearly verbatim from traceback.py
687 687 """
688 688 have_filedata = False
689 689 Colors = self.Colors
690 690 list = []
691 691 stype = py3compat.cast_unicode(Colors.excName + etype.__name__ + Colors.Normal)
692 692 if value is None:
693 693 # Not sure if this can still happen in Python 2.6 and above
694 694 list.append(stype + '\n')
695 695 else:
696 696 if issubclass(etype, SyntaxError):
697 697 have_filedata = True
698 698 if not value.filename: value.filename = "<string>"
699 699 if value.lineno:
700 700 lineno = value.lineno
701 701 textline = linecache.getline(value.filename, value.lineno)
702 702 else:
703 703 lineno = 'unknown'
704 704 textline = ''
705 705 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
706 706 (Colors.normalEm,
707 707 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
708 708 Colors.linenoEm, lineno, Colors.Normal ))
709 709 if textline == '':
710 710 textline = py3compat.cast_unicode(value.text, "utf-8")
711 711
712 712 if textline is not None:
713 713 i = 0
714 714 while i < len(textline) and textline[i].isspace():
715 715 i += 1
716 716 list.append('%s %s%s\n' % (Colors.line,
717 717 textline.strip(),
718 718 Colors.Normal))
719 719 if value.offset is not None:
720 720 s = ' '
721 721 for c in textline[i:value.offset - 1]:
722 722 if c.isspace():
723 723 s += c
724 724 else:
725 725 s += ' '
726 726 list.append('%s%s^%s\n' % (Colors.caret, s,
727 727 Colors.Normal))
728 728
729 729 try:
730 730 s = value.msg
731 731 except Exception:
732 732 s = self._some_str(value)
733 733 if s:
734 734 list.append('%s%s:%s %s\n' % (stype, Colors.excName,
735 735 Colors.Normal, s))
736 736 else:
737 737 list.append('%s\n' % stype)
738 738
739 739 # sync with user hooks
740 740 if have_filedata:
741 741 ipinst = get_ipython()
742 742 if ipinst is not None:
743 743 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
744 744
745 745 return list
746 746
747 747 def get_exception_only(self, etype, value):
748 748 """Only print the exception type and message, without a traceback.
749 749
750 750 Parameters
751 751 ----------
752 752 etype : exception type
753 753 value : exception value
754 754 """
755 755 return ListTB.structured_traceback(self, etype, value, [])
756 756
757 757 def show_exception_only(self, etype, evalue):
758 758 """Only print the exception type and message, without a traceback.
759 759
760 760 Parameters
761 761 ----------
762 762 etype : exception type
763 763 value : exception value
764 764 """
765 765 # This method needs to use __call__ from *this* class, not the one from
766 766 # a subclass whose signature or behavior may be different
767 767 ostream = self.ostream
768 768 ostream.flush()
769 769 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
770 770 ostream.flush()
771 771
772 772 def _some_str(self, value):
773 773 # Lifted from traceback.py
774 774 try:
775 775 return py3compat.cast_unicode(str(value))
776 776 except:
777 777 return u'<unprintable %s object>' % type(value).__name__
778 778
779 779
780 780 #----------------------------------------------------------------------------
781 781 class VerboseTB(TBTools):
782 782 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
783 783 of HTML. Requires inspect and pydoc. Crazy, man.
784 784
785 785 Modified version which optionally strips the topmost entries from the
786 786 traceback, to be used with alternate interpreters (because their own code
787 787 would appear in the traceback)."""
788 788
789 789 def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None,
790 790 tb_offset=0, long_header=False, include_vars=True,
791 791 check_cache=None, debugger_cls = None,
792 792 parent=None, config=None):
793 793 """Specify traceback offset, headers and color scheme.
794 794
795 795 Define how many frames to drop from the tracebacks. Calling it with
796 796 tb_offset=1 allows use of this handler in interpreters which will have
797 797 their own code at the top of the traceback (VerboseTB will first
798 798 remove that frame before printing the traceback info)."""
799 799 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
800 800 ostream=ostream, parent=parent, config=config)
801 801 self.tb_offset = tb_offset
802 802 self.long_header = long_header
803 803 self.include_vars = include_vars
804 804 # By default we use linecache.checkcache, but the user can provide a
805 805 # different check_cache implementation. This is used by the IPython
806 806 # kernel to provide tracebacks for interactive code that is cached,
807 807 # by a compiler instance that flushes the linecache but preserves its
808 808 # own code cache.
809 809 if check_cache is None:
810 810 check_cache = linecache.checkcache
811 811 self.check_cache = check_cache
812 812
813 813 self.debugger_cls = debugger_cls or debugger.Pdb
814 814
815 815 def format_records(self, records, last_unique, recursion_repeat):
816 816 """Format the stack frames of the traceback"""
817 817 frames = []
818 818 for r in records[:last_unique+recursion_repeat+1]:
819 819 #print '*** record:',file,lnum,func,lines,index # dbg
820 820 frames.append(self.format_record(*r))
821 821
822 822 if recursion_repeat:
823 823 frames.append('... last %d frames repeated, from the frame below ...\n' % recursion_repeat)
824 824 frames.append(self.format_record(*records[last_unique+recursion_repeat+1]))
825 825
826 826 return frames
827 827
828 828 def format_record(self, frame, file, lnum, func, lines, index):
829 829 """Format a single stack frame"""
830 830 Colors = self.Colors # just a shorthand + quicker name lookup
831 831 ColorsNormal = Colors.Normal # used a lot
832 832 col_scheme = self.color_scheme_table.active_scheme_name
833 833 indent = ' ' * INDENT_SIZE
834 834 em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal)
835 835 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
836 836 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
837 837 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
838 838 ColorsNormal)
839 839 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
840 840 (Colors.vName, Colors.valEm, ColorsNormal)
841 841 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
842 842 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
843 843 Colors.vName, ColorsNormal)
844 844 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
845 845
846 846 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
847 847 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm, Colors.line,
848 848 ColorsNormal)
849 849
850 850 abspath = os.path.abspath
851 851
852 852
853 853 if not file:
854 854 file = '?'
855 855 elif file.startswith(str("<")) and file.endswith(str(">")):
856 856 # Not a real filename, no problem...
857 857 pass
858 858 elif not os.path.isabs(file):
859 859 # Try to make the filename absolute by trying all
860 860 # sys.path entries (which is also what linecache does)
861 861 for dirname in sys.path:
862 862 try:
863 863 fullname = os.path.join(dirname, file)
864 864 if os.path.isfile(fullname):
865 865 file = os.path.abspath(fullname)
866 866 break
867 867 except Exception:
868 868 # Just in case that sys.path contains very
869 869 # strange entries...
870 870 pass
871 871
872 872 file = py3compat.cast_unicode(file, util_path.fs_encoding)
873 873 link = tpl_link % file
874 874 args, varargs, varkw, locals = inspect.getargvalues(frame)
875 875
876 876 if func == '?':
877 877 call = ''
878 878 else:
879 879 # Decide whether to include variable details or not
880 880 var_repr = self.include_vars and eqrepr or nullrepr
881 881 try:
882 882 call = tpl_call % (func, inspect.formatargvalues(args,
883 883 varargs, varkw,
884 884 locals, formatvalue=var_repr))
885 885 except KeyError:
886 886 # This happens in situations like errors inside generator
887 887 # expressions, where local variables are listed in the
888 888 # line, but can't be extracted from the frame. I'm not
889 889 # 100% sure this isn't actually a bug in inspect itself,
890 890 # but since there's no info for us to compute with, the
891 891 # best we can do is report the failure and move on. Here
892 892 # we must *not* call any traceback construction again,
893 893 # because that would mess up use of %debug later on. So we
894 894 # simply report the failure and move on. The only
895 895 # limitation will be that this frame won't have locals
896 896 # listed in the call signature. Quite subtle problem...
897 897 # I can't think of a good way to validate this in a unit
898 898 # test, but running a script consisting of:
899 899 # dict( (k,v.strip()) for (k,v) in range(10) )
900 900 # will illustrate the error, if this exception catch is
901 901 # disabled.
902 902 call = tpl_call_fail % func
903 903
904 904 # Don't attempt to tokenize binary files.
905 905 if file.endswith(('.so', '.pyd', '.dll')):
906 906 return '%s %s\n' % (link, call)
907 907
908 908 elif file.endswith(('.pyc', '.pyo')):
909 909 # Look up the corresponding source file.
910 910 try:
911 911 file = openpy.source_from_cache(file)
912 912 except ValueError:
913 913 # Failed to get the source file for some reason
914 914 # E.g. https://github.com/ipython/ipython/issues/9486
915 915 return '%s %s\n' % (link, call)
916 916
917 917 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
918 918 line = getline(file, lnum[0])
919 919 lnum[0] += 1
920 920 return line
921 921
922 922 # Build the list of names on this line of code where the exception
923 923 # occurred.
924 924 try:
925 925 names = []
926 926 name_cont = False
927 927
928 928 for token_type, token, start, end, line in generate_tokens(linereader):
929 929 # build composite names
930 930 if token_type == tokenize.NAME and token not in keyword.kwlist:
931 931 if name_cont:
932 932 # Continuation of a dotted name
933 933 try:
934 934 names[-1].append(token)
935 935 except IndexError:
936 936 names.append([token])
937 937 name_cont = False
938 938 else:
939 939 # Regular new names. We append everything, the caller
940 940 # will be responsible for pruning the list later. It's
941 941 # very tricky to try to prune as we go, b/c composite
942 942 # names can fool us. The pruning at the end is easy
943 943 # to do (or the caller can print a list with repeated
944 944 # names if so desired.
945 945 names.append([token])
946 946 elif token == '.':
947 947 name_cont = True
948 948 elif token_type == tokenize.NEWLINE:
949 949 break
950 950
951 951 except (IndexError, UnicodeDecodeError, SyntaxError):
952 952 # signals exit of tokenizer
953 953 # SyntaxError can occur if the file is not actually Python
954 954 # - see gh-6300
955 955 pass
956 956 except tokenize.TokenError as msg:
957 957 _m = ("An unexpected error occurred while tokenizing input\n"
958 958 "The following traceback may be corrupted or invalid\n"
959 959 "The error message is: %s\n" % msg)
960 960 error(_m)
961 961
962 962 # Join composite names (e.g. "dict.fromkeys")
963 963 names = ['.'.join(n) for n in names]
964 964 # prune names list of duplicates, but keep the right order
965 965 unique_names = uniq_stable(names)
966 966
967 967 # Start loop over vars
968 968 lvals = []
969 969 if self.include_vars:
970 970 for name_full in unique_names:
971 971 name_base = name_full.split('.', 1)[0]
972 972 if name_base in frame.f_code.co_varnames:
973 973 if name_base in locals:
974 974 try:
975 975 value = repr(eval(name_full, locals))
976 976 except:
977 977 value = undefined
978 978 else:
979 979 value = undefined
980 980 name = tpl_local_var % name_full
981 981 else:
982 982 if name_base in frame.f_globals:
983 983 try:
984 984 value = repr(eval(name_full, frame.f_globals))
985 985 except:
986 986 value = undefined
987 987 else:
988 988 value = undefined
989 989 name = tpl_global_var % name_full
990 990 lvals.append(tpl_name_val % (name, value))
991 991 if lvals:
992 992 lvals = '%s%s' % (indent, em_normal.join(lvals))
993 993 else:
994 994 lvals = ''
995 995
996 996 level = '%s %s\n' % (link, call)
997 997
998 998 if index is None:
999 999 return level
1000 1000 else:
1001 1001 _line_format = PyColorize.Parser(style=col_scheme, parent=self).format2
1002 1002 return '%s%s' % (level, ''.join(
1003 1003 _format_traceback_lines(lnum, index, lines, Colors, lvals,
1004 1004 _line_format)))
1005 1005
1006 1006 def prepare_chained_exception_message(self, cause):
1007 1007 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
1008 1008 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
1009 1009
1010 1010 if cause:
1011 1011 message = [[direct_cause]]
1012 1012 else:
1013 1013 message = [[exception_during_handling]]
1014 1014 return message
1015 1015
1016 1016 def prepare_header(self, etype, long_version=False):
1017 1017 colors = self.Colors # just a shorthand + quicker name lookup
1018 1018 colorsnormal = colors.Normal # used a lot
1019 1019 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
1020 1020 width = min(75, get_terminal_size()[0])
1021 1021 if long_version:
1022 1022 # Header with the exception type, python version, and date
1023 1023 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
1024 1024 date = time.ctime(time.time())
1025 1025
1026 1026 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * width, colorsnormal,
1027 1027 exc, ' ' * (width - len(str(etype)) - len(pyver)),
1028 1028 pyver, date.rjust(width) )
1029 1029 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
1030 1030 "\ncalls leading up to the error, with the most recent (innermost) call last."
1031 1031 else:
1032 1032 # Simplified header
1033 1033 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
1034 1034 rjust(width - len(str(etype))) )
1035 1035
1036 1036 return head
1037 1037
1038 1038 def format_exception(self, etype, evalue):
1039 1039 colors = self.Colors # just a shorthand + quicker name lookup
1040 1040 colorsnormal = colors.Normal # used a lot
1041 1041 indent = ' ' * INDENT_SIZE
1042 1042 # Get (safely) a string form of the exception info
1043 1043 try:
1044 1044 etype_str, evalue_str = map(str, (etype, evalue))
1045 1045 except:
1046 1046 # User exception is improperly defined.
1047 1047 etype, evalue = str, sys.exc_info()[:2]
1048 1048 etype_str, evalue_str = map(str, (etype, evalue))
1049 1049 # ... and format it
1050 1050 return ['%s%s%s: %s' % (colors.excName, etype_str,
1051 1051 colorsnormal, py3compat.cast_unicode(evalue_str))]
1052 1052
1053 1053 def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset):
1054 1054 """Formats the header, traceback and exception message for a single exception.
1055 1055
1056 1056 This may be called multiple times by Python 3 exception chaining
1057 1057 (PEP 3134).
1058 1058 """
1059 1059 # some locals
1060 1060 orig_etype = etype
1061 1061 try:
1062 1062 etype = etype.__name__
1063 1063 except AttributeError:
1064 1064 pass
1065 1065
1066 1066 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1067 1067 head = self.prepare_header(etype, self.long_header)
1068 1068 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
1069 1069
1070 1070 if records is None:
1071 1071 return ""
1072 1072
1073 1073 last_unique, recursion_repeat = find_recursion(orig_etype, evalue, records)
1074 1074
1075 1075 frames = self.format_records(records, last_unique, recursion_repeat)
1076 1076
1077 1077 formatted_exception = self.format_exception(etype, evalue)
1078 1078 if records:
1079 1079 filepath, lnum = records[-1][1:3]
1080 1080 filepath = os.path.abspath(filepath)
1081 1081 ipinst = get_ipython()
1082 1082 if ipinst is not None:
1083 1083 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
1084 1084
1085 1085 return [[head] + frames + [''.join(formatted_exception[0])]]
1086 1086
1087 1087 def get_records(self, etb, number_of_lines_of_context, tb_offset):
1088 1088 try:
1089 1089 # Try the default getinnerframes and Alex's: Alex's fixes some
1090 1090 # problems, but it generates empty tracebacks for console errors
1091 1091 # (5 blanks lines) where none should be returned.
1092 1092 return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)
1093 1093 except UnicodeDecodeError:
1094 1094 # This can occur if a file's encoding magic comment is wrong.
1095 1095 # I can't see a way to recover without duplicating a bunch of code
1096 1096 # from the stdlib traceback module. --TK
1097 1097 error('\nUnicodeDecodeError while processing traceback.\n')
1098 1098 return None
1099 1099 except:
1100 1100 # FIXME: I've been getting many crash reports from python 2.3
1101 1101 # users, traceable to inspect.py. If I can find a small test-case
1102 1102 # to reproduce this, I should either write a better workaround or
1103 1103 # file a bug report against inspect (if that's the real problem).
1104 1104 # So far, I haven't been able to find an isolated example to
1105 1105 # reproduce the problem.
1106 1106 inspect_error()
1107 1107 traceback.print_exc(file=self.ostream)
1108 1108 info('\nUnfortunately, your original traceback can not be constructed.\n')
1109 1109 return None
1110 1110
1111 1111 def get_parts_of_chained_exception(self, evalue):
1112 1112 def get_chained_exception(exception_value):
1113 1113 cause = getattr(exception_value, '__cause__', None)
1114 1114 if cause:
1115 1115 return cause
1116 1116 if getattr(exception_value, '__suppress_context__', False):
1117 1117 return None
1118 1118 return getattr(exception_value, '__context__', None)
1119 1119
1120 1120 chained_evalue = get_chained_exception(evalue)
1121 1121
1122 1122 if chained_evalue:
1123 1123 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
1124 1124
1125 1125 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
1126 1126 number_of_lines_of_context=5):
1127 1127 """Return a nice text document describing the traceback."""
1128 1128
1129 1129 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
1130 1130 tb_offset)
1131 1131
1132 1132 colors = self.Colors # just a shorthand + quicker name lookup
1133 1133 colorsnormal = colors.Normal # used a lot
1134 1134 head = '%s%s%s' % (colors.topline, '-' * min(75, get_terminal_size()[0]), colorsnormal)
1135 1135 structured_traceback_parts = [head]
1136 1136 if py3compat.PY3:
1137 1137 chained_exceptions_tb_offset = 0
1138 1138 lines_of_context = 3
1139 1139 formatted_exceptions = formatted_exception
1140 1140 exception = self.get_parts_of_chained_exception(evalue)
1141 1141 if exception:
1142 1142 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1143 1143 etype, evalue, etb = exception
1144 1144 else:
1145 1145 evalue = None
1146 1146 chained_exc_ids = set()
1147 1147 while evalue:
1148 1148 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
1149 1149 chained_exceptions_tb_offset)
1150 1150 exception = self.get_parts_of_chained_exception(evalue)
1151 1151
1152 1152 if exception and not id(exception[1]) in chained_exc_ids:
1153 1153 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
1154 1154 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1155 1155 etype, evalue, etb = exception
1156 1156 else:
1157 1157 evalue = None
1158 1158
1159 1159 # we want to see exceptions in a reversed order:
1160 1160 # the first exception should be on top
1161 1161 for formatted_exception in reversed(formatted_exceptions):
1162 1162 structured_traceback_parts += formatted_exception
1163 1163 else:
1164 1164 structured_traceback_parts += formatted_exception[0]
1165 1165
1166 1166 return structured_traceback_parts
1167 1167
1168 1168 def debugger(self, force=False):
1169 1169 """Call up the pdb debugger if desired, always clean up the tb
1170 1170 reference.
1171 1171
1172 1172 Keywords:
1173 1173
1174 1174 - force(False): by default, this routine checks the instance call_pdb
1175 1175 flag and does not actually invoke the debugger if the flag is false.
1176 1176 The 'force' option forces the debugger to activate even if the flag
1177 1177 is false.
1178 1178
1179 1179 If the call_pdb flag is set, the pdb interactive debugger is
1180 1180 invoked. In all cases, the self.tb reference to the current traceback
1181 1181 is deleted to prevent lingering references which hamper memory
1182 1182 management.
1183 1183
1184 1184 Note that each call to pdb() does an 'import readline', so if your app
1185 1185 requires a special setup for the readline completers, you'll have to
1186 1186 fix that by hand after invoking the exception handler."""
1187 1187
1188 1188 if force or self.call_pdb:
1189 1189 if self.pdb is None:
1190 1190 self.pdb = self.debugger_cls()
1191 1191 # the system displayhook may have changed, restore the original
1192 1192 # for pdb
1193 1193 display_trap = DisplayTrap(hook=sys.__displayhook__)
1194 1194 with display_trap:
1195 1195 self.pdb.reset()
1196 1196 # Find the right frame so we don't pop up inside ipython itself
1197 1197 if hasattr(self, 'tb') and self.tb is not None:
1198 1198 etb = self.tb
1199 1199 else:
1200 1200 etb = self.tb = sys.last_traceback
1201 1201 while self.tb is not None and self.tb.tb_next is not None:
1202 1202 self.tb = self.tb.tb_next
1203 1203 if etb and etb.tb_next:
1204 1204 etb = etb.tb_next
1205 1205 self.pdb.botframe = etb.tb_frame
1206 1206 self.pdb.interaction(self.tb.tb_frame, self.tb)
1207 1207
1208 1208 if hasattr(self, 'tb'):
1209 1209 del self.tb
1210 1210
1211 1211 def handler(self, info=None):
1212 1212 (etype, evalue, etb) = info or sys.exc_info()
1213 1213 self.tb = etb
1214 1214 ostream = self.ostream
1215 1215 ostream.flush()
1216 1216 ostream.write(self.text(etype, evalue, etb))
1217 1217 ostream.write('\n')
1218 1218 ostream.flush()
1219 1219
1220 1220 # Changed so an instance can just be called as VerboseTB_inst() and print
1221 1221 # out the right info on its own.
1222 1222 def __call__(self, etype=None, evalue=None, etb=None):
1223 1223 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1224 1224 if etb is None:
1225 1225 self.handler()
1226 1226 else:
1227 1227 self.handler((etype, evalue, etb))
1228 1228 try:
1229 1229 self.debugger()
1230 1230 except KeyboardInterrupt:
1231 1231 print("\nKeyboardInterrupt")
1232 1232
1233 1233
1234 1234 #----------------------------------------------------------------------------
1235 1235 class FormattedTB(VerboseTB, ListTB):
1236 1236 """Subclass ListTB but allow calling with a traceback.
1237 1237
1238 1238 It can thus be used as a sys.excepthook for Python > 2.1.
1239 1239
1240 1240 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1241 1241
1242 1242 Allows a tb_offset to be specified. This is useful for situations where
1243 1243 one needs to remove a number of topmost frames from the traceback (such as
1244 1244 occurs with python programs that themselves execute other python code,
1245 1245 like Python shells). """
1246 1246
1247 1247 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1248 1248 ostream=None,
1249 1249 tb_offset=0, long_header=False, include_vars=False,
1250 1250 check_cache=None, debugger_cls=None,
1251 1251 parent=None, config=None):
1252 1252
1253 1253 # NEVER change the order of this list. Put new modes at the end:
1254 1254 self.valid_modes = ['Plain', 'Context', 'Verbose']
1255 1255 self.verbose_modes = self.valid_modes[1:3]
1256 1256
1257 1257 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1258 1258 ostream=ostream, tb_offset=tb_offset,
1259 1259 long_header=long_header, include_vars=include_vars,
1260 1260 check_cache=check_cache, debugger_cls=debugger_cls,
1261 1261 parent=parent, config=config)
1262 1262
1263 1263 # Different types of tracebacks are joined with different separators to
1264 1264 # form a single string. They are taken from this dict
1265 1265 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1266 1266 # set_mode also sets the tb_join_char attribute
1267 1267 self.set_mode(mode)
1268 1268
1269 1269 def _extract_tb(self, tb):
1270 1270 if tb:
1271 1271 return traceback.extract_tb(tb)
1272 1272 else:
1273 1273 return None
1274 1274
1275 1275 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
1276 1276 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1277 1277 mode = self.mode
1278 1278 if mode in self.verbose_modes:
1279 1279 # Verbose modes need a full traceback
1280 1280 return VerboseTB.structured_traceback(
1281 1281 self, etype, value, tb, tb_offset, number_of_lines_of_context
1282 1282 )
1283 1283 else:
1284 1284 # We must check the source cache because otherwise we can print
1285 1285 # out-of-date source code.
1286 1286 self.check_cache()
1287 1287 # Now we can extract and format the exception
1288 1288 elist = self._extract_tb(tb)
1289 1289 return ListTB.structured_traceback(
1290 1290 self, etype, value, elist, tb_offset, number_of_lines_of_context
1291 1291 )
1292 1292
1293 1293 def stb2text(self, stb):
1294 1294 """Convert a structured traceback (a list) to a string."""
1295 1295 return self.tb_join_char.join(stb)
1296 1296
1297 1297
1298 1298 def set_mode(self, mode=None):
1299 1299 """Switch to the desired mode.
1300 1300
1301 1301 If mode is not specified, cycles through the available modes."""
1302 1302
1303 1303 if not mode:
1304 1304 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
1305 1305 len(self.valid_modes)
1306 1306 self.mode = self.valid_modes[new_idx]
1307 1307 elif mode not in self.valid_modes:
1308 1308 raise ValueError('Unrecognized mode in FormattedTB: <' + mode + '>\n'
1309 1309 'Valid modes: ' + str(self.valid_modes))
1310 1310 else:
1311 1311 self.mode = mode
1312 1312 # include variable details only in 'Verbose' mode
1313 1313 self.include_vars = (self.mode == self.valid_modes[2])
1314 1314 # Set the join character for generating text tracebacks
1315 1315 self.tb_join_char = self._join_chars[self.mode]
1316 1316
1317 1317 # some convenient shortcuts
1318 1318 def plain(self):
1319 1319 self.set_mode(self.valid_modes[0])
1320 1320
1321 1321 def context(self):
1322 1322 self.set_mode(self.valid_modes[1])
1323 1323
1324 1324 def verbose(self):
1325 1325 self.set_mode(self.valid_modes[2])
1326 1326
1327 1327
1328 1328 #----------------------------------------------------------------------------
1329 1329 class AutoFormattedTB(FormattedTB):
1330 1330 """A traceback printer which can be called on the fly.
1331 1331
1332 1332 It will find out about exceptions by itself.
1333 1333
1334 1334 A brief example::
1335 1335
1336 1336 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1337 1337 try:
1338 1338 ...
1339 1339 except:
1340 1340 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1341 1341 """
1342 1342
1343 1343 def __call__(self, etype=None, evalue=None, etb=None,
1344 1344 out=None, tb_offset=None):
1345 1345 """Print out a formatted exception traceback.
1346 1346
1347 1347 Optional arguments:
1348 1348 - out: an open file-like object to direct output to.
1349 1349
1350 1350 - tb_offset: the number of frames to skip over in the stack, on a
1351 1351 per-call basis (this overrides temporarily the instance's tb_offset
1352 1352 given at initialization time. """
1353 1353
1354 1354 if out is None:
1355 1355 out = self.ostream
1356 1356 out.flush()
1357 1357 out.write(self.text(etype, evalue, etb, tb_offset))
1358 1358 out.write('\n')
1359 1359 out.flush()
1360 1360 # FIXME: we should remove the auto pdb behavior from here and leave
1361 1361 # that to the clients.
1362 1362 try:
1363 1363 self.debugger()
1364 1364 except KeyboardInterrupt:
1365 1365 print("\nKeyboardInterrupt")
1366 1366
1367 1367 def structured_traceback(self, etype=None, value=None, tb=None,
1368 1368 tb_offset=None, number_of_lines_of_context=5):
1369 1369 if etype is None:
1370 1370 etype, value, tb = sys.exc_info()
1371 1371 self.tb = tb
1372 1372 return FormattedTB.structured_traceback(
1373 1373 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1374 1374
1375 1375
1376 1376 #---------------------------------------------------------------------------
1377 1377
1378 1378 # A simple class to preserve Nathan's original functionality.
1379 1379 class ColorTB(FormattedTB):
1380 1380 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1381 1381
1382 1382 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1383 1383 FormattedTB.__init__(self, color_scheme=color_scheme,
1384 1384 call_pdb=call_pdb, **kwargs)
1385 1385
1386 1386
1387 1387 class SyntaxTB(ListTB):
1388 1388 """Extension which holds some state: the last exception value"""
1389 1389
1390 1390 def __init__(self, color_scheme='NoColor', parent=None, config=None):
1391 1391 ListTB.__init__(self, color_scheme, parent=parent, config=config)
1392 1392 self.last_syntax_error = None
1393 1393
1394 1394 def __call__(self, etype, value, elist):
1395 1395 self.last_syntax_error = value
1396 1396
1397 1397 ListTB.__call__(self, etype, value, elist)
1398 1398
1399 1399 def structured_traceback(self, etype, value, elist, tb_offset=None,
1400 1400 context=5):
1401 1401 # If the source file has been edited, the line in the syntax error can
1402 1402 # be wrong (retrieved from an outdated cache). This replaces it with
1403 1403 # the current value.
1404 1404 if isinstance(value, SyntaxError) \
1405 1405 and isinstance(value.filename, str) \
1406 1406 and isinstance(value.lineno, int):
1407 1407 linecache.checkcache(value.filename)
1408 1408 newtext = linecache.getline(value.filename, value.lineno)
1409 1409 if newtext:
1410 1410 value.text = newtext
1411 1411 self.last_syntax_error = value
1412 1412 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1413 1413 tb_offset=tb_offset, context=context)
1414 1414
1415 1415 def clear_err_state(self):
1416 1416 """Return the current error state and clear it"""
1417 1417 e = self.last_syntax_error
1418 1418 self.last_syntax_error = None
1419 1419 return e
1420 1420
1421 1421 def stb2text(self, stb):
1422 1422 """Convert a structured traceback (a list) to a string."""
1423 1423 return ''.join(stb)
1424 1424
1425 1425
1426 1426 # some internal-use functions
1427 1427 def text_repr(value):
1428 1428 """Hopefully pretty robust repr equivalent."""
1429 1429 # this is pretty horrible but should always return *something*
1430 1430 try:
1431 1431 return pydoc.text.repr(value)
1432 1432 except KeyboardInterrupt:
1433 1433 raise
1434 1434 except:
1435 1435 try:
1436 1436 return repr(value)
1437 1437 except KeyboardInterrupt:
1438 1438 raise
1439 1439 except:
1440 1440 try:
1441 1441 # all still in an except block so we catch
1442 1442 # getattr raising
1443 1443 name = getattr(value, '__name__', None)
1444 1444 if name:
1445 1445 # ick, recursion
1446 1446 return text_repr(name)
1447 1447 klass = getattr(value, '__class__', None)
1448 1448 if klass:
1449 1449 return '%s instance' % text_repr(klass)
1450 1450 except KeyboardInterrupt:
1451 1451 raise
1452 1452 except:
1453 1453 return 'UNRECOVERABLE REPR FAILURE'
1454 1454
1455 1455
1456 1456 def eqrepr(value, repr=text_repr):
1457 1457 return '=%s' % repr(value)
1458 1458
1459 1459
1460 1460 def nullrepr(value, repr=text_repr):
1461 1461 return ''
@@ -1,127 +1,127
1 1 """Token-related utilities"""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6
7 7 from collections import namedtuple
8 8 from io import StringIO
9 9 from keyword import iskeyword
10 10
11 11 from . import tokenize2
12 12 from .py3compat import cast_unicode_py2
13 13
14 14 Token = namedtuple('Token', ['token', 'text', 'start', 'end', 'line'])
15 15
16 16 def generate_tokens(readline):
17 17 """wrap generate_tokens to catch EOF errors"""
18 18 try:
19 19 for token in tokenize2.generate_tokens(readline):
20 20 yield token
21 21 except tokenize2.TokenError:
22 22 # catch EOF error
23 23 return
24 24
25 25 def line_at_cursor(cell, cursor_pos=0):
26 26 """Return the line in a cell at a given cursor position
27 27
28 28 Used for calling line-based APIs that don't support multi-line input, yet.
29 29
30 30 Parameters
31 31 ----------
32 32
33 33 cell: str
34 34 multiline block of text
35 35 cursor_pos: integer
36 36 the cursor position
37 37
38 38 Returns
39 39 -------
40 40
41 41 (line, offset): (text, integer)
42 42 The line with the current cursor, and the character offset of the start of the line.
43 43 """
44 44 offset = 0
45 45 lines = cell.splitlines(True)
46 46 for line in lines:
47 47 next_offset = offset + len(line)
48 48 if next_offset >= cursor_pos:
49 49 break
50 50 offset = next_offset
51 51 else:
52 52 line = ""
53 53 return (line, offset)
54 54
55 55 def token_at_cursor(cell, cursor_pos=0):
56 56 """Get the token at a given cursor
57 57
58 58 Used for introspection.
59 59
60 60 Function calls are prioritized, so the token for the callable will be returned
61 61 if the cursor is anywhere inside the call.
62 62
63 63 Parameters
64 64 ----------
65 65
66 66 cell : unicode
67 67 A block of Python code
68 68 cursor_pos : int
69 69 The location of the cursor in the block where the token should be found
70 70 """
71 71 cell = cast_unicode_py2(cell)
72 72 names = []
73 73 tokens = []
74 74 call_names = []
75 75
76 76 offsets = {1: 0} # lines start at 1
77 77 for tup in generate_tokens(StringIO(cell).readline):
78 78
79 79 tok = Token(*tup)
80 80
81 81 # token, text, start, end, line = tup
82 82 start_line, start_col = tok.start
83 83 end_line, end_col = tok.end
84 84 if end_line + 1 not in offsets:
85 85 # keep track of offsets for each line
86 86 lines = tok.line.splitlines(True)
87 for lineno, line in zip(range(start_line + 1, end_line + 2), lines):
87 for lineno, line in enumerate(lines, start_line + 1):
88 88 if lineno not in offsets:
89 89 offsets[lineno] = offsets[lineno-1] + len(line)
90 90
91 91 offset = offsets[start_line]
92 92 # allow '|foo' to find 'foo' at the beginning of a line
93 93 boundary = cursor_pos + 1 if start_col == 0 else cursor_pos
94 94 if offset + start_col >= boundary:
95 95 # current token starts after the cursor,
96 96 # don't consume it
97 97 break
98 98
99 99 if tok.token == tokenize2.NAME and not iskeyword(tok.text):
100 100 if names and tokens and tokens[-1].token == tokenize2.OP and tokens[-1].text == '.':
101 101 names[-1] = "%s.%s" % (names[-1], tok.text)
102 102 else:
103 103 names.append(tok.text)
104 104 elif tok.token == tokenize2.OP:
105 105 if tok.text == '=' and names:
106 106 # don't inspect the lhs of an assignment
107 107 names.pop(-1)
108 108 if tok.text == '(' and names:
109 109 # if we are inside a function call, inspect the function
110 110 call_names.append(names[-1])
111 111 elif tok.text == ')' and call_names:
112 112 call_names.pop(-1)
113 113
114 114 tokens.append(tok)
115 115
116 116 if offsets[end_line] + end_col > cursor_pos:
117 117 # we found the cursor, stop reading
118 118 break
119 119
120 120 if call_names:
121 121 return call_names[-1]
122 122 elif names:
123 123 return names[-1]
124 124 else:
125 125 return ''
126 126
127 127
General Comments 0
You need to be logged in to leave comments. Login now