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