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