##// END OF EJS Templates
Running darker to format changes
Arthur Moreira -
Show More
@@ -1,1132 +1,1140 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Verbose and colourful traceback formatting.
3 Verbose and colourful traceback formatting.
4
4
5 **ColorTB**
5 **ColorTB**
6
6
7 I've always found it a bit hard to visually parse tracebacks in Python. The
7 I've always found it a bit hard to visually parse tracebacks in Python. The
8 ColorTB class is a solution to that problem. It colors the different parts of a
8 ColorTB class is a solution to that problem. It colors the different parts of a
9 traceback in a manner similar to what you would expect from a syntax-highlighting
9 traceback in a manner similar to what you would expect from a syntax-highlighting
10 text editor.
10 text editor.
11
11
12 Installation instructions for ColorTB::
12 Installation instructions for ColorTB::
13
13
14 import sys,ultratb
14 import sys,ultratb
15 sys.excepthook = ultratb.ColorTB()
15 sys.excepthook = ultratb.ColorTB()
16
16
17 **VerboseTB**
17 **VerboseTB**
18
18
19 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
19 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
20 of useful info when a traceback occurs. Ping originally had it spit out HTML
20 of useful info when a traceback occurs. Ping originally had it spit out HTML
21 and intended it for CGI programmers, but why should they have all the fun? I
21 and intended it for CGI programmers, but why should they have all the fun? I
22 altered it to spit out colored text to the terminal. It's a bit overwhelming,
22 altered it to spit out colored text to the terminal. It's a bit overwhelming,
23 but kind of neat, and maybe useful for long-running programs that you believe
23 but kind of neat, and maybe useful for long-running programs that you believe
24 are bug-free. If a crash *does* occur in that type of program you want details.
24 are bug-free. If a crash *does* occur in that type of program you want details.
25 Give it a shot--you'll love it or you'll hate it.
25 Give it a shot--you'll love it or you'll hate it.
26
26
27 .. note::
27 .. note::
28
28
29 The Verbose mode prints the variables currently visible where the exception
29 The Verbose mode prints the variables currently visible where the exception
30 happened (shortening their strings if too long). This can potentially be
30 happened (shortening their strings if too long). This can potentially be
31 very slow, if you happen to have a huge data structure whose string
31 very slow, if you happen to have a huge data structure whose string
32 representation is complex to compute. Your computer may appear to freeze for
32 representation is complex to compute. Your computer may appear to freeze for
33 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
33 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
34 with Ctrl-C (maybe hitting it more than once).
34 with Ctrl-C (maybe hitting it more than once).
35
35
36 If you encounter this kind of situation often, you may want to use the
36 If you encounter this kind of situation often, you may want to use the
37 Verbose_novars mode instead of the regular Verbose, which avoids formatting
37 Verbose_novars mode instead of the regular Verbose, which avoids formatting
38 variables (but otherwise includes the information and context given by
38 variables (but otherwise includes the information and context given by
39 Verbose).
39 Verbose).
40
40
41 .. note::
41 .. note::
42
42
43 The verbose mode print all variables in the stack, which means it can
43 The verbose mode print all variables in the stack, which means it can
44 potentially leak sensitive information like access keys, or unencrypted
44 potentially leak sensitive information like access keys, or unencrypted
45 password.
45 password.
46
46
47 Installation instructions for VerboseTB::
47 Installation instructions for VerboseTB::
48
48
49 import sys,ultratb
49 import sys,ultratb
50 sys.excepthook = ultratb.VerboseTB()
50 sys.excepthook = ultratb.VerboseTB()
51
51
52 Note: Much of the code in this module was lifted verbatim from the standard
52 Note: Much of the code in this module was lifted verbatim from the standard
53 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
53 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
54
54
55 Color schemes
55 Color schemes
56 -------------
56 -------------
57
57
58 The colors are defined in the class TBTools through the use of the
58 The colors are defined in the class TBTools through the use of the
59 ColorSchemeTable class. Currently the following exist:
59 ColorSchemeTable class. Currently the following exist:
60
60
61 - NoColor: allows all of this module to be used in any terminal (the color
61 - NoColor: allows all of this module to be used in any terminal (the color
62 escapes are just dummy blank strings).
62 escapes are just dummy blank strings).
63
63
64 - Linux: is meant to look good in a terminal like the Linux console (black
64 - Linux: is meant to look good in a terminal like the Linux console (black
65 or very dark background).
65 or very dark background).
66
66
67 - LightBG: similar to Linux but swaps dark/light colors to be more readable
67 - LightBG: similar to Linux but swaps dark/light colors to be more readable
68 in light background terminals.
68 in light background terminals.
69
69
70 - Neutral: a neutral color scheme that should be readable on both light and
70 - Neutral: a neutral color scheme that should be readable on both light and
71 dark background
71 dark background
72
72
73 You can implement other color schemes easily, the syntax is fairly
73 You can implement other color schemes easily, the syntax is fairly
74 self-explanatory. Please send back new schemes you develop to the author for
74 self-explanatory. Please send back new schemes you develop to the author for
75 possible inclusion in future releases.
75 possible inclusion in future releases.
76
76
77 Inheritance diagram:
77 Inheritance diagram:
78
78
79 .. inheritance-diagram:: IPython.core.ultratb
79 .. inheritance-diagram:: IPython.core.ultratb
80 :parts: 3
80 :parts: 3
81 """
81 """
82
82
83 #*****************************************************************************
83 #*****************************************************************************
84 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
84 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
85 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
85 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
86 #
86 #
87 # Distributed under the terms of the BSD License. The full license is in
87 # Distributed under the terms of the BSD License. The full license is in
88 # the file COPYING, distributed as part of this software.
88 # the file COPYING, distributed as part of this software.
89 #*****************************************************************************
89 #*****************************************************************************
90
90
91
91
92 import inspect
92 import inspect
93 import linecache
93 import linecache
94 import pydoc
94 import pydoc
95 import sys
95 import sys
96 import time
96 import time
97 import traceback
97 import traceback
98
98
99 import stack_data
99 import stack_data
100 from pygments.formatters.terminal256 import Terminal256Formatter
100 from pygments.formatters.terminal256 import Terminal256Formatter
101 from pygments.styles import get_style_by_name
101 from pygments.styles import get_style_by_name
102
102
103 # IPython's own modules
103 # IPython's own modules
104 from IPython import get_ipython
104 from IPython import get_ipython
105 from IPython.core import debugger
105 from IPython.core import debugger
106 from IPython.core.display_trap import DisplayTrap
106 from IPython.core.display_trap import DisplayTrap
107 from IPython.core.excolors import exception_colors
107 from IPython.core.excolors import exception_colors
108 from IPython.utils import path as util_path
108 from IPython.utils import path as util_path
109 from IPython.utils import py3compat
109 from IPython.utils import py3compat
110 from IPython.utils.terminal import get_terminal_size
110 from IPython.utils.terminal import get_terminal_size
111
111
112 import IPython.utils.colorable as colorable
112 import IPython.utils.colorable as colorable
113
113
114 # Globals
114 # Globals
115 # amount of space to put line numbers before verbose tracebacks
115 # amount of space to put line numbers before verbose tracebacks
116 INDENT_SIZE = 8
116 INDENT_SIZE = 8
117
117
118 # Default color scheme. This is used, for example, by the traceback
118 # Default color scheme. This is used, for example, by the traceback
119 # formatter. When running in an actual IPython instance, the user's rc.colors
119 # formatter. When running in an actual IPython instance, the user's rc.colors
120 # value is used, but having a module global makes this functionality available
120 # value is used, but having a module global makes this functionality available
121 # to users of ultratb who are NOT running inside ipython.
121 # to users of ultratb who are NOT running inside ipython.
122 DEFAULT_SCHEME = 'NoColor'
122 DEFAULT_SCHEME = 'NoColor'
123
123
124 # ---------------------------------------------------------------------------
124 # ---------------------------------------------------------------------------
125 # Code begins
125 # Code begins
126
126
127 # Helper function -- largely belongs to VerboseTB, but we need the same
127 # Helper function -- largely belongs to VerboseTB, but we need the same
128 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
128 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
129 # can be recognized properly by ipython.el's py-traceback-line-re
129 # can be recognized properly by ipython.el's py-traceback-line-re
130 # (SyntaxErrors have to be treated specially because they have no traceback)
130 # (SyntaxErrors have to be treated specially because they have no traceback)
131
131
132
132
133 def _format_traceback_lines(lines, Colors, has_colors, lvals):
133 def _format_traceback_lines(lines, Colors, has_colors, lvals):
134 """
134 """
135 Format tracebacks lines with pointing arrow, leading numbers...
135 Format tracebacks lines with pointing arrow, leading numbers...
136
136
137 Parameters
137 Parameters
138 ----------
138 ----------
139 lines : list[Line]
139 lines : list[Line]
140 Colors
140 Colors
141 ColorScheme used.
141 ColorScheme used.
142 lvals : str
142 lvals : str
143 Values of local variables, already colored, to inject just after the error line.
143 Values of local variables, already colored, to inject just after the error line.
144 """
144 """
145 numbers_width = INDENT_SIZE - 1
145 numbers_width = INDENT_SIZE - 1
146 res = []
146 res = []
147
147
148 for stack_line in lines:
148 for stack_line in lines:
149 if stack_line is stack_data.LINE_GAP:
149 if stack_line is stack_data.LINE_GAP:
150 res.append('%s (...)%s\n' % (Colors.linenoEm, Colors.Normal))
150 res.append('%s (...)%s\n' % (Colors.linenoEm, Colors.Normal))
151 continue
151 continue
152
152
153 line = stack_line.render(pygmented=has_colors).rstrip('\n') + '\n'
153 line = stack_line.render(pygmented=has_colors).rstrip('\n') + '\n'
154 lineno = stack_line.lineno
154 lineno = stack_line.lineno
155 if stack_line.is_current:
155 if stack_line.is_current:
156 # This is the line with the error
156 # This is the line with the error
157 pad = numbers_width - len(str(lineno))
157 pad = numbers_width - len(str(lineno))
158 num = '%s%s' % (debugger.make_arrow(pad), str(lineno))
158 num = '%s%s' % (debugger.make_arrow(pad), str(lineno))
159 start_color = Colors.linenoEm
159 start_color = Colors.linenoEm
160 else:
160 else:
161 num = '%*s' % (numbers_width, lineno)
161 num = '%*s' % (numbers_width, lineno)
162 start_color = Colors.lineno
162 start_color = Colors.lineno
163
163
164 line = '%s%s%s %s' % (start_color, num, Colors.Normal, line)
164 line = '%s%s%s %s' % (start_color, num, Colors.Normal, line)
165
165
166 res.append(line)
166 res.append(line)
167 if lvals and stack_line.is_current:
167 if lvals and stack_line.is_current:
168 res.append(lvals + '\n')
168 res.append(lvals + '\n')
169 return res
169 return res
170
170
171
171
172 def _format_filename(file, ColorFilename, ColorNormal):
172 def _format_filename(file, ColorFilename, ColorNormal):
173 """
173 """
174 Format filename lines with `In [n]` if it's the nth code cell or `File *.py` if it's a module.
174 Format filename lines with `In [n]` if it's the nth code cell or `File *.py` if it's a module.
175
175
176 Parameters
176 Parameters
177 ----------
177 ----------
178 file : str
178 file : str
179 ColorFilename
179 ColorFilename
180 ColorScheme's filename coloring to be used.
180 ColorScheme's filename coloring to be used.
181 ColorNormal
181 ColorNormal
182 ColorScheme's normal coloring to be used.
182 ColorScheme's normal coloring to be used.
183 """
183 """
184 ipinst = get_ipython()
184 ipinst = get_ipython()
185
185
186 if ipinst is not None and file in ipinst.compile._filename_map:
186 if ipinst is not None and file in ipinst.compile._filename_map:
187 file = "[%s]" % ipinst.compile._filename_map[file]
187 file = "[%s]" % ipinst.compile._filename_map[file]
188 tpl_link = "In %s%%s%s" % (ColorFilename, ColorNormal)
188 tpl_link = "In %s%%s%s" % (ColorFilename, ColorNormal)
189 else:
189 else:
190 file = util_path.compress_user(
190 file = util_path.compress_user(
191 py3compat.cast_unicode(file, util_path.fs_encoding)
191 py3compat.cast_unicode(file, util_path.fs_encoding)
192 )
192 )
193 tpl_link = "File %s%%s%s" % (ColorFilename, ColorNormal)
193 tpl_link = "File %s%%s%s" % (ColorFilename, ColorNormal)
194
194
195 return tpl_link % file
195 return tpl_link % file
196
196
197 #---------------------------------------------------------------------------
197 #---------------------------------------------------------------------------
198 # Module classes
198 # Module classes
199 class TBTools(colorable.Colorable):
199 class TBTools(colorable.Colorable):
200 """Basic tools used by all traceback printer classes."""
200 """Basic tools used by all traceback printer classes."""
201
201
202 # Number of frames to skip when reporting tracebacks
202 # Number of frames to skip when reporting tracebacks
203 tb_offset = 0
203 tb_offset = 0
204
204
205 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
205 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
206 # Whether to call the interactive pdb debugger after printing
206 # Whether to call the interactive pdb debugger after printing
207 # tracebacks or not
207 # tracebacks or not
208 super(TBTools, self).__init__(parent=parent, config=config)
208 super(TBTools, self).__init__(parent=parent, config=config)
209 self.call_pdb = call_pdb
209 self.call_pdb = call_pdb
210
210
211 # Output stream to write to. Note that we store the original value in
211 # Output stream to write to. Note that we store the original value in
212 # a private attribute and then make the public ostream a property, so
212 # a private attribute and then make the public ostream a property, so
213 # that we can delay accessing sys.stdout until runtime. The way
213 # that we can delay accessing sys.stdout until runtime. The way
214 # things are written now, the sys.stdout object is dynamically managed
214 # things are written now, the sys.stdout object is dynamically managed
215 # so a reference to it should NEVER be stored statically. This
215 # so a reference to it should NEVER be stored statically. This
216 # property approach confines this detail to a single location, and all
216 # property approach confines this detail to a single location, and all
217 # subclasses can simply access self.ostream for writing.
217 # subclasses can simply access self.ostream for writing.
218 self._ostream = ostream
218 self._ostream = ostream
219
219
220 # Create color table
220 # Create color table
221 self.color_scheme_table = exception_colors()
221 self.color_scheme_table = exception_colors()
222
222
223 self.set_colors(color_scheme)
223 self.set_colors(color_scheme)
224 self.old_scheme = color_scheme # save initial value for toggles
224 self.old_scheme = color_scheme # save initial value for toggles
225
225
226 if call_pdb:
226 if call_pdb:
227 self.pdb = debugger.Pdb()
227 self.pdb = debugger.Pdb()
228 else:
228 else:
229 self.pdb = None
229 self.pdb = None
230
230
231 def _get_ostream(self):
231 def _get_ostream(self):
232 """Output stream that exceptions are written to.
232 """Output stream that exceptions are written to.
233
233
234 Valid values are:
234 Valid values are:
235
235
236 - None: the default, which means that IPython will dynamically resolve
236 - None: the default, which means that IPython will dynamically resolve
237 to sys.stdout. This ensures compatibility with most tools, including
237 to sys.stdout. This ensures compatibility with most tools, including
238 Windows (where plain stdout doesn't recognize ANSI escapes).
238 Windows (where plain stdout doesn't recognize ANSI escapes).
239
239
240 - Any object with 'write' and 'flush' attributes.
240 - Any object with 'write' and 'flush' attributes.
241 """
241 """
242 return sys.stdout if self._ostream is None else self._ostream
242 return sys.stdout if self._ostream is None else self._ostream
243
243
244 def _set_ostream(self, val):
244 def _set_ostream(self, val):
245 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
245 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
246 self._ostream = val
246 self._ostream = val
247
247
248 ostream = property(_get_ostream, _set_ostream)
248 ostream = property(_get_ostream, _set_ostream)
249
249
250 def get_parts_of_chained_exception(self, evalue):
250 def get_parts_of_chained_exception(self, evalue):
251 def get_chained_exception(exception_value):
251 def get_chained_exception(exception_value):
252 cause = getattr(exception_value, '__cause__', None)
252 cause = getattr(exception_value, '__cause__', None)
253 if cause:
253 if cause:
254 return cause
254 return cause
255 if getattr(exception_value, '__suppress_context__', False):
255 if getattr(exception_value, '__suppress_context__', False):
256 return None
256 return None
257 return getattr(exception_value, '__context__', None)
257 return getattr(exception_value, '__context__', None)
258
258
259 chained_evalue = get_chained_exception(evalue)
259 chained_evalue = get_chained_exception(evalue)
260
260
261 if chained_evalue:
261 if chained_evalue:
262 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
262 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
263
263
264 def prepare_chained_exception_message(self, cause):
264 def prepare_chained_exception_message(self, cause):
265 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
265 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
266 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
266 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
267
267
268 if cause:
268 if cause:
269 message = [[direct_cause]]
269 message = [[direct_cause]]
270 else:
270 else:
271 message = [[exception_during_handling]]
271 message = [[exception_during_handling]]
272 return message
272 return message
273
273
274 @property
274 @property
275 def has_colors(self):
275 def has_colors(self):
276 return self.color_scheme_table.active_scheme_name.lower() != "nocolor"
276 return self.color_scheme_table.active_scheme_name.lower() != "nocolor"
277
277
278 def set_colors(self, *args, **kw):
278 def set_colors(self, *args, **kw):
279 """Shorthand access to the color table scheme selector method."""
279 """Shorthand access to the color table scheme selector method."""
280
280
281 # Set own color table
281 # Set own color table
282 self.color_scheme_table.set_active_scheme(*args, **kw)
282 self.color_scheme_table.set_active_scheme(*args, **kw)
283 # for convenience, set Colors to the active scheme
283 # for convenience, set Colors to the active scheme
284 self.Colors = self.color_scheme_table.active_colors
284 self.Colors = self.color_scheme_table.active_colors
285 # Also set colors of debugger
285 # Also set colors of debugger
286 if hasattr(self, 'pdb') and self.pdb is not None:
286 if hasattr(self, 'pdb') and self.pdb is not None:
287 self.pdb.set_colors(*args, **kw)
287 self.pdb.set_colors(*args, **kw)
288
288
289 def color_toggle(self):
289 def color_toggle(self):
290 """Toggle between the currently active color scheme and NoColor."""
290 """Toggle between the currently active color scheme and NoColor."""
291
291
292 if self.color_scheme_table.active_scheme_name == 'NoColor':
292 if self.color_scheme_table.active_scheme_name == 'NoColor':
293 self.color_scheme_table.set_active_scheme(self.old_scheme)
293 self.color_scheme_table.set_active_scheme(self.old_scheme)
294 self.Colors = self.color_scheme_table.active_colors
294 self.Colors = self.color_scheme_table.active_colors
295 else:
295 else:
296 self.old_scheme = self.color_scheme_table.active_scheme_name
296 self.old_scheme = self.color_scheme_table.active_scheme_name
297 self.color_scheme_table.set_active_scheme('NoColor')
297 self.color_scheme_table.set_active_scheme('NoColor')
298 self.Colors = self.color_scheme_table.active_colors
298 self.Colors = self.color_scheme_table.active_colors
299
299
300 def stb2text(self, stb):
300 def stb2text(self, stb):
301 """Convert a structured traceback (a list) to a string."""
301 """Convert a structured traceback (a list) to a string."""
302 return '\n'.join(stb)
302 return '\n'.join(stb)
303
303
304 def text(self, etype, value, tb, tb_offset=None, context=5):
304 def text(self, etype, value, tb, tb_offset=None, context=5):
305 """Return formatted traceback.
305 """Return formatted traceback.
306
306
307 Subclasses may override this if they add extra arguments.
307 Subclasses may override this if they add extra arguments.
308 """
308 """
309 tb_list = self.structured_traceback(etype, value, tb,
309 tb_list = self.structured_traceback(etype, value, tb,
310 tb_offset, context)
310 tb_offset, context)
311 return self.stb2text(tb_list)
311 return self.stb2text(tb_list)
312
312
313 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
313 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
314 context=5, mode=None):
314 context=5, mode=None):
315 """Return a list of traceback frames.
315 """Return a list of traceback frames.
316
316
317 Must be implemented by each class.
317 Must be implemented by each class.
318 """
318 """
319 raise NotImplementedError()
319 raise NotImplementedError()
320
320
321
321
322 #---------------------------------------------------------------------------
322 #---------------------------------------------------------------------------
323 class ListTB(TBTools):
323 class ListTB(TBTools):
324 """Print traceback information from a traceback list, with optional color.
324 """Print traceback information from a traceback list, with optional color.
325
325
326 Calling requires 3 arguments: (etype, evalue, elist)
326 Calling requires 3 arguments: (etype, evalue, elist)
327 as would be obtained by::
327 as would be obtained by::
328
328
329 etype, evalue, tb = sys.exc_info()
329 etype, evalue, tb = sys.exc_info()
330 if tb:
330 if tb:
331 elist = traceback.extract_tb(tb)
331 elist = traceback.extract_tb(tb)
332 else:
332 else:
333 elist = None
333 elist = None
334
334
335 It can thus be used by programs which need to process the traceback before
335 It can thus be used by programs which need to process the traceback before
336 printing (such as console replacements based on the code module from the
336 printing (such as console replacements based on the code module from the
337 standard library).
337 standard library).
338
338
339 Because they are meant to be called without a full traceback (only a
339 Because they are meant to be called without a full traceback (only a
340 list), instances of this class can't call the interactive pdb debugger."""
340 list), instances of this class can't call the interactive pdb debugger."""
341
341
342 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
342 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
343 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
343 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
344 ostream=ostream, parent=parent,config=config)
344 ostream=ostream, parent=parent,config=config)
345
345
346 def __call__(self, etype, value, elist):
346 def __call__(self, etype, value, elist):
347 self.ostream.flush()
347 self.ostream.flush()
348 self.ostream.write(self.text(etype, value, elist))
348 self.ostream.write(self.text(etype, value, elist))
349 self.ostream.write('\n')
349 self.ostream.write('\n')
350
350
351 def _extract_tb(self, tb):
351 def _extract_tb(self, tb):
352 if tb:
352 if tb:
353 return traceback.extract_tb(tb)
353 return traceback.extract_tb(tb)
354 else:
354 else:
355 return None
355 return None
356
356
357 def structured_traceback(self, etype, evalue, etb=None, tb_offset=None,
357 def structured_traceback(self, etype, evalue, etb=None, tb_offset=None,
358 context=5):
358 context=5):
359 """Return a color formatted string with the traceback info.
359 """Return a color formatted string with the traceback info.
360
360
361 Parameters
361 Parameters
362 ----------
362 ----------
363 etype : exception type
363 etype : exception type
364 Type of the exception raised.
364 Type of the exception raised.
365 evalue : object
365 evalue : object
366 Data stored in the exception
366 Data stored in the exception
367 etb : object
367 etb : object
368 If list: List of frames, see class docstring for details.
368 If list: List of frames, see class docstring for details.
369 If Traceback: Traceback of the exception.
369 If Traceback: Traceback of the exception.
370 tb_offset : int, optional
370 tb_offset : int, optional
371 Number of frames in the traceback to skip. If not given, the
371 Number of frames in the traceback to skip. If not given, the
372 instance evalue is used (set in constructor).
372 instance evalue is used (set in constructor).
373 context : int, optional
373 context : int, optional
374 Number of lines of context information to print.
374 Number of lines of context information to print.
375
375
376 Returns
376 Returns
377 -------
377 -------
378 String with formatted exception.
378 String with formatted exception.
379 """
379 """
380 # This is a workaround to get chained_exc_ids in recursive calls
380 # This is a workaround to get chained_exc_ids in recursive calls
381 # etb should not be a tuple if structured_traceback is not recursive
381 # etb should not be a tuple if structured_traceback is not recursive
382 if isinstance(etb, tuple):
382 if isinstance(etb, tuple):
383 etb, chained_exc_ids = etb
383 etb, chained_exc_ids = etb
384 else:
384 else:
385 chained_exc_ids = set()
385 chained_exc_ids = set()
386
386
387 if isinstance(etb, list):
387 if isinstance(etb, list):
388 elist = etb
388 elist = etb
389 elif etb is not None:
389 elif etb is not None:
390 elist = self._extract_tb(etb)
390 elist = self._extract_tb(etb)
391 else:
391 else:
392 elist = []
392 elist = []
393 tb_offset = self.tb_offset if tb_offset is None else tb_offset
393 tb_offset = self.tb_offset if tb_offset is None else tb_offset
394 Colors = self.Colors
394 Colors = self.Colors
395 out_list = []
395 out_list = []
396 if elist:
396 if elist:
397
397
398 if tb_offset and len(elist) > tb_offset:
398 if tb_offset and len(elist) > tb_offset:
399 elist = elist[tb_offset:]
399 elist = elist[tb_offset:]
400
400
401 out_list.append('Traceback %s(most recent call last)%s:' %
401 out_list.append('Traceback %s(most recent call last)%s:' %
402 (Colors.normalEm, Colors.Normal) + '\n')
402 (Colors.normalEm, Colors.Normal) + '\n')
403 out_list.extend(self._format_list(elist))
403 out_list.extend(self._format_list(elist))
404 # The exception info should be a single entry in the list.
404 # The exception info should be a single entry in the list.
405 lines = ''.join(self._format_exception_only(etype, evalue))
405 lines = ''.join(self._format_exception_only(etype, evalue))
406 out_list.append(lines)
406 out_list.append(lines)
407
407
408 exception = self.get_parts_of_chained_exception(evalue)
408 exception = self.get_parts_of_chained_exception(evalue)
409
409
410 if exception and not id(exception[1]) in chained_exc_ids:
410 if exception and not id(exception[1]) in chained_exc_ids:
411 chained_exception_message = self.prepare_chained_exception_message(
411 chained_exception_message = self.prepare_chained_exception_message(
412 evalue.__cause__)[0]
412 evalue.__cause__)[0]
413 etype, evalue, etb = exception
413 etype, evalue, etb = exception
414 # Trace exception to avoid infinite 'cause' loop
414 # Trace exception to avoid infinite 'cause' loop
415 chained_exc_ids.add(id(exception[1]))
415 chained_exc_ids.add(id(exception[1]))
416 chained_exceptions_tb_offset = 0
416 chained_exceptions_tb_offset = 0
417 out_list = (
417 out_list = (
418 self.structured_traceback(
418 self.structured_traceback(
419 etype, evalue, (etb, chained_exc_ids),
419 etype, evalue, (etb, chained_exc_ids),
420 chained_exceptions_tb_offset, context)
420 chained_exceptions_tb_offset, context)
421 + chained_exception_message
421 + chained_exception_message
422 + out_list)
422 + out_list)
423
423
424 return out_list
424 return out_list
425
425
426 def _format_list(self, extracted_list):
426 def _format_list(self, extracted_list):
427 """Format a list of traceback entry tuples for printing.
427 """Format a list of traceback entry tuples for printing.
428
428
429 Given a list of tuples as returned by extract_tb() or
429 Given a list of tuples as returned by extract_tb() or
430 extract_stack(), return a list of strings ready for printing.
430 extract_stack(), return a list of strings ready for printing.
431 Each string in the resulting list corresponds to the item with the
431 Each string in the resulting list corresponds to the item with the
432 same index in the argument list. Each string ends in a newline;
432 same index in the argument list. Each string ends in a newline;
433 the strings may contain internal newlines as well, for those items
433 the strings may contain internal newlines as well, for those items
434 whose source text line is not None.
434 whose source text line is not None.
435
435
436 Lifted almost verbatim from traceback.py
436 Lifted almost verbatim from traceback.py
437 """
437 """
438
438
439 Colors = self.Colors
439 Colors = self.Colors
440 list = []
440 list = []
441 for filename, lineno, name, line in extracted_list[:-1]:
441 for filename, lineno, name, line in extracted_list[:-1]:
442 item = " %s, line %s%d%s, in %s%s%s\n" % (
442 item = " %s, line %s%d%s, in %s%s%s\n" % (
443 _format_filename(filename, Colors.filename, Colors.Normal),
443 _format_filename(filename, Colors.filename, Colors.Normal),
444 Colors.lineno,
444 Colors.lineno,
445 lineno,
445 lineno,
446 Colors.Normal,
446 Colors.Normal,
447 Colors.name,
447 Colors.name,
448 name,
448 name,
449 Colors.Normal,
449 Colors.Normal,
450 )
450 )
451 if line:
451 if line:
452 item += ' %s\n' % line.strip()
452 item += ' %s\n' % line.strip()
453 list.append(item)
453 list.append(item)
454 # Emphasize the last entry
454 # Emphasize the last entry
455 filename, lineno, name, line = extracted_list[-1]
455 filename, lineno, name, line = extracted_list[-1]
456 item = "%s %s, line %s%d%s, in %s%s%s%s\n" % (
456 item = "%s %s, line %s%d%s, in %s%s%s%s\n" % (
457 Colors.normalEm,
457 Colors.normalEm,
458 _format_filename(filename, Colors.filenameEm, Colors.normalEm),
458 _format_filename(filename, Colors.filenameEm, Colors.normalEm),
459 Colors.linenoEm,
459 Colors.linenoEm,
460 lineno,
460 lineno,
461 Colors.normalEm,
461 Colors.normalEm,
462 Colors.nameEm,
462 Colors.nameEm,
463 name,
463 name,
464 Colors.normalEm,
464 Colors.normalEm,
465 Colors.Normal,
465 Colors.Normal,
466 )
466 )
467 if line:
467 if line:
468 item += '%s %s%s\n' % (Colors.line, line.strip(),
468 item += '%s %s%s\n' % (Colors.line, line.strip(),
469 Colors.Normal)
469 Colors.Normal)
470 list.append(item)
470 list.append(item)
471 return list
471 return list
472
472
473 def _format_exception_only(self, etype, value):
473 def _format_exception_only(self, etype, value):
474 """Format the exception part of a traceback.
474 """Format the exception part of a traceback.
475
475
476 The arguments are the exception type and value such as given by
476 The arguments are the exception type and value such as given by
477 sys.exc_info()[:2]. The return value is a list of strings, each ending
477 sys.exc_info()[:2]. The return value is a list of strings, each ending
478 in a newline. Normally, the list contains a single string; however,
478 in a newline. Normally, the list contains a single string; however,
479 for SyntaxError exceptions, it contains several lines that (when
479 for SyntaxError exceptions, it contains several lines that (when
480 printed) display detailed information about where the syntax error
480 printed) display detailed information about where the syntax error
481 occurred. The message indicating which exception occurred is the
481 occurred. The message indicating which exception occurred is the
482 always last string in the list.
482 always last string in the list.
483
483
484 Also lifted nearly verbatim from traceback.py
484 Also lifted nearly verbatim from traceback.py
485 """
485 """
486 have_filedata = False
486 have_filedata = False
487 Colors = self.Colors
487 Colors = self.Colors
488 list = []
488 list = []
489 stype = py3compat.cast_unicode(Colors.excName + etype.__name__ + Colors.Normal)
489 stype = py3compat.cast_unicode(Colors.excName + etype.__name__ + Colors.Normal)
490 if value is None:
490 if value is None:
491 # Not sure if this can still happen in Python 2.6 and above
491 # Not sure if this can still happen in Python 2.6 and above
492 list.append(stype + '\n')
492 list.append(stype + '\n')
493 else:
493 else:
494 if issubclass(etype, SyntaxError):
494 if issubclass(etype, SyntaxError):
495 have_filedata = True
495 have_filedata = True
496 if not value.filename: value.filename = "<string>"
496 if not value.filename: value.filename = "<string>"
497 if value.lineno:
497 if value.lineno:
498 lineno = value.lineno
498 lineno = value.lineno
499 textline = linecache.getline(value.filename, value.lineno)
499 textline = linecache.getline(value.filename, value.lineno)
500 else:
500 else:
501 lineno = "unknown"
501 lineno = "unknown"
502 textline = ""
502 textline = ""
503 list.append(
503 list.append(
504 "%s %s, line %s%s%s\n"
504 "%s %s, line %s%s%s\n"
505 % (
505 % (
506 Colors.normalEm,
506 Colors.normalEm,
507 _format_filename(
507 _format_filename(
508 value.filename, Colors.filenameEm, Colors.normalEm
508 value.filename, Colors.filenameEm, Colors.normalEm
509 ),
509 ),
510 Colors.linenoEm,
510 Colors.linenoEm,
511 lineno,
511 lineno,
512 Colors.Normal,
512 Colors.Normal,
513 )
513 )
514 )
514 )
515 if textline == "":
515 if textline == "":
516 textline = py3compat.cast_unicode(value.text, "utf-8")
516 textline = py3compat.cast_unicode(value.text, "utf-8")
517
517
518 if textline is not None:
518 if textline is not None:
519 i = 0
519 i = 0
520 while i < len(textline) and textline[i].isspace():
520 while i < len(textline) and textline[i].isspace():
521 i += 1
521 i += 1
522 list.append('%s %s%s\n' % (Colors.line,
522 list.append('%s %s%s\n' % (Colors.line,
523 textline.strip(),
523 textline.strip(),
524 Colors.Normal))
524 Colors.Normal))
525 if value.offset is not None:
525 if value.offset is not None:
526 s = ' '
526 s = ' '
527 for c in textline[i:value.offset - 1]:
527 for c in textline[i:value.offset - 1]:
528 if c.isspace():
528 if c.isspace():
529 s += c
529 s += c
530 else:
530 else:
531 s += ' '
531 s += ' '
532 list.append('%s%s^%s\n' % (Colors.caret, s,
532 list.append('%s%s^%s\n' % (Colors.caret, s,
533 Colors.Normal))
533 Colors.Normal))
534
534
535 try:
535 try:
536 s = value.msg
536 s = value.msg
537 except Exception:
537 except Exception:
538 s = self._some_str(value)
538 s = self._some_str(value)
539 if s:
539 if s:
540 list.append('%s%s:%s %s\n' % (stype, Colors.excName,
540 list.append('%s%s:%s %s\n' % (stype, Colors.excName,
541 Colors.Normal, s))
541 Colors.Normal, s))
542 else:
542 else:
543 list.append('%s\n' % stype)
543 list.append('%s\n' % stype)
544
544
545 # sync with user hooks
545 # sync with user hooks
546 if have_filedata:
546 if have_filedata:
547 ipinst = get_ipython()
547 ipinst = get_ipython()
548 if ipinst is not None:
548 if ipinst is not None:
549 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
549 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
550
550
551 return list
551 return list
552
552
553 def get_exception_only(self, etype, value):
553 def get_exception_only(self, etype, value):
554 """Only print the exception type and message, without a traceback.
554 """Only print the exception type and message, without a traceback.
555
555
556 Parameters
556 Parameters
557 ----------
557 ----------
558 etype : exception type
558 etype : exception type
559 evalue : exception value
559 evalue : exception value
560 """
560 """
561 return ListTB.structured_traceback(self, etype, value)
561 return ListTB.structured_traceback(self, etype, value)
562
562
563 def show_exception_only(self, etype, evalue):
563 def show_exception_only(self, etype, evalue):
564 """Only print the exception type and message, without a traceback.
564 """Only print the exception type and message, without a traceback.
565
565
566 Parameters
566 Parameters
567 ----------
567 ----------
568 etype : exception type
568 etype : exception type
569 evalue : exception value
569 evalue : exception value
570 """
570 """
571 # This method needs to use __call__ from *this* class, not the one from
571 # This method needs to use __call__ from *this* class, not the one from
572 # a subclass whose signature or behavior may be different
572 # a subclass whose signature or behavior may be different
573 ostream = self.ostream
573 ostream = self.ostream
574 ostream.flush()
574 ostream.flush()
575 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
575 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
576 ostream.flush()
576 ostream.flush()
577
577
578 def _some_str(self, value):
578 def _some_str(self, value):
579 # Lifted from traceback.py
579 # Lifted from traceback.py
580 try:
580 try:
581 return py3compat.cast_unicode(str(value))
581 return py3compat.cast_unicode(str(value))
582 except:
582 except:
583 return u'<unprintable %s object>' % type(value).__name__
583 return u'<unprintable %s object>' % type(value).__name__
584
584
585
585
586 #----------------------------------------------------------------------------
586 #----------------------------------------------------------------------------
587 class VerboseTB(TBTools):
587 class VerboseTB(TBTools):
588 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
588 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
589 of HTML. Requires inspect and pydoc. Crazy, man.
589 of HTML. Requires inspect and pydoc. Crazy, man.
590
590
591 Modified version which optionally strips the topmost entries from the
591 Modified version which optionally strips the topmost entries from the
592 traceback, to be used with alternate interpreters (because their own code
592 traceback, to be used with alternate interpreters (because their own code
593 would appear in the traceback)."""
593 would appear in the traceback)."""
594
594
595 def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None,
595 def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None,
596 tb_offset=0, long_header=False, include_vars=True,
596 tb_offset=0, long_header=False, include_vars=True,
597 check_cache=None, debugger_cls = None,
597 check_cache=None, debugger_cls = None,
598 parent=None, config=None):
598 parent=None, config=None):
599 """Specify traceback offset, headers and color scheme.
599 """Specify traceback offset, headers and color scheme.
600
600
601 Define how many frames to drop from the tracebacks. Calling it with
601 Define how many frames to drop from the tracebacks. Calling it with
602 tb_offset=1 allows use of this handler in interpreters which will have
602 tb_offset=1 allows use of this handler in interpreters which will have
603 their own code at the top of the traceback (VerboseTB will first
603 their own code at the top of the traceback (VerboseTB will first
604 remove that frame before printing the traceback info)."""
604 remove that frame before printing the traceback info)."""
605 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
605 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
606 ostream=ostream, parent=parent, config=config)
606 ostream=ostream, parent=parent, config=config)
607 self.tb_offset = tb_offset
607 self.tb_offset = tb_offset
608 self.long_header = long_header
608 self.long_header = long_header
609 self.include_vars = include_vars
609 self.include_vars = include_vars
610 # By default we use linecache.checkcache, but the user can provide a
610 # By default we use linecache.checkcache, but the user can provide a
611 # different check_cache implementation. This is used by the IPython
611 # different check_cache implementation. This is used by the IPython
612 # kernel to provide tracebacks for interactive code that is cached,
612 # kernel to provide tracebacks for interactive code that is cached,
613 # by a compiler instance that flushes the linecache but preserves its
613 # by a compiler instance that flushes the linecache but preserves its
614 # own code cache.
614 # own code cache.
615 if check_cache is None:
615 if check_cache is None:
616 check_cache = linecache.checkcache
616 check_cache = linecache.checkcache
617 self.check_cache = check_cache
617 self.check_cache = check_cache
618
618
619 self.debugger_cls = debugger_cls or debugger.Pdb
619 self.debugger_cls = debugger_cls or debugger.Pdb
620 self.skip_hidden = True
620 self.skip_hidden = True
621
621
622 def format_record(self, frame_info):
622 def format_record(self, frame_info):
623 """Format a single stack frame"""
623 """Format a single stack frame"""
624 Colors = self.Colors # just a shorthand + quicker name lookup
624 Colors = self.Colors # just a shorthand + quicker name lookup
625 ColorsNormal = Colors.Normal # used a lot
625 ColorsNormal = Colors.Normal # used a lot
626
626
627 if isinstance(frame_info, stack_data.RepeatedFrames):
627 if isinstance(frame_info, stack_data.RepeatedFrames):
628 return ' %s[... skipping similar frames: %s]%s\n' % (
628 return ' %s[... skipping similar frames: %s]%s\n' % (
629 Colors.excName, frame_info.description, ColorsNormal)
629 Colors.excName, frame_info.description, ColorsNormal)
630
630
631 indent = ' ' * INDENT_SIZE
631 indent = " " * INDENT_SIZE
632 em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal)
632 em_normal = "%s\n%s%s" % (Colors.valEm, indent, ColorsNormal)
633 tpl_call = 'line %s, in %s%%s%s%%s%s' % (frame_info.lineno, Colors.vName, Colors.valEm,
633 tpl_call = "line %s, in %s%%s%s%%s%s" % (
634 ColorsNormal)
634 frame_info.lineno,
635 tpl_call_fail = 'line %s, in %s%%s%s(***failed resolving arguments***)%s' % \
635 Colors.vName,
636 (frame_info.lineno, Colors.vName, Colors.valEm, ColorsNormal)
636 Colors.valEm,
637 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
637 ColorsNormal,
638 )
639 tpl_call_fail = "line %s, in %s%%s%s(***failed resolving arguments***)%s" % (
640 frame_info.lineno,
641 Colors.vName,
642 Colors.valEm,
643 ColorsNormal,
644 )
645 tpl_name_val = "%%s %s= %%s%s" % (Colors.valEm, ColorsNormal)
638
646
639 link = _format_filename(frame_info.filename, Colors.filenameEm, ColorsNormal)
647 link = _format_filename(frame_info.filename, Colors.filenameEm, ColorsNormal)
640 args, varargs, varkw, locals_ = inspect.getargvalues(frame_info.frame)
648 args, varargs, varkw, locals_ = inspect.getargvalues(frame_info.frame)
641
649
642 func = frame_info.executing.code_qualname()
650 func = frame_info.executing.code_qualname()
643 if func == '<module>':
651 if func == '<module>':
644 call = tpl_call % (func, '')
652 call = tpl_call % (func, '')
645 else:
653 else:
646 # Decide whether to include variable details or not
654 # Decide whether to include variable details or not
647 var_repr = eqrepr if self.include_vars else nullrepr
655 var_repr = eqrepr if self.include_vars else nullrepr
648 try:
656 try:
649 call = tpl_call % (func, inspect.formatargvalues(args,
657 call = tpl_call % (func, inspect.formatargvalues(args,
650 varargs, varkw,
658 varargs, varkw,
651 locals_, formatvalue=var_repr))
659 locals_, formatvalue=var_repr))
652 except KeyError:
660 except KeyError:
653 # This happens in situations like errors inside generator
661 # This happens in situations like errors inside generator
654 # expressions, where local variables are listed in the
662 # expressions, where local variables are listed in the
655 # line, but can't be extracted from the frame. I'm not
663 # line, but can't be extracted from the frame. I'm not
656 # 100% sure this isn't actually a bug in inspect itself,
664 # 100% sure this isn't actually a bug in inspect itself,
657 # but since there's no info for us to compute with, the
665 # but since there's no info for us to compute with, the
658 # best we can do is report the failure and move on. Here
666 # best we can do is report the failure and move on. Here
659 # we must *not* call any traceback construction again,
667 # we must *not* call any traceback construction again,
660 # because that would mess up use of %debug later on. So we
668 # because that would mess up use of %debug later on. So we
661 # simply report the failure and move on. The only
669 # simply report the failure and move on. The only
662 # limitation will be that this frame won't have locals
670 # limitation will be that this frame won't have locals
663 # listed in the call signature. Quite subtle problem...
671 # listed in the call signature. Quite subtle problem...
664 # I can't think of a good way to validate this in a unit
672 # I can't think of a good way to validate this in a unit
665 # test, but running a script consisting of:
673 # test, but running a script consisting of:
666 # dict( (k,v.strip()) for (k,v) in range(10) )
674 # dict( (k,v.strip()) for (k,v) in range(10) )
667 # will illustrate the error, if this exception catch is
675 # will illustrate the error, if this exception catch is
668 # disabled.
676 # disabled.
669 call = tpl_call_fail % func
677 call = tpl_call_fail % func
670
678
671 lvals = ''
679 lvals = ''
672 lvals_list = []
680 lvals_list = []
673 if self.include_vars:
681 if self.include_vars:
674 try:
682 try:
675 # we likely want to fix stackdata at some point, but
683 # we likely want to fix stackdata at some point, but
676 # still need a workaround.
684 # still need a workaround.
677 fibp = frame_info.variables_in_executing_piece
685 fibp = frame_info.variables_in_executing_piece
678 for var in fibp:
686 for var in fibp:
679 lvals_list.append(tpl_name_val % (var.name, repr(var.value)))
687 lvals_list.append(tpl_name_val % (var.name, repr(var.value)))
680 except Exception:
688 except Exception:
681 lvals_list.append(
689 lvals_list.append(
682 "Exception trying to inspect frame. No more locals available."
690 "Exception trying to inspect frame. No more locals available."
683 )
691 )
684 if lvals_list:
692 if lvals_list:
685 lvals = '%s%s' % (indent, em_normal.join(lvals_list))
693 lvals = '%s%s' % (indent, em_normal.join(lvals_list))
686
694
687 result = "%s, %s\n" % (link, call)
695 result = "%s, %s\n" % (link, call)
688
696
689 result += ''.join(_format_traceback_lines(frame_info.lines, Colors, self.has_colors, lvals))
697 result += ''.join(_format_traceback_lines(frame_info.lines, Colors, self.has_colors, lvals))
690 return result
698 return result
691
699
692 def prepare_header(self, etype, long_version=False):
700 def prepare_header(self, etype, long_version=False):
693 colors = self.Colors # just a shorthand + quicker name lookup
701 colors = self.Colors # just a shorthand + quicker name lookup
694 colorsnormal = colors.Normal # used a lot
702 colorsnormal = colors.Normal # used a lot
695 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
703 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
696 width = min(75, get_terminal_size()[0])
704 width = min(75, get_terminal_size()[0])
697 if long_version:
705 if long_version:
698 # Header with the exception type, python version, and date
706 # Header with the exception type, python version, and date
699 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
707 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
700 date = time.ctime(time.time())
708 date = time.ctime(time.time())
701
709
702 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * width, colorsnormal,
710 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * width, colorsnormal,
703 exc, ' ' * (width - len(str(etype)) - len(pyver)),
711 exc, ' ' * (width - len(str(etype)) - len(pyver)),
704 pyver, date.rjust(width) )
712 pyver, date.rjust(width) )
705 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
713 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
706 "\ncalls leading up to the error, with the most recent (innermost) call last."
714 "\ncalls leading up to the error, with the most recent (innermost) call last."
707 else:
715 else:
708 # Simplified header
716 # Simplified header
709 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
717 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
710 rjust(width - len(str(etype))) )
718 rjust(width - len(str(etype))) )
711
719
712 return head
720 return head
713
721
714 def format_exception(self, etype, evalue):
722 def format_exception(self, etype, evalue):
715 colors = self.Colors # just a shorthand + quicker name lookup
723 colors = self.Colors # just a shorthand + quicker name lookup
716 colorsnormal = colors.Normal # used a lot
724 colorsnormal = colors.Normal # used a lot
717 # Get (safely) a string form of the exception info
725 # Get (safely) a string form of the exception info
718 try:
726 try:
719 etype_str, evalue_str = map(str, (etype, evalue))
727 etype_str, evalue_str = map(str, (etype, evalue))
720 except:
728 except:
721 # User exception is improperly defined.
729 # User exception is improperly defined.
722 etype, evalue = str, sys.exc_info()[:2]
730 etype, evalue = str, sys.exc_info()[:2]
723 etype_str, evalue_str = map(str, (etype, evalue))
731 etype_str, evalue_str = map(str, (etype, evalue))
724 # ... and format it
732 # ... and format it
725 return ['%s%s%s: %s' % (colors.excName, etype_str,
733 return ['%s%s%s: %s' % (colors.excName, etype_str,
726 colorsnormal, py3compat.cast_unicode(evalue_str))]
734 colorsnormal, py3compat.cast_unicode(evalue_str))]
727
735
728 def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset):
736 def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset):
729 """Formats the header, traceback and exception message for a single exception.
737 """Formats the header, traceback and exception message for a single exception.
730
738
731 This may be called multiple times by Python 3 exception chaining
739 This may be called multiple times by Python 3 exception chaining
732 (PEP 3134).
740 (PEP 3134).
733 """
741 """
734 # some locals
742 # some locals
735 orig_etype = etype
743 orig_etype = etype
736 try:
744 try:
737 etype = etype.__name__
745 etype = etype.__name__
738 except AttributeError:
746 except AttributeError:
739 pass
747 pass
740
748
741 tb_offset = self.tb_offset if tb_offset is None else tb_offset
749 tb_offset = self.tb_offset if tb_offset is None else tb_offset
742 head = self.prepare_header(etype, self.long_header)
750 head = self.prepare_header(etype, self.long_header)
743 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
751 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
744
752
745 frames = []
753 frames = []
746 skipped = 0
754 skipped = 0
747 lastrecord = len(records) - 1
755 lastrecord = len(records) - 1
748 for i, r in enumerate(records):
756 for i, r in enumerate(records):
749 if not isinstance(r, stack_data.RepeatedFrames) and self.skip_hidden:
757 if not isinstance(r, stack_data.RepeatedFrames) and self.skip_hidden:
750 if r.frame.f_locals.get("__tracebackhide__", 0) and i != lastrecord:
758 if r.frame.f_locals.get("__tracebackhide__", 0) and i != lastrecord:
751 skipped += 1
759 skipped += 1
752 continue
760 continue
753 if skipped:
761 if skipped:
754 Colors = self.Colors # just a shorthand + quicker name lookup
762 Colors = self.Colors # just a shorthand + quicker name lookup
755 ColorsNormal = Colors.Normal # used a lot
763 ColorsNormal = Colors.Normal # used a lot
756 frames.append(
764 frames.append(
757 " %s[... skipping hidden %s frame]%s\n"
765 " %s[... skipping hidden %s frame]%s\n"
758 % (Colors.excName, skipped, ColorsNormal)
766 % (Colors.excName, skipped, ColorsNormal)
759 )
767 )
760 skipped = 0
768 skipped = 0
761 frames.append(self.format_record(r))
769 frames.append(self.format_record(r))
762 if skipped:
770 if skipped:
763 Colors = self.Colors # just a shorthand + quicker name lookup
771 Colors = self.Colors # just a shorthand + quicker name lookup
764 ColorsNormal = Colors.Normal # used a lot
772 ColorsNormal = Colors.Normal # used a lot
765 frames.append(
773 frames.append(
766 " %s[... skipping hidden %s frame]%s\n"
774 " %s[... skipping hidden %s frame]%s\n"
767 % (Colors.excName, skipped, ColorsNormal)
775 % (Colors.excName, skipped, ColorsNormal)
768 )
776 )
769
777
770 formatted_exception = self.format_exception(etype, evalue)
778 formatted_exception = self.format_exception(etype, evalue)
771 if records:
779 if records:
772 frame_info = records[-1]
780 frame_info = records[-1]
773 ipinst = get_ipython()
781 ipinst = get_ipython()
774 if ipinst is not None:
782 if ipinst is not None:
775 ipinst.hooks.synchronize_with_editor(frame_info.filename, frame_info.lineno, 0)
783 ipinst.hooks.synchronize_with_editor(frame_info.filename, frame_info.lineno, 0)
776
784
777 return [[head] + frames + [''.join(formatted_exception[0])]]
785 return [[head] + frames + [''.join(formatted_exception[0])]]
778
786
779 def get_records(self, etb, number_of_lines_of_context, tb_offset):
787 def get_records(self, etb, number_of_lines_of_context, tb_offset):
780 context = number_of_lines_of_context - 1
788 context = number_of_lines_of_context - 1
781 after = context // 2
789 after = context // 2
782 before = context - after
790 before = context - after
783 if self.has_colors:
791 if self.has_colors:
784 style = get_style_by_name('default')
792 style = get_style_by_name('default')
785 style = stack_data.style_with_executing_node(style, 'bg:#00005f')
793 style = stack_data.style_with_executing_node(style, 'bg:#00005f')
786 formatter = Terminal256Formatter(style=style)
794 formatter = Terminal256Formatter(style=style)
787 else:
795 else:
788 formatter = None
796 formatter = None
789 options = stack_data.Options(
797 options = stack_data.Options(
790 before=before,
798 before=before,
791 after=after,
799 after=after,
792 pygments_formatter=formatter,
800 pygments_formatter=formatter,
793 )
801 )
794 return list(stack_data.FrameInfo.stack_data(etb, options=options))[tb_offset:]
802 return list(stack_data.FrameInfo.stack_data(etb, options=options))[tb_offset:]
795
803
796 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
804 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
797 number_of_lines_of_context=5):
805 number_of_lines_of_context=5):
798 """Return a nice text document describing the traceback."""
806 """Return a nice text document describing the traceback."""
799
807
800 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
808 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
801 tb_offset)
809 tb_offset)
802
810
803 colors = self.Colors # just a shorthand + quicker name lookup
811 colors = self.Colors # just a shorthand + quicker name lookup
804 colorsnormal = colors.Normal # used a lot
812 colorsnormal = colors.Normal # used a lot
805 head = '%s%s%s' % (colors.topline, '-' * min(75, get_terminal_size()[0]), colorsnormal)
813 head = '%s%s%s' % (colors.topline, '-' * min(75, get_terminal_size()[0]), colorsnormal)
806 structured_traceback_parts = [head]
814 structured_traceback_parts = [head]
807 chained_exceptions_tb_offset = 0
815 chained_exceptions_tb_offset = 0
808 lines_of_context = 3
816 lines_of_context = 3
809 formatted_exceptions = formatted_exception
817 formatted_exceptions = formatted_exception
810 exception = self.get_parts_of_chained_exception(evalue)
818 exception = self.get_parts_of_chained_exception(evalue)
811 if exception:
819 if exception:
812 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
820 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
813 etype, evalue, etb = exception
821 etype, evalue, etb = exception
814 else:
822 else:
815 evalue = None
823 evalue = None
816 chained_exc_ids = set()
824 chained_exc_ids = set()
817 while evalue:
825 while evalue:
818 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
826 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
819 chained_exceptions_tb_offset)
827 chained_exceptions_tb_offset)
820 exception = self.get_parts_of_chained_exception(evalue)
828 exception = self.get_parts_of_chained_exception(evalue)
821
829
822 if exception and not id(exception[1]) in chained_exc_ids:
830 if exception and not id(exception[1]) in chained_exc_ids:
823 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
831 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
824 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
832 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
825 etype, evalue, etb = exception
833 etype, evalue, etb = exception
826 else:
834 else:
827 evalue = None
835 evalue = None
828
836
829 # we want to see exceptions in a reversed order:
837 # we want to see exceptions in a reversed order:
830 # the first exception should be on top
838 # the first exception should be on top
831 for formatted_exception in reversed(formatted_exceptions):
839 for formatted_exception in reversed(formatted_exceptions):
832 structured_traceback_parts += formatted_exception
840 structured_traceback_parts += formatted_exception
833
841
834 return structured_traceback_parts
842 return structured_traceback_parts
835
843
836 def debugger(self, force=False):
844 def debugger(self, force=False):
837 """Call up the pdb debugger if desired, always clean up the tb
845 """Call up the pdb debugger if desired, always clean up the tb
838 reference.
846 reference.
839
847
840 Keywords:
848 Keywords:
841
849
842 - force(False): by default, this routine checks the instance call_pdb
850 - force(False): by default, this routine checks the instance call_pdb
843 flag and does not actually invoke the debugger if the flag is false.
851 flag and does not actually invoke the debugger if the flag is false.
844 The 'force' option forces the debugger to activate even if the flag
852 The 'force' option forces the debugger to activate even if the flag
845 is false.
853 is false.
846
854
847 If the call_pdb flag is set, the pdb interactive debugger is
855 If the call_pdb flag is set, the pdb interactive debugger is
848 invoked. In all cases, the self.tb reference to the current traceback
856 invoked. In all cases, the self.tb reference to the current traceback
849 is deleted to prevent lingering references which hamper memory
857 is deleted to prevent lingering references which hamper memory
850 management.
858 management.
851
859
852 Note that each call to pdb() does an 'import readline', so if your app
860 Note that each call to pdb() does an 'import readline', so if your app
853 requires a special setup for the readline completers, you'll have to
861 requires a special setup for the readline completers, you'll have to
854 fix that by hand after invoking the exception handler."""
862 fix that by hand after invoking the exception handler."""
855
863
856 if force or self.call_pdb:
864 if force or self.call_pdb:
857 if self.pdb is None:
865 if self.pdb is None:
858 self.pdb = self.debugger_cls()
866 self.pdb = self.debugger_cls()
859 # the system displayhook may have changed, restore the original
867 # the system displayhook may have changed, restore the original
860 # for pdb
868 # for pdb
861 display_trap = DisplayTrap(hook=sys.__displayhook__)
869 display_trap = DisplayTrap(hook=sys.__displayhook__)
862 with display_trap:
870 with display_trap:
863 self.pdb.reset()
871 self.pdb.reset()
864 # Find the right frame so we don't pop up inside ipython itself
872 # Find the right frame so we don't pop up inside ipython itself
865 if hasattr(self, 'tb') and self.tb is not None:
873 if hasattr(self, 'tb') and self.tb is not None:
866 etb = self.tb
874 etb = self.tb
867 else:
875 else:
868 etb = self.tb = sys.last_traceback
876 etb = self.tb = sys.last_traceback
869 while self.tb is not None and self.tb.tb_next is not None:
877 while self.tb is not None and self.tb.tb_next is not None:
870 self.tb = self.tb.tb_next
878 self.tb = self.tb.tb_next
871 if etb and etb.tb_next:
879 if etb and etb.tb_next:
872 etb = etb.tb_next
880 etb = etb.tb_next
873 self.pdb.botframe = etb.tb_frame
881 self.pdb.botframe = etb.tb_frame
874 self.pdb.interaction(None, etb)
882 self.pdb.interaction(None, etb)
875
883
876 if hasattr(self, 'tb'):
884 if hasattr(self, 'tb'):
877 del self.tb
885 del self.tb
878
886
879 def handler(self, info=None):
887 def handler(self, info=None):
880 (etype, evalue, etb) = info or sys.exc_info()
888 (etype, evalue, etb) = info or sys.exc_info()
881 self.tb = etb
889 self.tb = etb
882 ostream = self.ostream
890 ostream = self.ostream
883 ostream.flush()
891 ostream.flush()
884 ostream.write(self.text(etype, evalue, etb))
892 ostream.write(self.text(etype, evalue, etb))
885 ostream.write('\n')
893 ostream.write('\n')
886 ostream.flush()
894 ostream.flush()
887
895
888 # Changed so an instance can just be called as VerboseTB_inst() and print
896 # Changed so an instance can just be called as VerboseTB_inst() and print
889 # out the right info on its own.
897 # out the right info on its own.
890 def __call__(self, etype=None, evalue=None, etb=None):
898 def __call__(self, etype=None, evalue=None, etb=None):
891 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
899 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
892 if etb is None:
900 if etb is None:
893 self.handler()
901 self.handler()
894 else:
902 else:
895 self.handler((etype, evalue, etb))
903 self.handler((etype, evalue, etb))
896 try:
904 try:
897 self.debugger()
905 self.debugger()
898 except KeyboardInterrupt:
906 except KeyboardInterrupt:
899 print("\nKeyboardInterrupt")
907 print("\nKeyboardInterrupt")
900
908
901
909
902 #----------------------------------------------------------------------------
910 #----------------------------------------------------------------------------
903 class FormattedTB(VerboseTB, ListTB):
911 class FormattedTB(VerboseTB, ListTB):
904 """Subclass ListTB but allow calling with a traceback.
912 """Subclass ListTB but allow calling with a traceback.
905
913
906 It can thus be used as a sys.excepthook for Python > 2.1.
914 It can thus be used as a sys.excepthook for Python > 2.1.
907
915
908 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
916 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
909
917
910 Allows a tb_offset to be specified. This is useful for situations where
918 Allows a tb_offset to be specified. This is useful for situations where
911 one needs to remove a number of topmost frames from the traceback (such as
919 one needs to remove a number of topmost frames from the traceback (such as
912 occurs with python programs that themselves execute other python code,
920 occurs with python programs that themselves execute other python code,
913 like Python shells). """
921 like Python shells). """
914
922
915 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
923 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
916 ostream=None,
924 ostream=None,
917 tb_offset=0, long_header=False, include_vars=False,
925 tb_offset=0, long_header=False, include_vars=False,
918 check_cache=None, debugger_cls=None,
926 check_cache=None, debugger_cls=None,
919 parent=None, config=None):
927 parent=None, config=None):
920
928
921 # NEVER change the order of this list. Put new modes at the end:
929 # NEVER change the order of this list. Put new modes at the end:
922 self.valid_modes = ['Plain', 'Context', 'Verbose', 'Minimal']
930 self.valid_modes = ['Plain', 'Context', 'Verbose', 'Minimal']
923 self.verbose_modes = self.valid_modes[1:3]
931 self.verbose_modes = self.valid_modes[1:3]
924
932
925 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
933 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
926 ostream=ostream, tb_offset=tb_offset,
934 ostream=ostream, tb_offset=tb_offset,
927 long_header=long_header, include_vars=include_vars,
935 long_header=long_header, include_vars=include_vars,
928 check_cache=check_cache, debugger_cls=debugger_cls,
936 check_cache=check_cache, debugger_cls=debugger_cls,
929 parent=parent, config=config)
937 parent=parent, config=config)
930
938
931 # Different types of tracebacks are joined with different separators to
939 # Different types of tracebacks are joined with different separators to
932 # form a single string. They are taken from this dict
940 # form a single string. They are taken from this dict
933 self._join_chars = dict(Plain='', Context='\n', Verbose='\n',
941 self._join_chars = dict(Plain='', Context='\n', Verbose='\n',
934 Minimal='')
942 Minimal='')
935 # set_mode also sets the tb_join_char attribute
943 # set_mode also sets the tb_join_char attribute
936 self.set_mode(mode)
944 self.set_mode(mode)
937
945
938 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
946 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
939 tb_offset = self.tb_offset if tb_offset is None else tb_offset
947 tb_offset = self.tb_offset if tb_offset is None else tb_offset
940 mode = self.mode
948 mode = self.mode
941 if mode in self.verbose_modes:
949 if mode in self.verbose_modes:
942 # Verbose modes need a full traceback
950 # Verbose modes need a full traceback
943 return VerboseTB.structured_traceback(
951 return VerboseTB.structured_traceback(
944 self, etype, value, tb, tb_offset, number_of_lines_of_context
952 self, etype, value, tb, tb_offset, number_of_lines_of_context
945 )
953 )
946 elif mode == 'Minimal':
954 elif mode == 'Minimal':
947 return ListTB.get_exception_only(self, etype, value)
955 return ListTB.get_exception_only(self, etype, value)
948 else:
956 else:
949 # We must check the source cache because otherwise we can print
957 # We must check the source cache because otherwise we can print
950 # out-of-date source code.
958 # out-of-date source code.
951 self.check_cache()
959 self.check_cache()
952 # Now we can extract and format the exception
960 # Now we can extract and format the exception
953 return ListTB.structured_traceback(
961 return ListTB.structured_traceback(
954 self, etype, value, tb, tb_offset, number_of_lines_of_context
962 self, etype, value, tb, tb_offset, number_of_lines_of_context
955 )
963 )
956
964
957 def stb2text(self, stb):
965 def stb2text(self, stb):
958 """Convert a structured traceback (a list) to a string."""
966 """Convert a structured traceback (a list) to a string."""
959 return self.tb_join_char.join(stb)
967 return self.tb_join_char.join(stb)
960
968
961
969
962 def set_mode(self, mode=None):
970 def set_mode(self, mode=None):
963 """Switch to the desired mode.
971 """Switch to the desired mode.
964
972
965 If mode is not specified, cycles through the available modes."""
973 If mode is not specified, cycles through the available modes."""
966
974
967 if not mode:
975 if not mode:
968 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
976 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
969 len(self.valid_modes)
977 len(self.valid_modes)
970 self.mode = self.valid_modes[new_idx]
978 self.mode = self.valid_modes[new_idx]
971 elif mode not in self.valid_modes:
979 elif mode not in self.valid_modes:
972 raise ValueError('Unrecognized mode in FormattedTB: <' + mode + '>\n'
980 raise ValueError('Unrecognized mode in FormattedTB: <' + mode + '>\n'
973 'Valid modes: ' + str(self.valid_modes))
981 'Valid modes: ' + str(self.valid_modes))
974 else:
982 else:
975 self.mode = mode
983 self.mode = mode
976 # include variable details only in 'Verbose' mode
984 # include variable details only in 'Verbose' mode
977 self.include_vars = (self.mode == self.valid_modes[2])
985 self.include_vars = (self.mode == self.valid_modes[2])
978 # Set the join character for generating text tracebacks
986 # Set the join character for generating text tracebacks
979 self.tb_join_char = self._join_chars[self.mode]
987 self.tb_join_char = self._join_chars[self.mode]
980
988
981 # some convenient shortcuts
989 # some convenient shortcuts
982 def plain(self):
990 def plain(self):
983 self.set_mode(self.valid_modes[0])
991 self.set_mode(self.valid_modes[0])
984
992
985 def context(self):
993 def context(self):
986 self.set_mode(self.valid_modes[1])
994 self.set_mode(self.valid_modes[1])
987
995
988 def verbose(self):
996 def verbose(self):
989 self.set_mode(self.valid_modes[2])
997 self.set_mode(self.valid_modes[2])
990
998
991 def minimal(self):
999 def minimal(self):
992 self.set_mode(self.valid_modes[3])
1000 self.set_mode(self.valid_modes[3])
993
1001
994
1002
995 #----------------------------------------------------------------------------
1003 #----------------------------------------------------------------------------
996 class AutoFormattedTB(FormattedTB):
1004 class AutoFormattedTB(FormattedTB):
997 """A traceback printer which can be called on the fly.
1005 """A traceback printer which can be called on the fly.
998
1006
999 It will find out about exceptions by itself.
1007 It will find out about exceptions by itself.
1000
1008
1001 A brief example::
1009 A brief example::
1002
1010
1003 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1011 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1004 try:
1012 try:
1005 ...
1013 ...
1006 except:
1014 except:
1007 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1015 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1008 """
1016 """
1009
1017
1010 def __call__(self, etype=None, evalue=None, etb=None,
1018 def __call__(self, etype=None, evalue=None, etb=None,
1011 out=None, tb_offset=None):
1019 out=None, tb_offset=None):
1012 """Print out a formatted exception traceback.
1020 """Print out a formatted exception traceback.
1013
1021
1014 Optional arguments:
1022 Optional arguments:
1015 - out: an open file-like object to direct output to.
1023 - out: an open file-like object to direct output to.
1016
1024
1017 - tb_offset: the number of frames to skip over in the stack, on a
1025 - tb_offset: the number of frames to skip over in the stack, on a
1018 per-call basis (this overrides temporarily the instance's tb_offset
1026 per-call basis (this overrides temporarily the instance's tb_offset
1019 given at initialization time."""
1027 given at initialization time."""
1020
1028
1021 if out is None:
1029 if out is None:
1022 out = self.ostream
1030 out = self.ostream
1023 out.flush()
1031 out.flush()
1024 out.write(self.text(etype, evalue, etb, tb_offset))
1032 out.write(self.text(etype, evalue, etb, tb_offset))
1025 out.write('\n')
1033 out.write('\n')
1026 out.flush()
1034 out.flush()
1027 # FIXME: we should remove the auto pdb behavior from here and leave
1035 # FIXME: we should remove the auto pdb behavior from here and leave
1028 # that to the clients.
1036 # that to the clients.
1029 try:
1037 try:
1030 self.debugger()
1038 self.debugger()
1031 except KeyboardInterrupt:
1039 except KeyboardInterrupt:
1032 print("\nKeyboardInterrupt")
1040 print("\nKeyboardInterrupt")
1033
1041
1034 def structured_traceback(self, etype=None, value=None, tb=None,
1042 def structured_traceback(self, etype=None, value=None, tb=None,
1035 tb_offset=None, number_of_lines_of_context=5):
1043 tb_offset=None, number_of_lines_of_context=5):
1036 if etype is None:
1044 if etype is None:
1037 etype, value, tb = sys.exc_info()
1045 etype, value, tb = sys.exc_info()
1038 if isinstance(tb, tuple):
1046 if isinstance(tb, tuple):
1039 # tb is a tuple if this is a chained exception.
1047 # tb is a tuple if this is a chained exception.
1040 self.tb = tb[0]
1048 self.tb = tb[0]
1041 else:
1049 else:
1042 self.tb = tb
1050 self.tb = tb
1043 return FormattedTB.structured_traceback(
1051 return FormattedTB.structured_traceback(
1044 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1052 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1045
1053
1046
1054
1047 #---------------------------------------------------------------------------
1055 #---------------------------------------------------------------------------
1048
1056
1049 # A simple class to preserve Nathan's original functionality.
1057 # A simple class to preserve Nathan's original functionality.
1050 class ColorTB(FormattedTB):
1058 class ColorTB(FormattedTB):
1051 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1059 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1052
1060
1053 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1061 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1054 FormattedTB.__init__(self, color_scheme=color_scheme,
1062 FormattedTB.__init__(self, color_scheme=color_scheme,
1055 call_pdb=call_pdb, **kwargs)
1063 call_pdb=call_pdb, **kwargs)
1056
1064
1057
1065
1058 class SyntaxTB(ListTB):
1066 class SyntaxTB(ListTB):
1059 """Extension which holds some state: the last exception value"""
1067 """Extension which holds some state: the last exception value"""
1060
1068
1061 def __init__(self, color_scheme='NoColor', parent=None, config=None):
1069 def __init__(self, color_scheme='NoColor', parent=None, config=None):
1062 ListTB.__init__(self, color_scheme, parent=parent, config=config)
1070 ListTB.__init__(self, color_scheme, parent=parent, config=config)
1063 self.last_syntax_error = None
1071 self.last_syntax_error = None
1064
1072
1065 def __call__(self, etype, value, elist):
1073 def __call__(self, etype, value, elist):
1066 self.last_syntax_error = value
1074 self.last_syntax_error = value
1067
1075
1068 ListTB.__call__(self, etype, value, elist)
1076 ListTB.__call__(self, etype, value, elist)
1069
1077
1070 def structured_traceback(self, etype, value, elist, tb_offset=None,
1078 def structured_traceback(self, etype, value, elist, tb_offset=None,
1071 context=5):
1079 context=5):
1072 # If the source file has been edited, the line in the syntax error can
1080 # If the source file has been edited, the line in the syntax error can
1073 # be wrong (retrieved from an outdated cache). This replaces it with
1081 # be wrong (retrieved from an outdated cache). This replaces it with
1074 # the current value.
1082 # the current value.
1075 if isinstance(value, SyntaxError) \
1083 if isinstance(value, SyntaxError) \
1076 and isinstance(value.filename, str) \
1084 and isinstance(value.filename, str) \
1077 and isinstance(value.lineno, int):
1085 and isinstance(value.lineno, int):
1078 linecache.checkcache(value.filename)
1086 linecache.checkcache(value.filename)
1079 newtext = linecache.getline(value.filename, value.lineno)
1087 newtext = linecache.getline(value.filename, value.lineno)
1080 if newtext:
1088 if newtext:
1081 value.text = newtext
1089 value.text = newtext
1082 self.last_syntax_error = value
1090 self.last_syntax_error = value
1083 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1091 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1084 tb_offset=tb_offset, context=context)
1092 tb_offset=tb_offset, context=context)
1085
1093
1086 def clear_err_state(self):
1094 def clear_err_state(self):
1087 """Return the current error state and clear it"""
1095 """Return the current error state and clear it"""
1088 e = self.last_syntax_error
1096 e = self.last_syntax_error
1089 self.last_syntax_error = None
1097 self.last_syntax_error = None
1090 return e
1098 return e
1091
1099
1092 def stb2text(self, stb):
1100 def stb2text(self, stb):
1093 """Convert a structured traceback (a list) to a string."""
1101 """Convert a structured traceback (a list) to a string."""
1094 return ''.join(stb)
1102 return ''.join(stb)
1095
1103
1096
1104
1097 # some internal-use functions
1105 # some internal-use functions
1098 def text_repr(value):
1106 def text_repr(value):
1099 """Hopefully pretty robust repr equivalent."""
1107 """Hopefully pretty robust repr equivalent."""
1100 # this is pretty horrible but should always return *something*
1108 # this is pretty horrible but should always return *something*
1101 try:
1109 try:
1102 return pydoc.text.repr(value)
1110 return pydoc.text.repr(value)
1103 except KeyboardInterrupt:
1111 except KeyboardInterrupt:
1104 raise
1112 raise
1105 except:
1113 except:
1106 try:
1114 try:
1107 return repr(value)
1115 return repr(value)
1108 except KeyboardInterrupt:
1116 except KeyboardInterrupt:
1109 raise
1117 raise
1110 except:
1118 except:
1111 try:
1119 try:
1112 # all still in an except block so we catch
1120 # all still in an except block so we catch
1113 # getattr raising
1121 # getattr raising
1114 name = getattr(value, '__name__', None)
1122 name = getattr(value, '__name__', None)
1115 if name:
1123 if name:
1116 # ick, recursion
1124 # ick, recursion
1117 return text_repr(name)
1125 return text_repr(name)
1118 klass = getattr(value, '__class__', None)
1126 klass = getattr(value, '__class__', None)
1119 if klass:
1127 if klass:
1120 return '%s instance' % text_repr(klass)
1128 return '%s instance' % text_repr(klass)
1121 except KeyboardInterrupt:
1129 except KeyboardInterrupt:
1122 raise
1130 raise
1123 except:
1131 except:
1124 return 'UNRECOVERABLE REPR FAILURE'
1132 return 'UNRECOVERABLE REPR FAILURE'
1125
1133
1126
1134
1127 def eqrepr(value, repr=text_repr):
1135 def eqrepr(value, repr=text_repr):
1128 return '=%s' % repr(value)
1136 return '=%s' % repr(value)
1129
1137
1130
1138
1131 def nullrepr(value, repr=text_repr):
1139 def nullrepr(value, repr=text_repr):
1132 return ''
1140 return ''
General Comments 0
You need to be logged in to leave comments. Login now