##// END OF EJS Templates
apply tuple_param_fix
Matthias BUSSONNIER -
Show More
@@ -1,1244 +1,1245 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 ultratb.py -- Spice up your tracebacks!
4 4
5 5 * ColorTB
6 6 I've always found it a bit hard to visually parse tracebacks in Python. The
7 7 ColorTB class is a solution to that problem. It colors the different parts of a
8 8 traceback in a manner similar to what you would expect from a syntax-highlighting
9 9 text editor.
10 10
11 11 Installation instructions for ColorTB:
12 12 import sys,ultratb
13 13 sys.excepthook = ultratb.ColorTB()
14 14
15 15 * VerboseTB
16 16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
17 17 of useful info when a traceback occurs. Ping originally had it spit out HTML
18 18 and intended it for CGI programmers, but why should they have all the fun? I
19 19 altered it to spit out colored text to the terminal. It's a bit overwhelming,
20 20 but kind of neat, and maybe useful for long-running programs that you believe
21 21 are bug-free. If a crash *does* occur in that type of program you want details.
22 22 Give it a shot--you'll love it or you'll hate it.
23 23
24 24 Note:
25 25
26 26 The Verbose mode prints the variables currently visible where the exception
27 27 happened (shortening their strings if too long). This can potentially be
28 28 very slow, if you happen to have a huge data structure whose string
29 29 representation is complex to compute. Your computer may appear to freeze for
30 30 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
31 31 with Ctrl-C (maybe hitting it more than once).
32 32
33 33 If you encounter this kind of situation often, you may want to use the
34 34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
35 35 variables (but otherwise includes the information and context given by
36 36 Verbose).
37 37
38 38
39 39 Installation instructions for ColorTB:
40 40 import sys,ultratb
41 41 sys.excepthook = ultratb.VerboseTB()
42 42
43 43 Note: Much of the code in this module was lifted verbatim from the standard
44 44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
45 45
46 46 * Color schemes
47 47 The colors are defined in the class TBTools through the use of the
48 48 ColorSchemeTable class. Currently the following exist:
49 49
50 50 - NoColor: allows all of this module to be used in any terminal (the color
51 51 escapes are just dummy blank strings).
52 52
53 53 - Linux: is meant to look good in a terminal like the Linux console (black
54 54 or very dark background).
55 55
56 56 - LightBG: similar to Linux but swaps dark/light colors to be more readable
57 57 in light background terminals.
58 58
59 59 You can implement other color schemes easily, the syntax is fairly
60 60 self-explanatory. Please send back new schemes you develop to the author for
61 61 possible inclusion in future releases.
62 62 """
63 63
64 64 #*****************************************************************************
65 65 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
66 66 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
67 67 #
68 68 # Distributed under the terms of the BSD License. The full license is in
69 69 # the file COPYING, distributed as part of this software.
70 70 #*****************************************************************************
71 71
72 72 from __future__ import with_statement
73 73
74 74 import inspect
75 75 import keyword
76 76 import linecache
77 77 import os
78 78 import pydoc
79 79 import re
80 80 import sys
81 81 import time
82 82 import tokenize
83 83 import traceback
84 84 import types
85 85
86 86 try: # Python 2
87 87 generate_tokens = tokenize.generate_tokens
88 88 except AttributeError: # Python 3
89 89 generate_tokens = tokenize.tokenize
90 90
91 91 # For purposes of monkeypatching inspect to fix a bug in it.
92 92 from inspect import getsourcefile, getfile, getmodule,\
93 93 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
94 94
95 95 # IPython's own modules
96 96 # Modified pdb which doesn't damage IPython's readline handling
97 97 from IPython.core import debugger, ipapi
98 98 from IPython.core.display_trap import DisplayTrap
99 99 from IPython.core.excolors import exception_colors
100 100 from IPython.utils import PyColorize
101 101 from IPython.utils import io
102 102 from IPython.utils import py3compat
103 103 from IPython.utils import pyfile
104 104 from IPython.utils.data import uniq_stable
105 105 from IPython.utils.warn import info, error
106 106
107 107 # Globals
108 108 # amount of space to put line numbers before verbose tracebacks
109 109 INDENT_SIZE = 8
110 110
111 111 # Default color scheme. This is used, for example, by the traceback
112 112 # formatter. When running in an actual IPython instance, the user's rc.colors
113 113 # value is used, but havinga module global makes this functionality available
114 114 # to users of ultratb who are NOT running inside ipython.
115 115 DEFAULT_SCHEME = 'NoColor'
116 116
117 117 #---------------------------------------------------------------------------
118 118 # Code begins
119 119
120 120 # Utility functions
121 121 def inspect_error():
122 122 """Print a message about internal inspect errors.
123 123
124 124 These are unfortunately quite common."""
125 125
126 126 error('Internal Python error in the inspect module.\n'
127 127 'Below is the traceback from this internal error.\n')
128 128
129 129
130 130 # N.B. This function is a monkeypatch we are currently not applying.
131 131 # It was written some time ago, to fix an apparent Python bug with
132 132 # codeobj.co_firstlineno . Unfortunately, we don't know under what conditions
133 133 # the bug occurred, so we can't tell if it has been fixed. If it reappears, we
134 134 # will apply the monkeypatch again. Also, note that findsource() is not called
135 135 # by our code at this time - we don't know if it was when the monkeypatch was
136 136 # written, or if the monkeypatch is needed for some other code (like a debugger).
137 137 # For the discussion about not applying it, see gh-1229. TK, Jan 2011.
138 138 def findsource(object):
139 139 """Return the entire source file and starting line number for an object.
140 140
141 141 The argument may be a module, class, method, function, traceback, frame,
142 142 or code object. The source code is returned as a list of all the lines
143 143 in the file and the line number indexes a line in that list. An IOError
144 144 is raised if the source code cannot be retrieved.
145 145
146 146 FIXED version with which we monkeypatch the stdlib to work around a bug."""
147 147
148 148 file = getsourcefile(object) or getfile(object)
149 149 # If the object is a frame, then trying to get the globals dict from its
150 150 # module won't work. Instead, the frame object itself has the globals
151 151 # dictionary.
152 152 globals_dict = None
153 153 if inspect.isframe(object):
154 154 # XXX: can this ever be false?
155 155 globals_dict = object.f_globals
156 156 else:
157 157 module = getmodule(object, file)
158 158 if module:
159 159 globals_dict = module.__dict__
160 160 lines = linecache.getlines(file, globals_dict)
161 161 if not lines:
162 162 raise IOError('could not get source code')
163 163
164 164 if ismodule(object):
165 165 return lines, 0
166 166
167 167 if isclass(object):
168 168 name = object.__name__
169 169 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
170 170 # make some effort to find the best matching class definition:
171 171 # use the one with the least indentation, which is the one
172 172 # that's most probably not inside a function definition.
173 173 candidates = []
174 174 for i in range(len(lines)):
175 175 match = pat.match(lines[i])
176 176 if match:
177 177 # if it's at toplevel, it's already the best one
178 178 if lines[i][0] == 'c':
179 179 return lines, i
180 180 # else add whitespace to candidate list
181 181 candidates.append((match.group(1), i))
182 182 if candidates:
183 183 # this will sort by whitespace, and by line number,
184 184 # less whitespace first
185 185 candidates.sort()
186 186 return lines, candidates[0][1]
187 187 else:
188 188 raise IOError('could not find class definition')
189 189
190 190 if ismethod(object):
191 191 object = object.im_func
192 192 if isfunction(object):
193 193 object = object.func_code
194 194 if istraceback(object):
195 195 object = object.tb_frame
196 196 if isframe(object):
197 197 object = object.f_code
198 198 if iscode(object):
199 199 if not hasattr(object, 'co_firstlineno'):
200 200 raise IOError('could not find function definition')
201 201 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
202 202 pmatch = pat.match
203 203 # fperez - fix: sometimes, co_firstlineno can give a number larger than
204 204 # the length of lines, which causes an error. Safeguard against that.
205 205 lnum = min(object.co_firstlineno,len(lines))-1
206 206 while lnum > 0:
207 207 if pmatch(lines[lnum]): break
208 208 lnum -= 1
209 209
210 210 return lines, lnum
211 211 raise IOError('could not find code object')
212 212
213 213 # Not applying the monkeypatch - see above the function for details. TK, Jan 2012
214 214 # Monkeypatch inspect to apply our bugfix. This code only works with py25
215 215 #if sys.version_info[:2] >= (2,5):
216 216 # inspect.findsource = findsource
217 217
218 218 def fix_frame_records_filenames(records):
219 219 """Try to fix the filenames in each record from inspect.getinnerframes().
220 220
221 221 Particularly, modules loaded from within zip files have useless filenames
222 222 attached to their code object, and inspect.getinnerframes() just uses it.
223 223 """
224 224 fixed_records = []
225 225 for frame, filename, line_no, func_name, lines, index in records:
226 226 # Look inside the frame's globals dictionary for __file__, which should
227 227 # be better.
228 228 better_fn = frame.f_globals.get('__file__', None)
229 229 if isinstance(better_fn, str):
230 230 # Check the type just in case someone did something weird with
231 231 # __file__. It might also be None if the error occurred during
232 232 # import.
233 233 filename = better_fn
234 234 fixed_records.append((frame, filename, line_no, func_name, lines, index))
235 235 return fixed_records
236 236
237 237
238 238 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
239 239 import linecache
240 240 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
241 241
242 242 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
243 243
244 244 # If the error is at the console, don't build any context, since it would
245 245 # otherwise produce 5 blank lines printed out (there is no file at the
246 246 # console)
247 247 rec_check = records[tb_offset:]
248 248 try:
249 249 rname = rec_check[0][1]
250 250 if rname == '<ipython console>' or rname.endswith('<string>'):
251 251 return rec_check
252 252 except IndexError:
253 253 pass
254 254
255 255 aux = traceback.extract_tb(etb)
256 256 assert len(records) == len(aux)
257 257 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
258 258 maybeStart = lnum-1 - context//2
259 259 start = max(maybeStart, 0)
260 260 end = start + context
261 261 lines = linecache.getlines(file)[start:end]
262 262 buf = list(records[i])
263 263 buf[LNUM_POS] = lnum
264 264 buf[INDEX_POS] = lnum - 1 - start
265 265 buf[LINES_POS] = lines
266 266 records[i] = tuple(buf)
267 267 return records[tb_offset:]
268 268
269 269 # Helper function -- largely belongs to VerboseTB, but we need the same
270 270 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
271 271 # can be recognized properly by ipython.el's py-traceback-line-re
272 272 # (SyntaxErrors have to be treated specially because they have no traceback)
273 273
274 274 _parser = PyColorize.Parser()
275 275
276 276 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
277 277 numbers_width = INDENT_SIZE - 1
278 278 res = []
279 279 i = lnum - index
280 280
281 281 # This lets us get fully syntax-highlighted tracebacks.
282 282 if scheme is None:
283 283 ipinst = ipapi.get()
284 284 if ipinst is not None:
285 285 scheme = ipinst.colors
286 286 else:
287 287 scheme = DEFAULT_SCHEME
288 288
289 289 _line_format = _parser.format2
290 290
291 291 for line in lines:
292 292 # FIXME: we need to ensure the source is a pure string at this point,
293 293 # else the coloring code makes a royal mess. This is in need of a
294 294 # serious refactoring, so that all of the ultratb and PyColorize code
295 295 # is unicode-safe. So for now this is rather an ugly hack, but
296 296 # necessary to at least have readable tracebacks. Improvements welcome!
297 297 line = py3compat.cast_bytes_py2(line, 'utf-8')
298 298
299 299 new_line, err = _line_format(line, 'str', scheme)
300 300 if not err: line = new_line
301 301
302 302 if i == lnum:
303 303 # This is the line with the error
304 304 pad = numbers_width - len(str(i))
305 305 if pad >= 3:
306 306 marker = '-'*(pad-3) + '-> '
307 307 elif pad == 2:
308 308 marker = '> '
309 309 elif pad == 1:
310 310 marker = '>'
311 311 else:
312 312 marker = ''
313 313 num = marker + str(i)
314 314 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
315 315 Colors.line, line, Colors.Normal)
316 316 else:
317 317 num = '%*s' % (numbers_width,i)
318 318 line = '%s%s%s %s' %(Colors.lineno, num,
319 319 Colors.Normal, line)
320 320
321 321 res.append(line)
322 322 if lvals and i == lnum:
323 323 res.append(lvals + '\n')
324 324 i = i + 1
325 325 return res
326 326
327 327
328 328 #---------------------------------------------------------------------------
329 329 # Module classes
330 330 class TBTools(object):
331 331 """Basic tools used by all traceback printer classes."""
332 332
333 333 # Number of frames to skip when reporting tracebacks
334 334 tb_offset = 0
335 335
336 336 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
337 337 # Whether to call the interactive pdb debugger after printing
338 338 # tracebacks or not
339 339 self.call_pdb = call_pdb
340 340
341 341 # Output stream to write to. Note that we store the original value in
342 342 # a private attribute and then make the public ostream a property, so
343 343 # that we can delay accessing io.stdout until runtime. The way
344 344 # things are written now, the io.stdout object is dynamically managed
345 345 # so a reference to it should NEVER be stored statically. This
346 346 # property approach confines this detail to a single location, and all
347 347 # subclasses can simply access self.ostream for writing.
348 348 self._ostream = ostream
349 349
350 350 # Create color table
351 351 self.color_scheme_table = exception_colors()
352 352
353 353 self.set_colors(color_scheme)
354 354 self.old_scheme = color_scheme # save initial value for toggles
355 355
356 356 if call_pdb:
357 357 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
358 358 else:
359 359 self.pdb = None
360 360
361 361 def _get_ostream(self):
362 362 """Output stream that exceptions are written to.
363 363
364 364 Valid values are:
365 365
366 366 - None: the default, which means that IPython will dynamically resolve
367 367 to io.stdout. This ensures compatibility with most tools, including
368 368 Windows (where plain stdout doesn't recognize ANSI escapes).
369 369
370 370 - Any object with 'write' and 'flush' attributes.
371 371 """
372 372 return io.stdout if self._ostream is None else self._ostream
373 373
374 374 def _set_ostream(self, val):
375 375 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
376 376 self._ostream = val
377 377
378 378 ostream = property(_get_ostream, _set_ostream)
379 379
380 380 def set_colors(self,*args,**kw):
381 381 """Shorthand access to the color table scheme selector method."""
382 382
383 383 # Set own color table
384 384 self.color_scheme_table.set_active_scheme(*args,**kw)
385 385 # for convenience, set Colors to the active scheme
386 386 self.Colors = self.color_scheme_table.active_colors
387 387 # Also set colors of debugger
388 388 if hasattr(self,'pdb') and self.pdb is not None:
389 389 self.pdb.set_colors(*args,**kw)
390 390
391 391 def color_toggle(self):
392 392 """Toggle between the currently active color scheme and NoColor."""
393 393
394 394 if self.color_scheme_table.active_scheme_name == 'NoColor':
395 395 self.color_scheme_table.set_active_scheme(self.old_scheme)
396 396 self.Colors = self.color_scheme_table.active_colors
397 397 else:
398 398 self.old_scheme = self.color_scheme_table.active_scheme_name
399 399 self.color_scheme_table.set_active_scheme('NoColor')
400 400 self.Colors = self.color_scheme_table.active_colors
401 401
402 402 def stb2text(self, stb):
403 403 """Convert a structured traceback (a list) to a string."""
404 404 return '\n'.join(stb)
405 405
406 406 def text(self, etype, value, tb, tb_offset=None, context=5):
407 407 """Return formatted traceback.
408 408
409 409 Subclasses may override this if they add extra arguments.
410 410 """
411 411 tb_list = self.structured_traceback(etype, value, tb,
412 412 tb_offset, context)
413 413 return self.stb2text(tb_list)
414 414
415 415 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
416 416 context=5, mode=None):
417 417 """Return a list of traceback frames.
418 418
419 419 Must be implemented by each class.
420 420 """
421 421 raise NotImplementedError()
422 422
423 423
424 424 #---------------------------------------------------------------------------
425 425 class ListTB(TBTools):
426 426 """Print traceback information from a traceback list, with optional color.
427 427
428 428 Calling: requires 3 arguments:
429 429 (etype, evalue, elist)
430 430 as would be obtained by:
431 431 etype, evalue, tb = sys.exc_info()
432 432 if tb:
433 433 elist = traceback.extract_tb(tb)
434 434 else:
435 435 elist = None
436 436
437 437 It can thus be used by programs which need to process the traceback before
438 438 printing (such as console replacements based on the code module from the
439 439 standard library).
440 440
441 441 Because they are meant to be called without a full traceback (only a
442 442 list), instances of this class can't call the interactive pdb debugger."""
443 443
444 444 def __init__(self,color_scheme = 'NoColor', call_pdb=False, ostream=None):
445 445 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
446 446 ostream=ostream)
447 447
448 448 def __call__(self, etype, value, elist):
449 449 self.ostream.flush()
450 450 self.ostream.write(self.text(etype, value, elist))
451 451 self.ostream.write('\n')
452 452
453 453 def structured_traceback(self, etype, value, elist, tb_offset=None,
454 454 context=5):
455 455 """Return a color formatted string with the traceback info.
456 456
457 457 Parameters
458 458 ----------
459 459 etype : exception type
460 460 Type of the exception raised.
461 461
462 462 value : object
463 463 Data stored in the exception
464 464
465 465 elist : list
466 466 List of frames, see class docstring for details.
467 467
468 468 tb_offset : int, optional
469 469 Number of frames in the traceback to skip. If not given, the
470 470 instance value is used (set in constructor).
471 471
472 472 context : int, optional
473 473 Number of lines of context information to print.
474 474
475 475 Returns
476 476 -------
477 477 String with formatted exception.
478 478 """
479 479 tb_offset = self.tb_offset if tb_offset is None else tb_offset
480 480 Colors = self.Colors
481 481 out_list = []
482 482 if elist:
483 483
484 484 if tb_offset and len(elist) > tb_offset:
485 485 elist = elist[tb_offset:]
486 486
487 487 out_list.append('Traceback %s(most recent call last)%s:' %
488 488 (Colors.normalEm, Colors.Normal) + '\n')
489 489 out_list.extend(self._format_list(elist))
490 490 # The exception info should be a single entry in the list.
491 491 lines = ''.join(self._format_exception_only(etype, value))
492 492 out_list.append(lines)
493 493
494 494 # Note: this code originally read:
495 495
496 496 ## for line in lines[:-1]:
497 497 ## out_list.append(" "+line)
498 498 ## out_list.append(lines[-1])
499 499
500 500 # This means it was indenting everything but the last line by a little
501 501 # bit. I've disabled this for now, but if we see ugliness somewhre we
502 502 # can restore it.
503 503
504 504 return out_list
505 505
506 506 def _format_list(self, extracted_list):
507 507 """Format a list of traceback entry tuples for printing.
508 508
509 509 Given a list of tuples as returned by extract_tb() or
510 510 extract_stack(), return a list of strings ready for printing.
511 511 Each string in the resulting list corresponds to the item with the
512 512 same index in the argument list. Each string ends in a newline;
513 513 the strings may contain internal newlines as well, for those items
514 514 whose source text line is not None.
515 515
516 516 Lifted almost verbatim from traceback.py
517 517 """
518 518
519 519 Colors = self.Colors
520 520 list = []
521 521 for filename, lineno, name, line in extracted_list[:-1]:
522 522 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
523 523 (Colors.filename, filename, Colors.Normal,
524 524 Colors.lineno, lineno, Colors.Normal,
525 525 Colors.name, name, Colors.Normal)
526 526 if line:
527 527 item += ' %s\n' % line.strip()
528 528 list.append(item)
529 529 # Emphasize the last entry
530 530 filename, lineno, name, line = extracted_list[-1]
531 531 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
532 532 (Colors.normalEm,
533 533 Colors.filenameEm, filename, Colors.normalEm,
534 534 Colors.linenoEm, lineno, Colors.normalEm,
535 535 Colors.nameEm, name, Colors.normalEm,
536 536 Colors.Normal)
537 537 if line:
538 538 item += '%s %s%s\n' % (Colors.line, line.strip(),
539 539 Colors.Normal)
540 540 list.append(item)
541 541 #from pprint import pformat; print 'LISTTB', pformat(list) # dbg
542 542 return list
543 543
544 544 def _format_exception_only(self, etype, value):
545 545 """Format the exception part of a traceback.
546 546
547 547 The arguments are the exception type and value such as given by
548 548 sys.exc_info()[:2]. The return value is a list of strings, each ending
549 549 in a newline. Normally, the list contains a single string; however,
550 550 for SyntaxError exceptions, it contains several lines that (when
551 551 printed) display detailed information about where the syntax error
552 552 occurred. The message indicating which exception occurred is the
553 553 always last string in the list.
554 554
555 555 Also lifted nearly verbatim from traceback.py
556 556 """
557 557
558 558 have_filedata = False
559 559 Colors = self.Colors
560 560 list = []
561 561 stype = Colors.excName + etype.__name__ + Colors.Normal
562 562 if value is None:
563 563 # Not sure if this can still happen in Python 2.6 and above
564 564 list.append( str(stype) + '\n')
565 565 else:
566 566 if etype is SyntaxError:
567 567 have_filedata = True
568 568 #print 'filename is',filename # dbg
569 569 if not value.filename: value.filename = "<string>"
570 570 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
571 571 (Colors.normalEm,
572 572 Colors.filenameEm, value.filename, Colors.normalEm,
573 573 Colors.linenoEm, value.lineno, Colors.Normal ))
574 574 if value.text is not None:
575 575 i = 0
576 576 while i < len(value.text) and value.text[i].isspace():
577 577 i += 1
578 578 list.append('%s %s%s\n' % (Colors.line,
579 579 value.text.strip(),
580 580 Colors.Normal))
581 581 if value.offset is not None:
582 582 s = ' '
583 583 for c in value.text[i:value.offset-1]:
584 584 if c.isspace():
585 585 s += c
586 586 else:
587 587 s += ' '
588 588 list.append('%s%s^%s\n' % (Colors.caret, s,
589 589 Colors.Normal) )
590 590
591 591 try:
592 592 s = value.msg
593 593 except Exception:
594 594 s = self._some_str(value)
595 595 if s:
596 596 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
597 597 Colors.Normal, s))
598 598 else:
599 599 list.append('%s\n' % str(stype))
600 600
601 601 # sync with user hooks
602 602 if have_filedata:
603 603 ipinst = ipapi.get()
604 604 if ipinst is not None:
605 605 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
606 606
607 607 return list
608 608
609 609 def get_exception_only(self, etype, value):
610 610 """Only print the exception type and message, without a traceback.
611 611
612 612 Parameters
613 613 ----------
614 614 etype : exception type
615 615 value : exception value
616 616 """
617 617 return ListTB.structured_traceback(self, etype, value, [])
618 618
619 619
620 620 def show_exception_only(self, etype, evalue):
621 621 """Only print the exception type and message, without a traceback.
622 622
623 623 Parameters
624 624 ----------
625 625 etype : exception type
626 626 value : exception value
627 627 """
628 628 # This method needs to use __call__ from *this* class, not the one from
629 629 # a subclass whose signature or behavior may be different
630 630 ostream = self.ostream
631 631 ostream.flush()
632 632 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
633 633 ostream.flush()
634 634
635 635 def _some_str(self, value):
636 636 # Lifted from traceback.py
637 637 try:
638 638 return str(value)
639 639 except:
640 640 return '<unprintable %s object>' % type(value).__name__
641 641
642 642 #----------------------------------------------------------------------------
643 643 class VerboseTB(TBTools):
644 644 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
645 645 of HTML. Requires inspect and pydoc. Crazy, man.
646 646
647 647 Modified version which optionally strips the topmost entries from the
648 648 traceback, to be used with alternate interpreters (because their own code
649 649 would appear in the traceback)."""
650 650
651 651 def __init__(self,color_scheme = 'Linux', call_pdb=False, ostream=None,
652 652 tb_offset=0, long_header=False, include_vars=True,
653 653 check_cache=None):
654 654 """Specify traceback offset, headers and color scheme.
655 655
656 656 Define how many frames to drop from the tracebacks. Calling it with
657 657 tb_offset=1 allows use of this handler in interpreters which will have
658 658 their own code at the top of the traceback (VerboseTB will first
659 659 remove that frame before printing the traceback info)."""
660 660 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
661 661 ostream=ostream)
662 662 self.tb_offset = tb_offset
663 663 self.long_header = long_header
664 664 self.include_vars = include_vars
665 665 # By default we use linecache.checkcache, but the user can provide a
666 666 # different check_cache implementation. This is used by the IPython
667 667 # kernel to provide tracebacks for interactive code that is cached,
668 668 # by a compiler instance that flushes the linecache but preserves its
669 669 # own code cache.
670 670 if check_cache is None:
671 671 check_cache = linecache.checkcache
672 672 self.check_cache = check_cache
673 673
674 674 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
675 675 context=5):
676 676 """Return a nice text document describing the traceback."""
677 677
678 678 tb_offset = self.tb_offset if tb_offset is None else tb_offset
679 679
680 680 # some locals
681 681 try:
682 682 etype = etype.__name__
683 683 except AttributeError:
684 684 pass
685 685 Colors = self.Colors # just a shorthand + quicker name lookup
686 686 ColorsNormal = Colors.Normal # used a lot
687 687 col_scheme = self.color_scheme_table.active_scheme_name
688 688 indent = ' '*INDENT_SIZE
689 689 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
690 690 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
691 691 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
692 692
693 693 # some internal-use functions
694 694 def text_repr(value):
695 695 """Hopefully pretty robust repr equivalent."""
696 696 # this is pretty horrible but should always return *something*
697 697 try:
698 698 return pydoc.text.repr(value)
699 699 except KeyboardInterrupt:
700 700 raise
701 701 except:
702 702 try:
703 703 return repr(value)
704 704 except KeyboardInterrupt:
705 705 raise
706 706 except:
707 707 try:
708 708 # all still in an except block so we catch
709 709 # getattr raising
710 710 name = getattr(value, '__name__', None)
711 711 if name:
712 712 # ick, recursion
713 713 return text_repr(name)
714 714 klass = getattr(value, '__class__', None)
715 715 if klass:
716 716 return '%s instance' % text_repr(klass)
717 717 except KeyboardInterrupt:
718 718 raise
719 719 except:
720 720 return 'UNRECOVERABLE REPR FAILURE'
721 721 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
722 722 def nullrepr(value, repr=text_repr): return ''
723 723
724 724 # meat of the code begins
725 725 try:
726 726 etype = etype.__name__
727 727 except AttributeError:
728 728 pass
729 729
730 730 if self.long_header:
731 731 # Header with the exception type, python version, and date
732 732 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
733 733 date = time.ctime(time.time())
734 734
735 735 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
736 736 exc, ' '*(75-len(str(etype))-len(pyver)),
737 737 pyver, date.rjust(75) )
738 738 head += "\nA problem occured executing Python code. Here is the sequence of function"\
739 739 "\ncalls leading up to the error, with the most recent (innermost) call last."
740 740 else:
741 741 # Simplified header
742 742 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
743 743 'Traceback (most recent call last)'.\
744 744 rjust(75 - len(str(etype)) ) )
745 745 frames = []
746 746 # Flush cache before calling inspect. This helps alleviate some of the
747 747 # problems with python 2.3's inspect.py.
748 748 ##self.check_cache()
749 749 # Drop topmost frames if requested
750 750 try:
751 751 # Try the default getinnerframes and Alex's: Alex's fixes some
752 752 # problems, but it generates empty tracebacks for console errors
753 753 # (5 blanks lines) where none should be returned.
754 754 #records = inspect.getinnerframes(etb, context)[tb_offset:]
755 755 #print 'python records:', records # dbg
756 756 records = _fixed_getinnerframes(etb, context, tb_offset)
757 757 #print 'alex records:', records # dbg
758 758 except:
759 759
760 760 # FIXME: I've been getting many crash reports from python 2.3
761 761 # users, traceable to inspect.py. If I can find a small test-case
762 762 # to reproduce this, I should either write a better workaround or
763 763 # file a bug report against inspect (if that's the real problem).
764 764 # So far, I haven't been able to find an isolated example to
765 765 # reproduce the problem.
766 766 inspect_error()
767 767 traceback.print_exc(file=self.ostream)
768 768 info('\nUnfortunately, your original traceback can not be constructed.\n')
769 769 return ''
770 770
771 771 # build some color string templates outside these nested loops
772 772 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
773 773 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
774 774 ColorsNormal)
775 775 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
776 776 (Colors.vName, Colors.valEm, ColorsNormal)
777 777 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
778 778 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
779 779 Colors.vName, ColorsNormal)
780 780 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
781 781 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
782 782 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
783 783 ColorsNormal)
784 784
785 785 # now, loop over all records printing context and info
786 786 abspath = os.path.abspath
787 787 for frame, file, lnum, func, lines, index in records:
788 788 #print '*** record:',file,lnum,func,lines,index # dbg
789 789
790 790 if not file:
791 791 file = '?'
792 792 elif not(file.startswith("<") and file.endswith(">")):
793 793 # Guess that filenames like <string> aren't real filenames, so
794 794 # don't call abspath on them.
795 795 try:
796 796 file = abspath(file)
797 797 except OSError:
798 798 # Not sure if this can still happen: abspath now works with
799 799 # file names like <string>
800 800 pass
801 801
802 802 link = tpl_link % file
803 803 args, varargs, varkw, locals = inspect.getargvalues(frame)
804 804
805 805 if func == '?':
806 806 call = ''
807 807 else:
808 808 # Decide whether to include variable details or not
809 809 var_repr = self.include_vars and eqrepr or nullrepr
810 810 try:
811 811 call = tpl_call % (func,inspect.formatargvalues(args,
812 812 varargs, varkw,
813 813 locals,formatvalue=var_repr))
814 814 except KeyError:
815 815 # This happens in situations like errors inside generator
816 816 # expressions, where local variables are listed in the
817 817 # line, but can't be extracted from the frame. I'm not
818 818 # 100% sure this isn't actually a bug in inspect itself,
819 819 # but since there's no info for us to compute with, the
820 820 # best we can do is report the failure and move on. Here
821 821 # we must *not* call any traceback construction again,
822 822 # because that would mess up use of %debug later on. So we
823 823 # simply report the failure and move on. The only
824 824 # limitation will be that this frame won't have locals
825 825 # listed in the call signature. Quite subtle problem...
826 826 # I can't think of a good way to validate this in a unit
827 827 # test, but running a script consisting of:
828 828 # dict( (k,v.strip()) for (k,v) in range(10) )
829 829 # will illustrate the error, if this exception catch is
830 830 # disabled.
831 831 call = tpl_call_fail % func
832 832
833 833 # Don't attempt to tokenize binary files.
834 834 if file.endswith(('.so', '.pyd', '.dll')):
835 835 frames.append('%s %s\n' % (link,call))
836 836 continue
837 837 elif file.endswith(('.pyc','.pyo')):
838 838 # Look up the corresponding source file.
839 839 file = pyfile.source_from_cache(file)
840 840
841 841 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
842 842 line = getline(file, lnum[0])
843 843 lnum[0] += 1
844 844 return line
845 845
846 846 # Build the list of names on this line of code where the exception
847 847 # occurred.
848 848 try:
849 849 names = []
850 850 name_cont = False
851 851
852 852 for token_type, token, start, end, line in generate_tokens(linereader):
853 853 # build composite names
854 854 if token_type == tokenize.NAME and token not in keyword.kwlist:
855 855 if name_cont:
856 856 # Continuation of a dotted name
857 857 try:
858 858 names[-1].append(token)
859 859 except IndexError:
860 860 names.append([token])
861 861 name_cont = False
862 862 else:
863 863 # Regular new names. We append everything, the caller
864 864 # will be responsible for pruning the list later. It's
865 865 # very tricky to try to prune as we go, b/c composite
866 866 # names can fool us. The pruning at the end is easy
867 867 # to do (or the caller can print a list with repeated
868 868 # names if so desired.
869 869 names.append([token])
870 870 elif token == '.':
871 871 name_cont = True
872 872 elif token_type == tokenize.NEWLINE:
873 873 break
874 874
875 875 except (IndexError, UnicodeDecodeError):
876 876 # signals exit of tokenizer
877 877 pass
878 878 except tokenize.TokenError as msg:
879 879 _m = ("An unexpected error occurred while tokenizing input\n"
880 880 "The following traceback may be corrupted or invalid\n"
881 881 "The error message is: %s\n" % msg)
882 882 error(_m)
883 883
884 884 # Join composite names (e.g. "dict.fromkeys")
885 885 names = ['.'.join(n) for n in names]
886 886 # prune names list of duplicates, but keep the right order
887 887 unique_names = uniq_stable(names)
888 888
889 889 # Start loop over vars
890 890 lvals = []
891 891 if self.include_vars:
892 892 for name_full in unique_names:
893 893 name_base = name_full.split('.',1)[0]
894 894 if name_base in frame.f_code.co_varnames:
895 895 if name_base in locals:
896 896 try:
897 897 value = repr(eval(name_full,locals))
898 898 except:
899 899 value = undefined
900 900 else:
901 901 value = undefined
902 902 name = tpl_local_var % name_full
903 903 else:
904 904 if name_base in frame.f_globals:
905 905 try:
906 906 value = repr(eval(name_full,frame.f_globals))
907 907 except:
908 908 value = undefined
909 909 else:
910 910 value = undefined
911 911 name = tpl_global_var % name_full
912 912 lvals.append(tpl_name_val % (name,value))
913 913 if lvals:
914 914 lvals = '%s%s' % (indent,em_normal.join(lvals))
915 915 else:
916 916 lvals = ''
917 917
918 918 level = '%s %s\n' % (link,call)
919 919
920 920 if index is None:
921 921 frames.append(level)
922 922 else:
923 923 frames.append('%s%s' % (level,''.join(
924 924 _format_traceback_lines(lnum,index,lines,Colors,lvals,
925 925 col_scheme))))
926 926
927 927 # Get (safely) a string form of the exception info
928 928 try:
929 929 etype_str,evalue_str = map(str,(etype,evalue))
930 930 except:
931 931 # User exception is improperly defined.
932 932 etype,evalue = str,sys.exc_info()[:2]
933 933 etype_str,evalue_str = map(str,(etype,evalue))
934 934 # ... and format it
935 935 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
936 936 ColorsNormal, evalue_str)]
937 937 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
938 938 try:
939 939 names = [w for w in dir(evalue) if isinstance(w, basestring)]
940 940 except:
941 941 # Every now and then, an object with funny inernals blows up
942 942 # when dir() is called on it. We do the best we can to report
943 943 # the problem and continue
944 944 _m = '%sException reporting error (object with broken dir())%s:'
945 945 exception.append(_m % (Colors.excName,ColorsNormal))
946 946 etype_str,evalue_str = map(str,sys.exc_info()[:2])
947 947 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
948 948 ColorsNormal, evalue_str))
949 949 names = []
950 950 for name in names:
951 951 value = text_repr(getattr(evalue, name))
952 952 exception.append('\n%s%s = %s' % (indent, name, value))
953 953
954 954 # vds: >>
955 955 if records:
956 956 filepath, lnum = records[-1][1:3]
957 957 #print "file:", str(file), "linenb", str(lnum) # dbg
958 958 filepath = os.path.abspath(filepath)
959 959 ipinst = ipapi.get()
960 960 if ipinst is not None:
961 961 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
962 962 # vds: <<
963 963
964 964 # return all our info assembled as a single string
965 965 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
966 966 return [head] + frames + [''.join(exception[0])]
967 967
968 968 def debugger(self,force=False):
969 969 """Call up the pdb debugger if desired, always clean up the tb
970 970 reference.
971 971
972 972 Keywords:
973 973
974 974 - force(False): by default, this routine checks the instance call_pdb
975 975 flag and does not actually invoke the debugger if the flag is false.
976 976 The 'force' option forces the debugger to activate even if the flag
977 977 is false.
978 978
979 979 If the call_pdb flag is set, the pdb interactive debugger is
980 980 invoked. In all cases, the self.tb reference to the current traceback
981 981 is deleted to prevent lingering references which hamper memory
982 982 management.
983 983
984 984 Note that each call to pdb() does an 'import readline', so if your app
985 985 requires a special setup for the readline completers, you'll have to
986 986 fix that by hand after invoking the exception handler."""
987 987
988 988 if force or self.call_pdb:
989 989 if self.pdb is None:
990 990 self.pdb = debugger.Pdb(
991 991 self.color_scheme_table.active_scheme_name)
992 992 # the system displayhook may have changed, restore the original
993 993 # for pdb
994 994 display_trap = DisplayTrap(hook=sys.__displayhook__)
995 995 with display_trap:
996 996 self.pdb.reset()
997 997 # Find the right frame so we don't pop up inside ipython itself
998 998 if hasattr(self,'tb') and self.tb is not None:
999 999 etb = self.tb
1000 1000 else:
1001 1001 etb = self.tb = sys.last_traceback
1002 1002 while self.tb is not None and self.tb.tb_next is not None:
1003 1003 self.tb = self.tb.tb_next
1004 1004 if etb and etb.tb_next:
1005 1005 etb = etb.tb_next
1006 1006 self.pdb.botframe = etb.tb_frame
1007 1007 self.pdb.interaction(self.tb.tb_frame, self.tb)
1008 1008
1009 1009 if hasattr(self,'tb'):
1010 1010 del self.tb
1011 1011
1012 1012 def handler(self, info=None):
1013 1013 (etype, evalue, etb) = info or sys.exc_info()
1014 1014 self.tb = etb
1015 1015 ostream = self.ostream
1016 1016 ostream.flush()
1017 1017 ostream.write(self.text(etype, evalue, etb))
1018 1018 ostream.write('\n')
1019 1019 ostream.flush()
1020 1020
1021 1021 # Changed so an instance can just be called as VerboseTB_inst() and print
1022 1022 # out the right info on its own.
1023 1023 def __call__(self, etype=None, evalue=None, etb=None):
1024 1024 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1025 1025 if etb is None:
1026 1026 self.handler()
1027 1027 else:
1028 1028 self.handler((etype, evalue, etb))
1029 1029 try:
1030 1030 self.debugger()
1031 1031 except KeyboardInterrupt:
1032 1032 print "\nKeyboardInterrupt"
1033 1033
1034 1034 #----------------------------------------------------------------------------
1035 1035 class FormattedTB(VerboseTB, ListTB):
1036 1036 """Subclass ListTB but allow calling with a traceback.
1037 1037
1038 1038 It can thus be used as a sys.excepthook for Python > 2.1.
1039 1039
1040 1040 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1041 1041
1042 1042 Allows a tb_offset to be specified. This is useful for situations where
1043 1043 one needs to remove a number of topmost frames from the traceback (such as
1044 1044 occurs with python programs that themselves execute other python code,
1045 1045 like Python shells). """
1046 1046
1047 1047 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1048 1048 ostream=None,
1049 1049 tb_offset=0, long_header=False, include_vars=False,
1050 1050 check_cache=None):
1051 1051
1052 1052 # NEVER change the order of this list. Put new modes at the end:
1053 1053 self.valid_modes = ['Plain','Context','Verbose']
1054 1054 self.verbose_modes = self.valid_modes[1:3]
1055 1055
1056 1056 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1057 1057 ostream=ostream, tb_offset=tb_offset,
1058 1058 long_header=long_header, include_vars=include_vars,
1059 1059 check_cache=check_cache)
1060 1060
1061 1061 # Different types of tracebacks are joined with different separators to
1062 1062 # form a single string. They are taken from this dict
1063 1063 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1064 1064 # set_mode also sets the tb_join_char attribute
1065 1065 self.set_mode(mode)
1066 1066
1067 1067 def _extract_tb(self,tb):
1068 1068 if tb:
1069 1069 return traceback.extract_tb(tb)
1070 1070 else:
1071 1071 return None
1072 1072
1073 1073 def structured_traceback(self, etype, value, tb, tb_offset=None, context=5):
1074 1074 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1075 1075 mode = self.mode
1076 1076 if mode in self.verbose_modes:
1077 1077 # Verbose modes need a full traceback
1078 1078 return VerboseTB.structured_traceback(
1079 1079 self, etype, value, tb, tb_offset, context
1080 1080 )
1081 1081 else:
1082 1082 # We must check the source cache because otherwise we can print
1083 1083 # out-of-date source code.
1084 1084 self.check_cache()
1085 1085 # Now we can extract and format the exception
1086 1086 elist = self._extract_tb(tb)
1087 1087 return ListTB.structured_traceback(
1088 1088 self, etype, value, elist, tb_offset, context
1089 1089 )
1090 1090
1091 1091 def stb2text(self, stb):
1092 1092 """Convert a structured traceback (a list) to a string."""
1093 1093 return self.tb_join_char.join(stb)
1094 1094
1095 1095
1096 1096 def set_mode(self,mode=None):
1097 1097 """Switch to the desired mode.
1098 1098
1099 1099 If mode is not specified, cycles through the available modes."""
1100 1100
1101 1101 if not mode:
1102 1102 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
1103 1103 len(self.valid_modes)
1104 1104 self.mode = self.valid_modes[new_idx]
1105 1105 elif mode not in self.valid_modes:
1106 1106 raise ValueError('Unrecognized mode in FormattedTB: <'+mode+'>\n'
1107 1107 'Valid modes: '+str(self.valid_modes))
1108 1108 else:
1109 1109 self.mode = mode
1110 1110 # include variable details only in 'Verbose' mode
1111 1111 self.include_vars = (self.mode == self.valid_modes[2])
1112 1112 # Set the join character for generating text tracebacks
1113 1113 self.tb_join_char = self._join_chars[self.mode]
1114 1114
1115 1115 # some convenient shorcuts
1116 1116 def plain(self):
1117 1117 self.set_mode(self.valid_modes[0])
1118 1118
1119 1119 def context(self):
1120 1120 self.set_mode(self.valid_modes[1])
1121 1121
1122 1122 def verbose(self):
1123 1123 self.set_mode(self.valid_modes[2])
1124 1124
1125 1125 #----------------------------------------------------------------------------
1126 1126 class AutoFormattedTB(FormattedTB):
1127 1127 """A traceback printer which can be called on the fly.
1128 1128
1129 1129 It will find out about exceptions by itself.
1130 1130
1131 1131 A brief example:
1132 1132
1133 1133 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1134 1134 try:
1135 1135 ...
1136 1136 except:
1137 1137 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1138 1138 """
1139 1139
1140 1140 def __call__(self,etype=None,evalue=None,etb=None,
1141 1141 out=None,tb_offset=None):
1142 1142 """Print out a formatted exception traceback.
1143 1143
1144 1144 Optional arguments:
1145 1145 - out: an open file-like object to direct output to.
1146 1146
1147 1147 - tb_offset: the number of frames to skip over in the stack, on a
1148 1148 per-call basis (this overrides temporarily the instance's tb_offset
1149 1149 given at initialization time. """
1150 1150
1151 1151
1152 1152 if out is None:
1153 1153 out = self.ostream
1154 1154 out.flush()
1155 1155 out.write(self.text(etype, evalue, etb, tb_offset))
1156 1156 out.write('\n')
1157 1157 out.flush()
1158 1158 # FIXME: we should remove the auto pdb behavior from here and leave
1159 1159 # that to the clients.
1160 1160 try:
1161 1161 self.debugger()
1162 1162 except KeyboardInterrupt:
1163 1163 print "\nKeyboardInterrupt"
1164 1164
1165 1165 def structured_traceback(self, etype=None, value=None, tb=None,
1166 1166 tb_offset=None, context=5):
1167 1167 if etype is None:
1168 1168 etype,value,tb = sys.exc_info()
1169 1169 self.tb = tb
1170 1170 return FormattedTB.structured_traceback(
1171 1171 self, etype, value, tb, tb_offset, context)
1172 1172
1173 1173 #---------------------------------------------------------------------------
1174 1174
1175 1175 # A simple class to preserve Nathan's original functionality.
1176 1176 class ColorTB(FormattedTB):
1177 1177 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1178 1178 def __init__(self,color_scheme='Linux',call_pdb=0):
1179 1179 FormattedTB.__init__(self,color_scheme=color_scheme,
1180 1180 call_pdb=call_pdb)
1181 1181
1182 1182
1183 1183 class SyntaxTB(ListTB):
1184 1184 """Extension which holds some state: the last exception value"""
1185 1185
1186 1186 def __init__(self,color_scheme = 'NoColor'):
1187 1187 ListTB.__init__(self,color_scheme)
1188 1188 self.last_syntax_error = None
1189 1189
1190 1190 def __call__(self, etype, value, elist):
1191 1191 self.last_syntax_error = value
1192 1192 ListTB.__call__(self,etype,value,elist)
1193 1193
1194 1194 def clear_err_state(self):
1195 1195 """Return the current error state and clear it"""
1196 1196 e = self.last_syntax_error
1197 1197 self.last_syntax_error = None
1198 1198 return e
1199 1199
1200 1200 def stb2text(self, stb):
1201 1201 """Convert a structured traceback (a list) to a string."""
1202 1202 return ''.join(stb)
1203 1203
1204 1204
1205 1205 #----------------------------------------------------------------------------
1206 1206 # module testing (minimal)
1207 1207 if __name__ == "__main__":
1208 def spam(c, (d, e)):
1208 def spam(c, d_e):
1209 (d, e) = d_e
1209 1210 x = c + d
1210 1211 y = c * d
1211 1212 foo(x, y)
1212 1213
1213 1214 def foo(a, b, bar=1):
1214 1215 eggs(a, b + bar)
1215 1216
1216 1217 def eggs(f, g, z=globals()):
1217 1218 h = f + g
1218 1219 i = f - g
1219 1220 return h / i
1220 1221
1221 1222 print ''
1222 1223 print '*** Before ***'
1223 1224 try:
1224 1225 print spam(1, (2, 3))
1225 1226 except:
1226 1227 traceback.print_exc()
1227 1228 print ''
1228 1229
1229 1230 handler = ColorTB()
1230 1231 print '*** ColorTB ***'
1231 1232 try:
1232 1233 print spam(1, (2, 3))
1233 1234 except:
1234 1235 handler(*sys.exc_info())
1235 1236 print ''
1236 1237
1237 1238 handler = VerboseTB()
1238 1239 print '*** VerboseTB ***'
1239 1240 try:
1240 1241 print spam(1, (2, 3))
1241 1242 except:
1242 1243 handler(*sys.exc_info())
1243 1244 print ''
1244 1245
@@ -1,308 +1,308 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Class and program to colorize python source code for ANSI terminals.
4 4
5 5 Based on an HTML code highlighter by Jurgen Hermann found at:
6 6 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52298
7 7
8 8 Modifications by Fernando Perez (fperez@colorado.edu).
9 9
10 10 Information on the original HTML highlighter follows:
11 11
12 12 MoinMoin - Python Source Parser
13 13
14 14 Title: Colorize Python source using the built-in tokenizer
15 15
16 16 Submitter: Jurgen Hermann
17 17 Last Updated:2001/04/06
18 18
19 19 Version no:1.2
20 20
21 21 Description:
22 22
23 23 This code is part of MoinMoin (http://moin.sourceforge.net/) and converts
24 24 Python source code to HTML markup, rendering comments, keywords,
25 25 operators, numeric and string literals in different colors.
26 26
27 27 It shows how to use the built-in keyword, token and tokenize modules to
28 28 scan Python source code and re-emit it with no changes to its original
29 29 formatting (which is the hard part).
30 30 """
31 31 from __future__ import print_function
32 32
33 33 __all__ = ['ANSICodeColors','Parser']
34 34
35 35 _scheme_default = 'Linux'
36 36
37 37
38 38 # Imports
39 39 import StringIO
40 40 import keyword
41 41 import os
42 42 import optparse
43 43 import sys
44 44 import token
45 45 import tokenize
46 46
47 47 try:
48 48 generate_tokens = tokenize.generate_tokens
49 49 except AttributeError:
50 50 # Python 3. Note that we use the undocumented _tokenize because it expects
51 51 # strings, not bytes. See also Python issue #9969.
52 52 generate_tokens = tokenize._tokenize
53 53
54 54 from IPython.utils.coloransi import *
55 55
56 56 #############################################################################
57 57 ### Python Source Parser (does Hilighting)
58 58 #############################################################################
59 59
60 60 _KEYWORD = token.NT_OFFSET + 1
61 61 _TEXT = token.NT_OFFSET + 2
62 62
63 63 #****************************************************************************
64 64 # Builtin color schemes
65 65
66 66 Colors = TermColors # just a shorthand
67 67
68 68 # Build a few color schemes
69 69 NoColor = ColorScheme(
70 70 'NoColor',{
71 71 token.NUMBER : Colors.NoColor,
72 72 token.OP : Colors.NoColor,
73 73 token.STRING : Colors.NoColor,
74 74 tokenize.COMMENT : Colors.NoColor,
75 75 token.NAME : Colors.NoColor,
76 76 token.ERRORTOKEN : Colors.NoColor,
77 77
78 78 _KEYWORD : Colors.NoColor,
79 79 _TEXT : Colors.NoColor,
80 80
81 81 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
82 82 } )
83 83
84 84 LinuxColors = ColorScheme(
85 85 'Linux',{
86 86 token.NUMBER : Colors.LightCyan,
87 87 token.OP : Colors.Yellow,
88 88 token.STRING : Colors.LightBlue,
89 89 tokenize.COMMENT : Colors.LightRed,
90 90 token.NAME : Colors.Normal,
91 91 token.ERRORTOKEN : Colors.Red,
92 92
93 93 _KEYWORD : Colors.LightGreen,
94 94 _TEXT : Colors.Yellow,
95 95
96 96 'normal' : Colors.Normal # color off (usu. Colors.Normal)
97 97 } )
98 98
99 99 LightBGColors = ColorScheme(
100 100 'LightBG',{
101 101 token.NUMBER : Colors.Cyan,
102 102 token.OP : Colors.Blue,
103 103 token.STRING : Colors.Blue,
104 104 tokenize.COMMENT : Colors.Red,
105 105 token.NAME : Colors.Normal,
106 106 token.ERRORTOKEN : Colors.Red,
107 107
108 108 _KEYWORD : Colors.Green,
109 109 _TEXT : Colors.Blue,
110 110
111 111 'normal' : Colors.Normal # color off (usu. Colors.Normal)
112 112 } )
113 113
114 114 # Build table of color schemes (needed by the parser)
115 115 ANSICodeColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
116 116 _scheme_default)
117 117
118 118 class Parser:
119 119 """ Format colored Python source.
120 120 """
121 121
122 122 def __init__(self, color_table=None,out = sys.stdout):
123 123 """ Create a parser with a specified color table and output channel.
124 124
125 125 Call format() to process code.
126 126 """
127 127 self.color_table = color_table and color_table or ANSICodeColors
128 128 self.out = out
129 129
130 130 def format(self, raw, out = None, scheme = ''):
131 131 return self.format2(raw, out, scheme)[0]
132 132
133 133 def format2(self, raw, out = None, scheme = ''):
134 134 """ Parse and send the colored source.
135 135
136 136 If out and scheme are not specified, the defaults (given to
137 137 constructor) are used.
138 138
139 139 out should be a file-type object. Optionally, out can be given as the
140 140 string 'str' and the parser will automatically return the output in a
141 141 string."""
142 142
143 143 string_output = 0
144 144 if out == 'str' or self.out == 'str' or \
145 145 isinstance(self.out,StringIO.StringIO):
146 146 # XXX - I don't really like this state handling logic, but at this
147 147 # point I don't want to make major changes, so adding the
148 148 # isinstance() check is the simplest I can do to ensure correct
149 149 # behavior.
150 150 out_old = self.out
151 151 self.out = StringIO.StringIO()
152 152 string_output = 1
153 153 elif out is not None:
154 154 self.out = out
155 155
156 156 # Fast return of the unmodified input for NoColor scheme
157 157 if scheme == 'NoColor':
158 158 error = False
159 159 self.out.write(raw)
160 160 if string_output:
161 161 return raw,error
162 162 else:
163 163 return None,error
164 164
165 165 # local shorthands
166 166 colors = self.color_table[scheme].colors
167 167 self.colors = colors # put in object so __call__ sees it
168 168
169 169 # Remove trailing whitespace and normalize tabs
170 170 self.raw = raw.expandtabs().rstrip()
171 171
172 172 # store line offsets in self.lines
173 173 self.lines = [0, 0]
174 174 pos = 0
175 175 raw_find = self.raw.find
176 176 lines_append = self.lines.append
177 177 while 1:
178 178 pos = raw_find('\n', pos) + 1
179 179 if not pos: break
180 180 lines_append(pos)
181 181 lines_append(len(self.raw))
182 182
183 183 # parse the source and write it
184 184 self.pos = 0
185 185 text = StringIO.StringIO(self.raw)
186 186
187 187 error = False
188 188 try:
189 189 for atoken in generate_tokens(text.readline):
190 190 self(*atoken)
191 191 except tokenize.TokenError as ex:
192 192 msg = ex.args[0]
193 193 line = ex.args[1][0]
194 194 self.out.write("%s\n\n*** ERROR: %s%s%s\n" %
195 195 (colors[token.ERRORTOKEN],
196 196 msg, self.raw[self.lines[line]:],
197 197 colors.normal)
198 198 )
199 199 error = True
200 200 self.out.write(colors.normal+'\n')
201 201 if string_output:
202 202 output = self.out.getvalue()
203 203 self.out = out_old
204 204 return (output, error)
205 205 return (None, error)
206 206
207 def __call__(self, toktype, toktext, (srow,scol), (erow,ecol), line):
207 def __call__(self, toktype, toktext, start_pos, end_pos, line):
208 208 """ Token handler, with syntax highlighting."""
209
210 # local shorthands
209 (srow,scol) = start_pos
210 (erow,ecol) = end_pos
211 211 colors = self.colors
212 212 owrite = self.out.write
213 213
214 214 # line separator, so this works across platforms
215 215 linesep = os.linesep
216 216
217 217 # calculate new positions
218 218 oldpos = self.pos
219 219 newpos = self.lines[srow] + scol
220 220 self.pos = newpos + len(toktext)
221 221
222 222 # send the original whitespace, if needed
223 223 if newpos > oldpos:
224 224 owrite(self.raw[oldpos:newpos])
225 225
226 226 # skip indenting tokens
227 227 if toktype in [token.INDENT, token.DEDENT]:
228 228 self.pos = newpos
229 229 return
230 230
231 231 # map token type to a color group
232 232 if token.LPAR <= toktype and toktype <= token.OP:
233 233 toktype = token.OP
234 234 elif toktype == token.NAME and keyword.iskeyword(toktext):
235 235 toktype = _KEYWORD
236 236 color = colors.get(toktype, colors[_TEXT])
237 237
238 238 #print '<%s>' % toktext, # dbg
239 239
240 240 # Triple quoted strings must be handled carefully so that backtracking
241 241 # in pagers works correctly. We need color terminators on _each_ line.
242 242 if linesep in toktext:
243 243 toktext = toktext.replace(linesep, '%s%s%s' %
244 244 (colors.normal,linesep,color))
245 245
246 246 # send text
247 247 owrite('%s%s%s' % (color,toktext,colors.normal))
248 248
249 249 def main(argv=None):
250 250 """Run as a command-line script: colorize a python file or stdin using ANSI
251 251 color escapes and print to stdout.
252 252
253 253 Inputs:
254 254
255 255 - argv(None): a list of strings like sys.argv[1:] giving the command-line
256 256 arguments. If None, use sys.argv[1:].
257 257 """
258 258
259 259 usage_msg = """%prog [options] [filename]
260 260
261 261 Colorize a python file or stdin using ANSI color escapes and print to stdout.
262 262 If no filename is given, or if filename is -, read standard input."""
263 263
264 264 parser = optparse.OptionParser(usage=usage_msg)
265 265 newopt = parser.add_option
266 266 newopt('-s','--scheme',metavar='NAME',dest='scheme_name',action='store',
267 267 choices=['Linux','LightBG','NoColor'],default=_scheme_default,
268 268 help="give the color scheme to use. Currently only 'Linux'\
269 269 (default) and 'LightBG' and 'NoColor' are implemented (give without\
270 270 quotes)")
271 271
272 272 opts,args = parser.parse_args(argv)
273 273
274 274 if len(args) > 1:
275 275 parser.error("you must give at most one filename.")
276 276
277 277 if len(args) == 0:
278 278 fname = '-' # no filename given; setup to read from stdin
279 279 else:
280 280 fname = args[0]
281 281
282 282 if fname == '-':
283 283 stream = sys.stdin
284 284 else:
285 285 try:
286 286 stream = open(fname)
287 287 except IOError as msg:
288 288 print(msg, file=sys.stderr)
289 289 sys.exit(1)
290 290
291 291 parser = Parser()
292 292
293 293 # we need nested try blocks because pre-2.5 python doesn't support unified
294 294 # try-except-finally
295 295 try:
296 296 try:
297 297 # write colorized version to stdout
298 298 parser.format(stream.read(),scheme=opts.scheme_name)
299 299 except IOError as msg:
300 300 # if user reads through a pager and quits, don't print traceback
301 301 if msg.args != (32,'Broken pipe'):
302 302 raise
303 303 finally:
304 304 if stream is not sys.stdin:
305 305 stream.close() # in case a non-handled exception happened above
306 306
307 307 if __name__ == "__main__":
308 308 main()
General Comments 0
You need to be logged in to leave comments. Login now