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