##// END OF EJS Templates
fix small bug in traceback building
fperez -
Show More
@@ -1,76 +1,76 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Release data for the IPython project.
2 """Release data for the IPython project.
3
3
4 $Id: Release.py 988 2006-01-02 21:21:47Z fperez $"""
4 $Id: Release.py 992 2006-01-04 18:35:40Z fperez $"""
5
5
6 #*****************************************************************************
6 #*****************************************************************************
7 # Copyright (C) 2001-2005 Fernando Perez <fperez@colorado.edu>
7 # Copyright (C) 2001-2005 Fernando Perez <fperez@colorado.edu>
8 #
8 #
9 # Copyright (c) 2001 Janko Hauser <jhauser@zscout.de> and Nathaniel Gray
9 # Copyright (c) 2001 Janko Hauser <jhauser@zscout.de> and Nathaniel Gray
10 # <n8gray@caltech.edu>
10 # <n8gray@caltech.edu>
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #*****************************************************************************
14 #*****************************************************************************
15
15
16 # Name of the package for release purposes. This is the name which labels
16 # Name of the package for release purposes. This is the name which labels
17 # the tarballs and RPMs made by distutils, so it's best to lowercase it.
17 # the tarballs and RPMs made by distutils, so it's best to lowercase it.
18 name = 'ipython'
18 name = 'ipython'
19
19
20 # For versions with substrings (like 0.6.16.svn), use an extra . to separate
20 # For versions with substrings (like 0.6.16.svn), use an extra . to separate
21 # the new substring. We have to avoid using either dashes or underscores,
21 # the new substring. We have to avoid using either dashes or underscores,
22 # because bdist_rpm does not accept dashes (an RPM) convention, and
22 # because bdist_rpm does not accept dashes (an RPM) convention, and
23 # bdist_deb does not accept underscores (a Debian convention).
23 # bdist_deb does not accept underscores (a Debian convention).
24
24
25 version = '0.7.0.rc7'
25 version = '0.7.0.rc8'
26
26
27 revision = '$Revision: 988 $'
27 revision = '$Revision: 992 $'
28
28
29 description = "An enhanced interactive Python shell."
29 description = "An enhanced interactive Python shell."
30
30
31 long_description = \
31 long_description = \
32 """
32 """
33 IPython provides a replacement for the interactive Python interpreter with
33 IPython provides a replacement for the interactive Python interpreter with
34 extra functionality.
34 extra functionality.
35
35
36 Main features:
36 Main features:
37
37
38 * Comprehensive object introspection.
38 * Comprehensive object introspection.
39
39
40 * Input history, persistent across sessions.
40 * Input history, persistent across sessions.
41
41
42 * Caching of output results during a session with automatically generated
42 * Caching of output results during a session with automatically generated
43 references.
43 references.
44
44
45 * Readline based name completion.
45 * Readline based name completion.
46
46
47 * Extensible system of 'magic' commands for controlling the environment and
47 * Extensible system of 'magic' commands for controlling the environment and
48 performing many tasks related either to IPython or the operating system.
48 performing many tasks related either to IPython or the operating system.
49
49
50 * Configuration system with easy switching between different setups (simpler
50 * Configuration system with easy switching between different setups (simpler
51 than changing $PYTHONSTARTUP environment variables every time).
51 than changing $PYTHONSTARTUP environment variables every time).
52
52
53 * Session logging and reloading.
53 * Session logging and reloading.
54
54
55 * Extensible syntax processing for special purpose situations.
55 * Extensible syntax processing for special purpose situations.
56
56
57 * Access to the system shell with user-extensible alias system.
57 * Access to the system shell with user-extensible alias system.
58
58
59 * Easily embeddable in other Python programs.
59 * Easily embeddable in other Python programs.
60
60
61 * Integrated access to the pdb debugger and the Python profiler. """
61 * Integrated access to the pdb debugger and the Python profiler. """
62
62
63 license = 'BSD'
63 license = 'BSD'
64
64
65 authors = {'Fernando' : ('Fernando Perez','fperez@colorado.edu'),
65 authors = {'Fernando' : ('Fernando Perez','fperez@colorado.edu'),
66 'Janko' : ('Janko Hauser','jhauser@zscout.de'),
66 'Janko' : ('Janko Hauser','jhauser@zscout.de'),
67 'Nathan' : ('Nathaniel Gray','n8gray@caltech.edu')
67 'Nathan' : ('Nathaniel Gray','n8gray@caltech.edu')
68 }
68 }
69
69
70 url = 'http://ipython.scipy.org'
70 url = 'http://ipython.scipy.org'
71
71
72 download_url = 'http://ipython.scipy.org/dist'
72 download_url = 'http://ipython.scipy.org/dist'
73
73
74 platforms = ['Linux','Mac OSX','Windows XP/2000/NT','Windows 95/98/ME']
74 platforms = ['Linux','Mac OSX','Windows XP/2000/NT','Windows 95/98/ME']
75
75
76 keywords = ['Interactive','Interpreter','Shell']
76 keywords = ['Interactive','Interpreter','Shell']
@@ -1,855 +1,858 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 ultraTB.py -- Spice up your tracebacks!
3 ultraTB.py -- Spice up your tracebacks!
4
4
5 * ColorTB
5 * ColorTB
6 I've always found it a bit hard to visually parse tracebacks in Python. The
6 I've always found it a bit hard to visually parse tracebacks in Python. The
7 ColorTB class is a solution to that problem. It colors the different parts of a
7 ColorTB class is a solution to that problem. It colors the different parts of a
8 traceback in a manner similar to what you would expect from a syntax-highlighting
8 traceback in a manner similar to what you would expect from a syntax-highlighting
9 text editor.
9 text editor.
10
10
11 Installation instructions for ColorTB:
11 Installation instructions for ColorTB:
12 import sys,ultraTB
12 import sys,ultraTB
13 sys.excepthook = ultraTB.ColorTB()
13 sys.excepthook = ultraTB.ColorTB()
14
14
15 * VerboseTB
15 * VerboseTB
16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
17 of useful info when a traceback occurs. Ping originally had it spit out HTML
17 of useful info when a traceback occurs. Ping originally had it spit out HTML
18 and intended it for CGI programmers, but why should they have all the fun? I
18 and intended it for CGI programmers, but why should they have all the fun? I
19 altered it to spit out colored text to the terminal. It's a bit overwhelming,
19 altered it to spit out colored text to the terminal. It's a bit overwhelming,
20 but kind of neat, and maybe useful for long-running programs that you believe
20 but kind of neat, and maybe useful for long-running programs that you believe
21 are bug-free. If a crash *does* occur in that type of program you want details.
21 are bug-free. If a crash *does* occur in that type of program you want details.
22 Give it a shot--you'll love it or you'll hate it.
22 Give it a shot--you'll love it or you'll hate it.
23
23
24 Note:
24 Note:
25
25
26 The Verbose mode prints the variables currently visible where the exception
26 The Verbose mode prints the variables currently visible where the exception
27 happened (shortening their strings if too long). This can potentially be
27 happened (shortening their strings if too long). This can potentially be
28 very slow, if you happen to have a huge data structure whose string
28 very slow, if you happen to have a huge data structure whose string
29 representation is complex to compute. Your computer may appear to freeze for
29 representation is complex to compute. Your computer may appear to freeze for
30 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
30 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
31 with Ctrl-C (maybe hitting it more than once).
31 with Ctrl-C (maybe hitting it more than once).
32
32
33 If you encounter this kind of situation often, you may want to use the
33 If you encounter this kind of situation often, you may want to use the
34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
35 variables (but otherwise includes the information and context given by
35 variables (but otherwise includes the information and context given by
36 Verbose).
36 Verbose).
37
37
38
38
39 Installation instructions for ColorTB:
39 Installation instructions for ColorTB:
40 import sys,ultraTB
40 import sys,ultraTB
41 sys.excepthook = ultraTB.VerboseTB()
41 sys.excepthook = ultraTB.VerboseTB()
42
42
43 Note: Much of the code in this module was lifted verbatim from the standard
43 Note: Much of the code in this module was lifted verbatim from the standard
44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
45
45
46 * Color schemes
46 * Color schemes
47 The colors are defined in the class TBTools through the use of the
47 The colors are defined in the class TBTools through the use of the
48 ColorSchemeTable class. Currently the following exist:
48 ColorSchemeTable class. Currently the following exist:
49
49
50 - NoColor: allows all of this module to be used in any terminal (the color
50 - NoColor: allows all of this module to be used in any terminal (the color
51 escapes are just dummy blank strings).
51 escapes are just dummy blank strings).
52
52
53 - Linux: is meant to look good in a terminal like the Linux console (black
53 - Linux: is meant to look good in a terminal like the Linux console (black
54 or very dark background).
54 or very dark background).
55
55
56 - LightBG: similar to Linux but swaps dark/light colors to be more readable
56 - LightBG: similar to Linux but swaps dark/light colors to be more readable
57 in light background terminals.
57 in light background terminals.
58
58
59 You can implement other color schemes easily, the syntax is fairly
59 You can implement other color schemes easily, the syntax is fairly
60 self-explanatory. Please send back new schemes you develop to the author for
60 self-explanatory. Please send back new schemes you develop to the author for
61 possible inclusion in future releases.
61 possible inclusion in future releases.
62
62
63 $Id: ultraTB.py 988 2006-01-02 21:21:47Z fperez $"""
63 $Id: ultraTB.py 992 2006-01-04 18:35:40Z fperez $"""
64
64
65 #*****************************************************************************
65 #*****************************************************************************
66 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
66 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
67 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
67 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
68 #
68 #
69 # Distributed under the terms of the BSD License. The full license is in
69 # Distributed under the terms of the BSD License. The full license is in
70 # the file COPYING, distributed as part of this software.
70 # the file COPYING, distributed as part of this software.
71 #*****************************************************************************
71 #*****************************************************************************
72
72
73 from IPython import Release
73 from IPython import Release
74 __author__ = '%s <%s>\n%s <%s>' % (Release.authors['Nathan']+
74 __author__ = '%s <%s>\n%s <%s>' % (Release.authors['Nathan']+
75 Release.authors['Fernando'])
75 Release.authors['Fernando'])
76 __license__ = Release.license
76 __license__ = Release.license
77
77
78 # Required modules
78 # Required modules
79 import inspect
79 import inspect
80 import keyword
80 import keyword
81 import linecache
81 import linecache
82 import os
82 import os
83 import pydoc
83 import pydoc
84 import string
84 import string
85 import sys
85 import sys
86 import time
86 import time
87 import tokenize
87 import tokenize
88 import traceback
88 import traceback
89 import types
89 import types
90
90
91 # IPython's own modules
91 # IPython's own modules
92 # Modified pdb which doesn't damage IPython's readline handling
92 # Modified pdb which doesn't damage IPython's readline handling
93 from IPython import Debugger
93 from IPython import Debugger
94 from IPython.Struct import Struct
94 from IPython.Struct import Struct
95 from IPython.excolors import ExceptionColors
95 from IPython.excolors import ExceptionColors
96 from IPython.genutils import Term,uniq_stable,error,info
96 from IPython.genutils import Term,uniq_stable,error,info
97
97
98 # Globals
98 # Globals
99 # amount of space to put line numbers before verbose tracebacks
99 # amount of space to put line numbers before verbose tracebacks
100 INDENT_SIZE = 8
100 INDENT_SIZE = 8
101
101
102 #---------------------------------------------------------------------------
102 #---------------------------------------------------------------------------
103 # Code begins
103 # Code begins
104
104
105 # Utility functions
105 # Utility functions
106 def inspect_error():
106 def inspect_error():
107 """Print a message about internal inspect errors.
107 """Print a message about internal inspect errors.
108
108
109 These are unfortunately quite common."""
109 These are unfortunately quite common."""
110
110
111 error('Internal Python error in the inspect module.\n'
111 error('Internal Python error in the inspect module.\n'
112 'Below is the traceback from this internal error.\n')
112 'Below is the traceback from this internal error.\n')
113
113
114 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
114 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
115 import linecache
115 import linecache
116 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
116 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
117
117
118 records = inspect.getinnerframes(etb, context)
118 records = inspect.getinnerframes(etb, context)
119
119
120 # If the error is at the console, don't build any context, since it would
120 # If the error is at the console, don't build any context, since it would
121 # otherwise produce 5 blank lines printed out (there is no file at the
121 # otherwise produce 5 blank lines printed out (there is no file at the
122 # console)
122 # console)
123 rec_check = records[tb_offset:]
123 rec_check = records[tb_offset:]
124 rname = rec_check[0][1]
124 try:
125 if rname == '<ipython console>' or rname.endswith('<string>'):
125 rname = rec_check[0][1]
126 return rec_check
126 if rname == '<ipython console>' or rname.endswith('<string>'):
127 return rec_check
128 except IndexError:
129 pass
127
130
128 aux = traceback.extract_tb(etb)
131 aux = traceback.extract_tb(etb)
129 assert len(records) == len(aux)
132 assert len(records) == len(aux)
130 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
133 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
131 maybeStart = lnum-1 - context//2
134 maybeStart = lnum-1 - context//2
132 start = max(maybeStart, 0)
135 start = max(maybeStart, 0)
133 end = start + context
136 end = start + context
134 lines = linecache.getlines(file)[start:end]
137 lines = linecache.getlines(file)[start:end]
135 # pad with empty lines if necessary
138 # pad with empty lines if necessary
136 if maybeStart < 0:
139 if maybeStart < 0:
137 lines = (['\n'] * -maybeStart) + lines
140 lines = (['\n'] * -maybeStart) + lines
138 if len(lines) < context:
141 if len(lines) < context:
139 lines += ['\n'] * (context - len(lines))
142 lines += ['\n'] * (context - len(lines))
140 assert len(lines) == context
143 assert len(lines) == context
141 buf = list(records[i])
144 buf = list(records[i])
142 buf[LNUM_POS] = lnum
145 buf[LNUM_POS] = lnum
143 buf[INDEX_POS] = lnum - 1 - start
146 buf[INDEX_POS] = lnum - 1 - start
144 buf[LINES_POS] = lines
147 buf[LINES_POS] = lines
145 records[i] = tuple(buf)
148 records[i] = tuple(buf)
146 return records[tb_offset:]
149 return records[tb_offset:]
147
150
148 # Helper function -- largely belongs to VerboseTB, but we need the same
151 # Helper function -- largely belongs to VerboseTB, but we need the same
149 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
152 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
150 # can be recognized properly by ipython.el's py-traceback-line-re
153 # can be recognized properly by ipython.el's py-traceback-line-re
151 # (SyntaxErrors have to be treated specially because they have no traceback)
154 # (SyntaxErrors have to be treated specially because they have no traceback)
152 def _formatTracebackLines(lnum, index, lines, Colors, lvals=None):
155 def _formatTracebackLines(lnum, index, lines, Colors, lvals=None):
153 numbers_width = INDENT_SIZE - 1
156 numbers_width = INDENT_SIZE - 1
154 res = []
157 res = []
155 i = lnum - index
158 i = lnum - index
156 for line in lines:
159 for line in lines:
157 if i == lnum:
160 if i == lnum:
158 # This is the line with the error
161 # This is the line with the error
159 pad = numbers_width - len(str(i))
162 pad = numbers_width - len(str(i))
160 if pad >= 3:
163 if pad >= 3:
161 marker = '-'*(pad-3) + '-> '
164 marker = '-'*(pad-3) + '-> '
162 elif pad == 2:
165 elif pad == 2:
163 marker = '> '
166 marker = '> '
164 elif pad == 1:
167 elif pad == 1:
165 marker = '>'
168 marker = '>'
166 else:
169 else:
167 marker = ''
170 marker = ''
168 num = marker + str(i)
171 num = marker + str(i)
169 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
172 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
170 Colors.line, line, Colors.Normal)
173 Colors.line, line, Colors.Normal)
171 else:
174 else:
172 num = '%*s' % (numbers_width,i)
175 num = '%*s' % (numbers_width,i)
173 line = '%s%s%s %s' %(Colors.lineno, num,
176 line = '%s%s%s %s' %(Colors.lineno, num,
174 Colors.Normal, line)
177 Colors.Normal, line)
175
178
176 res.append(line)
179 res.append(line)
177 if lvals and i == lnum:
180 if lvals and i == lnum:
178 res.append(lvals + '\n')
181 res.append(lvals + '\n')
179 i = i + 1
182 i = i + 1
180 return res
183 return res
181
184
182 #---------------------------------------------------------------------------
185 #---------------------------------------------------------------------------
183 # Module classes
186 # Module classes
184 class TBTools:
187 class TBTools:
185 """Basic tools used by all traceback printer classes."""
188 """Basic tools used by all traceback printer classes."""
186
189
187 def __init__(self,color_scheme = 'NoColor',call_pdb=False):
190 def __init__(self,color_scheme = 'NoColor',call_pdb=False):
188 # Whether to call the interactive pdb debugger after printing
191 # Whether to call the interactive pdb debugger after printing
189 # tracebacks or not
192 # tracebacks or not
190 self.call_pdb = call_pdb
193 self.call_pdb = call_pdb
191
194
192 # Create color table
195 # Create color table
193 self.color_scheme_table = ExceptionColors
196 self.color_scheme_table = ExceptionColors
194
197
195 self.set_colors(color_scheme)
198 self.set_colors(color_scheme)
196 self.old_scheme = color_scheme # save initial value for toggles
199 self.old_scheme = color_scheme # save initial value for toggles
197
200
198 if call_pdb:
201 if call_pdb:
199 self.pdb = Debugger.Pdb(self.color_scheme_table.active_scheme_name)
202 self.pdb = Debugger.Pdb(self.color_scheme_table.active_scheme_name)
200 else:
203 else:
201 self.pdb = None
204 self.pdb = None
202
205
203 def set_colors(self,*args,**kw):
206 def set_colors(self,*args,**kw):
204 """Shorthand access to the color table scheme selector method."""
207 """Shorthand access to the color table scheme selector method."""
205
208
206 self.color_scheme_table.set_active_scheme(*args,**kw)
209 self.color_scheme_table.set_active_scheme(*args,**kw)
207 # for convenience, set Colors to the active scheme
210 # for convenience, set Colors to the active scheme
208 self.Colors = self.color_scheme_table.active_colors
211 self.Colors = self.color_scheme_table.active_colors
209
212
210 def color_toggle(self):
213 def color_toggle(self):
211 """Toggle between the currently active color scheme and NoColor."""
214 """Toggle between the currently active color scheme and NoColor."""
212
215
213 if self.color_scheme_table.active_scheme_name == 'NoColor':
216 if self.color_scheme_table.active_scheme_name == 'NoColor':
214 self.color_scheme_table.set_active_scheme(self.old_scheme)
217 self.color_scheme_table.set_active_scheme(self.old_scheme)
215 self.Colors = self.color_scheme_table.active_colors
218 self.Colors = self.color_scheme_table.active_colors
216 else:
219 else:
217 self.old_scheme = self.color_scheme_table.active_scheme_name
220 self.old_scheme = self.color_scheme_table.active_scheme_name
218 self.color_scheme_table.set_active_scheme('NoColor')
221 self.color_scheme_table.set_active_scheme('NoColor')
219 self.Colors = self.color_scheme_table.active_colors
222 self.Colors = self.color_scheme_table.active_colors
220
223
221 #---------------------------------------------------------------------------
224 #---------------------------------------------------------------------------
222 class ListTB(TBTools):
225 class ListTB(TBTools):
223 """Print traceback information from a traceback list, with optional color.
226 """Print traceback information from a traceback list, with optional color.
224
227
225 Calling: requires 3 arguments:
228 Calling: requires 3 arguments:
226 (etype, evalue, elist)
229 (etype, evalue, elist)
227 as would be obtained by:
230 as would be obtained by:
228 etype, evalue, tb = sys.exc_info()
231 etype, evalue, tb = sys.exc_info()
229 if tb:
232 if tb:
230 elist = traceback.extract_tb(tb)
233 elist = traceback.extract_tb(tb)
231 else:
234 else:
232 elist = None
235 elist = None
233
236
234 It can thus be used by programs which need to process the traceback before
237 It can thus be used by programs which need to process the traceback before
235 printing (such as console replacements based on the code module from the
238 printing (such as console replacements based on the code module from the
236 standard library).
239 standard library).
237
240
238 Because they are meant to be called without a full traceback (only a
241 Because they are meant to be called without a full traceback (only a
239 list), instances of this class can't call the interactive pdb debugger."""
242 list), instances of this class can't call the interactive pdb debugger."""
240
243
241 def __init__(self,color_scheme = 'NoColor'):
244 def __init__(self,color_scheme = 'NoColor'):
242 TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0)
245 TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0)
243
246
244 def __call__(self, etype, value, elist):
247 def __call__(self, etype, value, elist):
245 print >> Term.cerr, self.text(etype,value,elist)
248 print >> Term.cerr, self.text(etype,value,elist)
246
249
247 def text(self,etype, value, elist,context=5):
250 def text(self,etype, value, elist,context=5):
248 """Return a color formatted string with the traceback info."""
251 """Return a color formatted string with the traceback info."""
249
252
250 Colors = self.Colors
253 Colors = self.Colors
251 out_string = ['%s%s%s\n' % (Colors.topline,'-'*60,Colors.Normal)]
254 out_string = ['%s%s%s\n' % (Colors.topline,'-'*60,Colors.Normal)]
252 if elist:
255 if elist:
253 out_string.append('Traceback %s(most recent call last)%s:' % \
256 out_string.append('Traceback %s(most recent call last)%s:' % \
254 (Colors.normalEm, Colors.Normal) + '\n')
257 (Colors.normalEm, Colors.Normal) + '\n')
255 out_string.extend(self._format_list(elist))
258 out_string.extend(self._format_list(elist))
256 lines = self._format_exception_only(etype, value)
259 lines = self._format_exception_only(etype, value)
257 for line in lines[:-1]:
260 for line in lines[:-1]:
258 out_string.append(" "+line)
261 out_string.append(" "+line)
259 out_string.append(lines[-1])
262 out_string.append(lines[-1])
260 return ''.join(out_string)
263 return ''.join(out_string)
261
264
262 def _format_list(self, extracted_list):
265 def _format_list(self, extracted_list):
263 """Format a list of traceback entry tuples for printing.
266 """Format a list of traceback entry tuples for printing.
264
267
265 Given a list of tuples as returned by extract_tb() or
268 Given a list of tuples as returned by extract_tb() or
266 extract_stack(), return a list of strings ready for printing.
269 extract_stack(), return a list of strings ready for printing.
267 Each string in the resulting list corresponds to the item with the
270 Each string in the resulting list corresponds to the item with the
268 same index in the argument list. Each string ends in a newline;
271 same index in the argument list. Each string ends in a newline;
269 the strings may contain internal newlines as well, for those items
272 the strings may contain internal newlines as well, for those items
270 whose source text line is not None.
273 whose source text line is not None.
271
274
272 Lifted almost verbatim from traceback.py
275 Lifted almost verbatim from traceback.py
273 """
276 """
274
277
275 Colors = self.Colors
278 Colors = self.Colors
276 list = []
279 list = []
277 for filename, lineno, name, line in extracted_list[:-1]:
280 for filename, lineno, name, line in extracted_list[:-1]:
278 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
281 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
279 (Colors.filename, filename, Colors.Normal,
282 (Colors.filename, filename, Colors.Normal,
280 Colors.lineno, lineno, Colors.Normal,
283 Colors.lineno, lineno, Colors.Normal,
281 Colors.name, name, Colors.Normal)
284 Colors.name, name, Colors.Normal)
282 if line:
285 if line:
283 item = item + ' %s\n' % line.strip()
286 item = item + ' %s\n' % line.strip()
284 list.append(item)
287 list.append(item)
285 # Emphasize the last entry
288 # Emphasize the last entry
286 filename, lineno, name, line = extracted_list[-1]
289 filename, lineno, name, line = extracted_list[-1]
287 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
290 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
288 (Colors.normalEm,
291 (Colors.normalEm,
289 Colors.filenameEm, filename, Colors.normalEm,
292 Colors.filenameEm, filename, Colors.normalEm,
290 Colors.linenoEm, lineno, Colors.normalEm,
293 Colors.linenoEm, lineno, Colors.normalEm,
291 Colors.nameEm, name, Colors.normalEm,
294 Colors.nameEm, name, Colors.normalEm,
292 Colors.Normal)
295 Colors.Normal)
293 if line:
296 if line:
294 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
297 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
295 Colors.Normal)
298 Colors.Normal)
296 list.append(item)
299 list.append(item)
297 return list
300 return list
298
301
299 def _format_exception_only(self, etype, value):
302 def _format_exception_only(self, etype, value):
300 """Format the exception part of a traceback.
303 """Format the exception part of a traceback.
301
304
302 The arguments are the exception type and value such as given by
305 The arguments are the exception type and value such as given by
303 sys.exc_info()[:2]. The return value is a list of strings, each ending
306 sys.exc_info()[:2]. The return value is a list of strings, each ending
304 in a newline. Normally, the list contains a single string; however,
307 in a newline. Normally, the list contains a single string; however,
305 for SyntaxError exceptions, it contains several lines that (when
308 for SyntaxError exceptions, it contains several lines that (when
306 printed) display detailed information about where the syntax error
309 printed) display detailed information about where the syntax error
307 occurred. The message indicating which exception occurred is the
310 occurred. The message indicating which exception occurred is the
308 always last string in the list.
311 always last string in the list.
309
312
310 Also lifted nearly verbatim from traceback.py
313 Also lifted nearly verbatim from traceback.py
311 """
314 """
312
315
313 Colors = self.Colors
316 Colors = self.Colors
314 list = []
317 list = []
315 if type(etype) == types.ClassType:
318 if type(etype) == types.ClassType:
316 stype = Colors.excName + etype.__name__ + Colors.Normal
319 stype = Colors.excName + etype.__name__ + Colors.Normal
317 else:
320 else:
318 stype = etype # String exceptions don't get special coloring
321 stype = etype # String exceptions don't get special coloring
319 if value is None:
322 if value is None:
320 list.append( str(stype) + '\n')
323 list.append( str(stype) + '\n')
321 else:
324 else:
322 if etype is SyntaxError:
325 if etype is SyntaxError:
323 try:
326 try:
324 msg, (filename, lineno, offset, line) = value
327 msg, (filename, lineno, offset, line) = value
325 except:
328 except:
326 pass
329 pass
327 else:
330 else:
328 #print 'filename is',filename # dbg
331 #print 'filename is',filename # dbg
329 if not filename: filename = "<string>"
332 if not filename: filename = "<string>"
330 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
333 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
331 (Colors.normalEm,
334 (Colors.normalEm,
332 Colors.filenameEm, filename, Colors.normalEm,
335 Colors.filenameEm, filename, Colors.normalEm,
333 Colors.linenoEm, lineno, Colors.Normal ))
336 Colors.linenoEm, lineno, Colors.Normal ))
334 if line is not None:
337 if line is not None:
335 i = 0
338 i = 0
336 while i < len(line) and line[i].isspace():
339 while i < len(line) and line[i].isspace():
337 i = i+1
340 i = i+1
338 list.append('%s %s%s\n' % (Colors.line,
341 list.append('%s %s%s\n' % (Colors.line,
339 line.strip(),
342 line.strip(),
340 Colors.Normal))
343 Colors.Normal))
341 if offset is not None:
344 if offset is not None:
342 s = ' '
345 s = ' '
343 for c in line[i:offset-1]:
346 for c in line[i:offset-1]:
344 if c.isspace():
347 if c.isspace():
345 s = s + c
348 s = s + c
346 else:
349 else:
347 s = s + ' '
350 s = s + ' '
348 list.append('%s%s^%s\n' % (Colors.caret, s,
351 list.append('%s%s^%s\n' % (Colors.caret, s,
349 Colors.Normal) )
352 Colors.Normal) )
350 value = msg
353 value = msg
351 s = self._some_str(value)
354 s = self._some_str(value)
352 if s:
355 if s:
353 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
356 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
354 Colors.Normal, s))
357 Colors.Normal, s))
355 else:
358 else:
356 list.append('%s\n' % str(stype))
359 list.append('%s\n' % str(stype))
357 return list
360 return list
358
361
359 def _some_str(self, value):
362 def _some_str(self, value):
360 # Lifted from traceback.py
363 # Lifted from traceback.py
361 try:
364 try:
362 return str(value)
365 return str(value)
363 except:
366 except:
364 return '<unprintable %s object>' % type(value).__name__
367 return '<unprintable %s object>' % type(value).__name__
365
368
366 #----------------------------------------------------------------------------
369 #----------------------------------------------------------------------------
367 class VerboseTB(TBTools):
370 class VerboseTB(TBTools):
368 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
371 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
369 of HTML. Requires inspect and pydoc. Crazy, man.
372 of HTML. Requires inspect and pydoc. Crazy, man.
370
373
371 Modified version which optionally strips the topmost entries from the
374 Modified version which optionally strips the topmost entries from the
372 traceback, to be used with alternate interpreters (because their own code
375 traceback, to be used with alternate interpreters (because their own code
373 would appear in the traceback)."""
376 would appear in the traceback)."""
374
377
375 def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0,
378 def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0,
376 call_pdb = 0, include_vars=1):
379 call_pdb = 0, include_vars=1):
377 """Specify traceback offset, headers and color scheme.
380 """Specify traceback offset, headers and color scheme.
378
381
379 Define how many frames to drop from the tracebacks. Calling it with
382 Define how many frames to drop from the tracebacks. Calling it with
380 tb_offset=1 allows use of this handler in interpreters which will have
383 tb_offset=1 allows use of this handler in interpreters which will have
381 their own code at the top of the traceback (VerboseTB will first
384 their own code at the top of the traceback (VerboseTB will first
382 remove that frame before printing the traceback info)."""
385 remove that frame before printing the traceback info)."""
383 TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb)
386 TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb)
384 self.tb_offset = tb_offset
387 self.tb_offset = tb_offset
385 self.long_header = long_header
388 self.long_header = long_header
386 self.include_vars = include_vars
389 self.include_vars = include_vars
387
390
388 def text(self, etype, evalue, etb, context=5):
391 def text(self, etype, evalue, etb, context=5):
389 """Return a nice text document describing the traceback."""
392 """Return a nice text document describing the traceback."""
390
393
391 # some locals
394 # some locals
392 Colors = self.Colors # just a shorthand + quicker name lookup
395 Colors = self.Colors # just a shorthand + quicker name lookup
393 ColorsNormal = Colors.Normal # used a lot
396 ColorsNormal = Colors.Normal # used a lot
394 indent = ' '*INDENT_SIZE
397 indent = ' '*INDENT_SIZE
395 text_repr = pydoc.text.repr
398 text_repr = pydoc.text.repr
396 exc = '%s%s%s' % (Colors.excName, str(etype), ColorsNormal)
399 exc = '%s%s%s' % (Colors.excName, str(etype), ColorsNormal)
397 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
400 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
398 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
401 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
399
402
400 # some internal-use functions
403 # some internal-use functions
401 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
404 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
402 def nullrepr(value, repr=text_repr): return ''
405 def nullrepr(value, repr=text_repr): return ''
403
406
404 # meat of the code begins
407 # meat of the code begins
405 if type(etype) is types.ClassType:
408 if type(etype) is types.ClassType:
406 etype = etype.__name__
409 etype = etype.__name__
407
410
408 if self.long_header:
411 if self.long_header:
409 # Header with the exception type, python version, and date
412 # Header with the exception type, python version, and date
410 pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable
413 pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable
411 date = time.ctime(time.time())
414 date = time.ctime(time.time())
412
415
413 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
416 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
414 exc, ' '*(75-len(str(etype))-len(pyver)),
417 exc, ' '*(75-len(str(etype))-len(pyver)),
415 pyver, string.rjust(date, 75) )
418 pyver, string.rjust(date, 75) )
416 head += "\nA problem occured executing Python code. Here is the sequence of function"\
419 head += "\nA problem occured executing Python code. Here is the sequence of function"\
417 "\ncalls leading up to the error, with the most recent (innermost) call last."
420 "\ncalls leading up to the error, with the most recent (innermost) call last."
418 else:
421 else:
419 # Simplified header
422 # Simplified header
420 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
423 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
421 string.rjust('Traceback (most recent call last)',
424 string.rjust('Traceback (most recent call last)',
422 75 - len(str(etype)) ) )
425 75 - len(str(etype)) ) )
423 frames = []
426 frames = []
424 # Flush cache before calling inspect. This helps alleviate some of the
427 # Flush cache before calling inspect. This helps alleviate some of the
425 # problems with python 2.3's inspect.py.
428 # problems with python 2.3's inspect.py.
426 linecache.checkcache()
429 linecache.checkcache()
427 # Drop topmost frames if requested
430 # Drop topmost frames if requested
428 try:
431 try:
429 # Try the default getinnerframes and Alex's: Alex's fixes some
432 # Try the default getinnerframes and Alex's: Alex's fixes some
430 # problems, but it generates empty tracebacks for console errors
433 # problems, but it generates empty tracebacks for console errors
431 # (5 blanks lines) where none should be returned.
434 # (5 blanks lines) where none should be returned.
432 #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
435 #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
433 #print 'python records:', records # dbg
436 #print 'python records:', records # dbg
434 records = _fixed_getinnerframes(etb, context,self.tb_offset)
437 records = _fixed_getinnerframes(etb, context,self.tb_offset)
435 #print 'alex records:', records # dbg
438 #print 'alex records:', records # dbg
436 except:
439 except:
437
440
438 # FIXME: I've been getting many crash reports from python 2.3
441 # FIXME: I've been getting many crash reports from python 2.3
439 # users, traceable to inspect.py. If I can find a small test-case
442 # users, traceable to inspect.py. If I can find a small test-case
440 # to reproduce this, I should either write a better workaround or
443 # to reproduce this, I should either write a better workaround or
441 # file a bug report against inspect (if that's the real problem).
444 # file a bug report against inspect (if that's the real problem).
442 # So far, I haven't been able to find an isolated example to
445 # So far, I haven't been able to find an isolated example to
443 # reproduce the problem.
446 # reproduce the problem.
444 inspect_error()
447 inspect_error()
445 traceback.print_exc(file=Term.cerr)
448 traceback.print_exc(file=Term.cerr)
446 info('\nUnfortunately, your original traceback can not be constructed.\n')
449 info('\nUnfortunately, your original traceback can not be constructed.\n')
447 return ''
450 return ''
448
451
449 # build some color string templates outside these nested loops
452 # build some color string templates outside these nested loops
450 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
453 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
451 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
454 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
452 ColorsNormal)
455 ColorsNormal)
453 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
456 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
454 (Colors.vName, Colors.valEm, ColorsNormal)
457 (Colors.vName, Colors.valEm, ColorsNormal)
455 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
458 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
456 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
459 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
457 Colors.vName, ColorsNormal)
460 Colors.vName, ColorsNormal)
458 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
461 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
459 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
462 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
460 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
463 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
461 ColorsNormal)
464 ColorsNormal)
462
465
463 # now, loop over all records printing context and info
466 # now, loop over all records printing context and info
464 abspath = os.path.abspath
467 abspath = os.path.abspath
465 for frame, file, lnum, func, lines, index in records:
468 for frame, file, lnum, func, lines, index in records:
466 #print '*** record:',file,lnum,func,lines,index # dbg
469 #print '*** record:',file,lnum,func,lines,index # dbg
467 try:
470 try:
468 file = file and abspath(file) or '?'
471 file = file and abspath(file) or '?'
469 except OSError:
472 except OSError:
470 # if file is '<console>' or something not in the filesystem,
473 # if file is '<console>' or something not in the filesystem,
471 # the abspath call will throw an OSError. Just ignore it and
474 # the abspath call will throw an OSError. Just ignore it and
472 # keep the original file string.
475 # keep the original file string.
473 pass
476 pass
474 link = tpl_link % file
477 link = tpl_link % file
475 try:
478 try:
476 args, varargs, varkw, locals = inspect.getargvalues(frame)
479 args, varargs, varkw, locals = inspect.getargvalues(frame)
477 except:
480 except:
478 # This can happen due to a bug in python2.3. We should be
481 # This can happen due to a bug in python2.3. We should be
479 # able to remove this try/except when 2.4 becomes a
482 # able to remove this try/except when 2.4 becomes a
480 # requirement. Bug details at http://python.org/sf/1005466
483 # requirement. Bug details at http://python.org/sf/1005466
481 inspect_error()
484 inspect_error()
482 traceback.print_exc(file=Term.cerr)
485 traceback.print_exc(file=Term.cerr)
483 info("\nIPython's exception reporting continues...\n")
486 info("\nIPython's exception reporting continues...\n")
484
487
485 if func == '?':
488 if func == '?':
486 call = ''
489 call = ''
487 else:
490 else:
488 # Decide whether to include variable details or not
491 # Decide whether to include variable details or not
489 var_repr = self.include_vars and eqrepr or nullrepr
492 var_repr = self.include_vars and eqrepr or nullrepr
490 try:
493 try:
491 call = tpl_call % (func,inspect.formatargvalues(args,
494 call = tpl_call % (func,inspect.formatargvalues(args,
492 varargs, varkw,
495 varargs, varkw,
493 locals,formatvalue=var_repr))
496 locals,formatvalue=var_repr))
494 except KeyError:
497 except KeyError:
495 # Very odd crash from inspect.formatargvalues(). The
498 # Very odd crash from inspect.formatargvalues(). The
496 # scenario under which it appeared was a call to
499 # scenario under which it appeared was a call to
497 # view(array,scale) in NumTut.view.view(), where scale had
500 # view(array,scale) in NumTut.view.view(), where scale had
498 # been defined as a scalar (it should be a tuple). Somehow
501 # been defined as a scalar (it should be a tuple). Somehow
499 # inspect messes up resolving the argument list of view()
502 # inspect messes up resolving the argument list of view()
500 # and barfs out. At some point I should dig into this one
503 # and barfs out. At some point I should dig into this one
501 # and file a bug report about it.
504 # and file a bug report about it.
502 inspect_error()
505 inspect_error()
503 traceback.print_exc(file=Term.cerr)
506 traceback.print_exc(file=Term.cerr)
504 info("\nIPython's exception reporting continues...\n")
507 info("\nIPython's exception reporting continues...\n")
505 call = tpl_call_fail % func
508 call = tpl_call_fail % func
506
509
507 # Initialize a list of names on the current line, which the
510 # Initialize a list of names on the current line, which the
508 # tokenizer below will populate.
511 # tokenizer below will populate.
509 names = []
512 names = []
510
513
511 def tokeneater(token_type, token, start, end, line):
514 def tokeneater(token_type, token, start, end, line):
512 """Stateful tokeneater which builds dotted names.
515 """Stateful tokeneater which builds dotted names.
513
516
514 The list of names it appends to (from the enclosing scope) can
517 The list of names it appends to (from the enclosing scope) can
515 contain repeated composite names. This is unavoidable, since
518 contain repeated composite names. This is unavoidable, since
516 there is no way to disambguate partial dotted structures until
519 there is no way to disambguate partial dotted structures until
517 the full list is known. The caller is responsible for pruning
520 the full list is known. The caller is responsible for pruning
518 the final list of duplicates before using it."""
521 the final list of duplicates before using it."""
519
522
520 # build composite names
523 # build composite names
521 if token == '.':
524 if token == '.':
522 try:
525 try:
523 names[-1] += '.'
526 names[-1] += '.'
524 # store state so the next token is added for x.y.z names
527 # store state so the next token is added for x.y.z names
525 tokeneater.name_cont = True
528 tokeneater.name_cont = True
526 return
529 return
527 except IndexError:
530 except IndexError:
528 pass
531 pass
529 if token_type == tokenize.NAME and token not in keyword.kwlist:
532 if token_type == tokenize.NAME and token not in keyword.kwlist:
530 if tokeneater.name_cont:
533 if tokeneater.name_cont:
531 # Dotted names
534 # Dotted names
532 names[-1] += token
535 names[-1] += token
533 tokeneater.name_cont = False
536 tokeneater.name_cont = False
534 else:
537 else:
535 # Regular new names. We append everything, the caller
538 # Regular new names. We append everything, the caller
536 # will be responsible for pruning the list later. It's
539 # will be responsible for pruning the list later. It's
537 # very tricky to try to prune as we go, b/c composite
540 # very tricky to try to prune as we go, b/c composite
538 # names can fool us. The pruning at the end is easy
541 # names can fool us. The pruning at the end is easy
539 # to do (or the caller can print a list with repeated
542 # to do (or the caller can print a list with repeated
540 # names if so desired.
543 # names if so desired.
541 names.append(token)
544 names.append(token)
542 elif token_type == tokenize.NEWLINE:
545 elif token_type == tokenize.NEWLINE:
543 raise IndexError
546 raise IndexError
544 # we need to store a bit of state in the tokenizer to build
547 # we need to store a bit of state in the tokenizer to build
545 # dotted names
548 # dotted names
546 tokeneater.name_cont = False
549 tokeneater.name_cont = False
547
550
548 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
551 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
549 line = getline(file, lnum[0])
552 line = getline(file, lnum[0])
550 lnum[0] += 1
553 lnum[0] += 1
551 return line
554 return line
552
555
553 # Build the list of names on this line of code where the exception
556 # Build the list of names on this line of code where the exception
554 # occurred.
557 # occurred.
555 try:
558 try:
556 # This builds the names list in-place by capturing it from the
559 # This builds the names list in-place by capturing it from the
557 # enclosing scope.
560 # enclosing scope.
558 tokenize.tokenize(linereader, tokeneater)
561 tokenize.tokenize(linereader, tokeneater)
559 except IndexError:
562 except IndexError:
560 # signals exit of tokenizer
563 # signals exit of tokenizer
561 pass
564 pass
562 except tokenize.TokenError,msg:
565 except tokenize.TokenError,msg:
563 _m = ("An unexpected error occurred while tokenizing input\n"
566 _m = ("An unexpected error occurred while tokenizing input\n"
564 "The following traceback may be corrupted or invalid\n"
567 "The following traceback may be corrupted or invalid\n"
565 "The error message is: %s\n" % msg)
568 "The error message is: %s\n" % msg)
566 error(_m)
569 error(_m)
567
570
568 # prune names list of duplicates, but keep the right order
571 # prune names list of duplicates, but keep the right order
569 unique_names = uniq_stable(names)
572 unique_names = uniq_stable(names)
570
573
571 # Start loop over vars
574 # Start loop over vars
572 lvals = []
575 lvals = []
573 if self.include_vars:
576 if self.include_vars:
574 for name_full in unique_names:
577 for name_full in unique_names:
575 name_base = name_full.split('.',1)[0]
578 name_base = name_full.split('.',1)[0]
576 if name_base in frame.f_code.co_varnames:
579 if name_base in frame.f_code.co_varnames:
577 if locals.has_key(name_base):
580 if locals.has_key(name_base):
578 try:
581 try:
579 value = repr(eval(name_full,locals))
582 value = repr(eval(name_full,locals))
580 except:
583 except:
581 value = undefined
584 value = undefined
582 else:
585 else:
583 value = undefined
586 value = undefined
584 name = tpl_local_var % name_full
587 name = tpl_local_var % name_full
585 else:
588 else:
586 if frame.f_globals.has_key(name_base):
589 if frame.f_globals.has_key(name_base):
587 try:
590 try:
588 value = repr(eval(name_full,frame.f_globals))
591 value = repr(eval(name_full,frame.f_globals))
589 except:
592 except:
590 value = undefined
593 value = undefined
591 else:
594 else:
592 value = undefined
595 value = undefined
593 name = tpl_global_var % name_full
596 name = tpl_global_var % name_full
594 lvals.append(tpl_name_val % (name,value))
597 lvals.append(tpl_name_val % (name,value))
595 if lvals:
598 if lvals:
596 lvals = '%s%s' % (indent,em_normal.join(lvals))
599 lvals = '%s%s' % (indent,em_normal.join(lvals))
597 else:
600 else:
598 lvals = ''
601 lvals = ''
599
602
600 level = '%s %s\n' % (link,call)
603 level = '%s %s\n' % (link,call)
601
604
602 if index is None:
605 if index is None:
603 frames.append(level)
606 frames.append(level)
604 else:
607 else:
605 frames.append('%s%s' % (level,''.join(
608 frames.append('%s%s' % (level,''.join(
606 _formatTracebackLines(lnum,index,lines,self.Colors,lvals))))
609 _formatTracebackLines(lnum,index,lines,self.Colors,lvals))))
607
610
608 # Get (safely) a string form of the exception info
611 # Get (safely) a string form of the exception info
609 try:
612 try:
610 etype_str,evalue_str = map(str,(etype,evalue))
613 etype_str,evalue_str = map(str,(etype,evalue))
611 except:
614 except:
612 # User exception is improperly defined.
615 # User exception is improperly defined.
613 etype,evalue = str,sys.exc_info()[:2]
616 etype,evalue = str,sys.exc_info()[:2]
614 etype_str,evalue_str = map(str,(etype,evalue))
617 etype_str,evalue_str = map(str,(etype,evalue))
615 # ... and format it
618 # ... and format it
616 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
619 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
617 ColorsNormal, evalue_str)]
620 ColorsNormal, evalue_str)]
618 if type(evalue) is types.InstanceType:
621 if type(evalue) is types.InstanceType:
619 try:
622 try:
620 names = [w for w in dir(evalue) if isinstance(w, basestring)]
623 names = [w for w in dir(evalue) if isinstance(w, basestring)]
621 except:
624 except:
622 # Every now and then, an object with funny inernals blows up
625 # Every now and then, an object with funny inernals blows up
623 # when dir() is called on it. We do the best we can to report
626 # when dir() is called on it. We do the best we can to report
624 # the problem and continue
627 # the problem and continue
625 _m = '%sException reporting error (object with broken dir())%s:'
628 _m = '%sException reporting error (object with broken dir())%s:'
626 exception.append(_m % (Colors.excName,ColorsNormal))
629 exception.append(_m % (Colors.excName,ColorsNormal))
627 etype_str,evalue_str = map(str,sys.exc_info()[:2])
630 etype_str,evalue_str = map(str,sys.exc_info()[:2])
628 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
631 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
629 ColorsNormal, evalue_str))
632 ColorsNormal, evalue_str))
630 names = []
633 names = []
631 for name in names:
634 for name in names:
632 value = text_repr(getattr(evalue, name))
635 value = text_repr(getattr(evalue, name))
633 exception.append('\n%s%s = %s' % (indent, name, value))
636 exception.append('\n%s%s = %s' % (indent, name, value))
634 # return all our info assembled as a single string
637 # return all our info assembled as a single string
635 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
638 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
636
639
637 def debugger(self):
640 def debugger(self):
638 """Call up the pdb debugger if desired, always clean up the tb reference.
641 """Call up the pdb debugger if desired, always clean up the tb reference.
639
642
640 If the call_pdb flag is set, the pdb interactive debugger is
643 If the call_pdb flag is set, the pdb interactive debugger is
641 invoked. In all cases, the self.tb reference to the current traceback
644 invoked. In all cases, the self.tb reference to the current traceback
642 is deleted to prevent lingering references which hamper memory
645 is deleted to prevent lingering references which hamper memory
643 management.
646 management.
644
647
645 Note that each call to pdb() does an 'import readline', so if your app
648 Note that each call to pdb() does an 'import readline', so if your app
646 requires a special setup for the readline completers, you'll have to
649 requires a special setup for the readline completers, you'll have to
647 fix that by hand after invoking the exception handler."""
650 fix that by hand after invoking the exception handler."""
648
651
649 if self.call_pdb:
652 if self.call_pdb:
650 if self.pdb is None:
653 if self.pdb is None:
651 self.pdb = Debugger.Pdb(
654 self.pdb = Debugger.Pdb(
652 self.color_scheme_table.active_scheme_name)
655 self.color_scheme_table.active_scheme_name)
653 # the system displayhook may have changed, restore the original
656 # the system displayhook may have changed, restore the original
654 # for pdb
657 # for pdb
655 dhook = sys.displayhook
658 dhook = sys.displayhook
656 sys.displayhook = sys.__displayhook__
659 sys.displayhook = sys.__displayhook__
657 self.pdb.reset()
660 self.pdb.reset()
658 # Find the right frame so we don't pop up inside ipython itself
661 # Find the right frame so we don't pop up inside ipython itself
659 etb = self.tb
662 etb = self.tb
660 while self.tb.tb_next is not None:
663 while self.tb.tb_next is not None:
661 self.tb = self.tb.tb_next
664 self.tb = self.tb.tb_next
662 try:
665 try:
663 if etb and etb.tb_next:
666 if etb and etb.tb_next:
664 etb = etb.tb_next
667 etb = etb.tb_next
665 self.pdb.botframe = etb.tb_frame
668 self.pdb.botframe = etb.tb_frame
666 self.pdb.interaction(self.tb.tb_frame, self.tb)
669 self.pdb.interaction(self.tb.tb_frame, self.tb)
667 except:
670 except:
668 print '*** ERROR ***'
671 print '*** ERROR ***'
669 print 'This version of pdb has a bug and crashed.'
672 print 'This version of pdb has a bug and crashed.'
670 print 'Returning to IPython...'
673 print 'Returning to IPython...'
671 sys.displayhook = dhook
674 sys.displayhook = dhook
672 del self.tb
675 del self.tb
673
676
674 def handler(self, info=None):
677 def handler(self, info=None):
675 (etype, evalue, etb) = info or sys.exc_info()
678 (etype, evalue, etb) = info or sys.exc_info()
676 self.tb = etb
679 self.tb = etb
677 print >> Term.cerr, self.text(etype, evalue, etb)
680 print >> Term.cerr, self.text(etype, evalue, etb)
678
681
679 # Changed so an instance can just be called as VerboseTB_inst() and print
682 # Changed so an instance can just be called as VerboseTB_inst() and print
680 # out the right info on its own.
683 # out the right info on its own.
681 def __call__(self, etype=None, evalue=None, etb=None):
684 def __call__(self, etype=None, evalue=None, etb=None):
682 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
685 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
683 if etb is None:
686 if etb is None:
684 self.handler()
687 self.handler()
685 else:
688 else:
686 self.handler((etype, evalue, etb))
689 self.handler((etype, evalue, etb))
687 self.debugger()
690 self.debugger()
688
691
689 #----------------------------------------------------------------------------
692 #----------------------------------------------------------------------------
690 class FormattedTB(VerboseTB,ListTB):
693 class FormattedTB(VerboseTB,ListTB):
691 """Subclass ListTB but allow calling with a traceback.
694 """Subclass ListTB but allow calling with a traceback.
692
695
693 It can thus be used as a sys.excepthook for Python > 2.1.
696 It can thus be used as a sys.excepthook for Python > 2.1.
694
697
695 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
698 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
696
699
697 Allows a tb_offset to be specified. This is useful for situations where
700 Allows a tb_offset to be specified. This is useful for situations where
698 one needs to remove a number of topmost frames from the traceback (such as
701 one needs to remove a number of topmost frames from the traceback (such as
699 occurs with python programs that themselves execute other python code,
702 occurs with python programs that themselves execute other python code,
700 like Python shells). """
703 like Python shells). """
701
704
702 def __init__(self, mode = 'Plain', color_scheme='Linux',
705 def __init__(self, mode = 'Plain', color_scheme='Linux',
703 tb_offset = 0,long_header=0,call_pdb=0,include_vars=0):
706 tb_offset = 0,long_header=0,call_pdb=0,include_vars=0):
704
707
705 # NEVER change the order of this list. Put new modes at the end:
708 # NEVER change the order of this list. Put new modes at the end:
706 self.valid_modes = ['Plain','Context','Verbose']
709 self.valid_modes = ['Plain','Context','Verbose']
707 self.verbose_modes = self.valid_modes[1:3]
710 self.verbose_modes = self.valid_modes[1:3]
708
711
709 VerboseTB.__init__(self,color_scheme,tb_offset,long_header,
712 VerboseTB.__init__(self,color_scheme,tb_offset,long_header,
710 call_pdb=call_pdb,include_vars=include_vars)
713 call_pdb=call_pdb,include_vars=include_vars)
711 self.set_mode(mode)
714 self.set_mode(mode)
712
715
713 def _extract_tb(self,tb):
716 def _extract_tb(self,tb):
714 if tb:
717 if tb:
715 return traceback.extract_tb(tb)
718 return traceback.extract_tb(tb)
716 else:
719 else:
717 return None
720 return None
718
721
719 def text(self, etype, value, tb,context=5,mode=None):
722 def text(self, etype, value, tb,context=5,mode=None):
720 """Return formatted traceback.
723 """Return formatted traceback.
721
724
722 If the optional mode parameter is given, it overrides the current
725 If the optional mode parameter is given, it overrides the current
723 mode."""
726 mode."""
724
727
725 if mode is None:
728 if mode is None:
726 mode = self.mode
729 mode = self.mode
727 if mode in self.verbose_modes:
730 if mode in self.verbose_modes:
728 # verbose modes need a full traceback
731 # verbose modes need a full traceback
729 return VerboseTB.text(self,etype, value, tb,context=5)
732 return VerboseTB.text(self,etype, value, tb,context=5)
730 else:
733 else:
731 # We must check the source cache because otherwise we can print
734 # We must check the source cache because otherwise we can print
732 # out-of-date source code.
735 # out-of-date source code.
733 linecache.checkcache()
736 linecache.checkcache()
734 # Now we can extract and format the exception
737 # Now we can extract and format the exception
735 elist = self._extract_tb(tb)
738 elist = self._extract_tb(tb)
736 if len(elist) > self.tb_offset:
739 if len(elist) > self.tb_offset:
737 del elist[:self.tb_offset]
740 del elist[:self.tb_offset]
738 return ListTB.text(self,etype,value,elist)
741 return ListTB.text(self,etype,value,elist)
739
742
740 def set_mode(self,mode=None):
743 def set_mode(self,mode=None):
741 """Switch to the desired mode.
744 """Switch to the desired mode.
742
745
743 If mode is not specified, cycles through the available modes."""
746 If mode is not specified, cycles through the available modes."""
744
747
745 if not mode:
748 if not mode:
746 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
749 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
747 len(self.valid_modes)
750 len(self.valid_modes)
748 self.mode = self.valid_modes[new_idx]
751 self.mode = self.valid_modes[new_idx]
749 elif mode not in self.valid_modes:
752 elif mode not in self.valid_modes:
750 raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
753 raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
751 'Valid modes: '+str(self.valid_modes)
754 'Valid modes: '+str(self.valid_modes)
752 else:
755 else:
753 self.mode = mode
756 self.mode = mode
754 # include variable details only in 'Verbose' mode
757 # include variable details only in 'Verbose' mode
755 self.include_vars = (self.mode == self.valid_modes[2])
758 self.include_vars = (self.mode == self.valid_modes[2])
756
759
757 # some convenient shorcuts
760 # some convenient shorcuts
758 def plain(self):
761 def plain(self):
759 self.set_mode(self.valid_modes[0])
762 self.set_mode(self.valid_modes[0])
760
763
761 def context(self):
764 def context(self):
762 self.set_mode(self.valid_modes[1])
765 self.set_mode(self.valid_modes[1])
763
766
764 def verbose(self):
767 def verbose(self):
765 self.set_mode(self.valid_modes[2])
768 self.set_mode(self.valid_modes[2])
766
769
767 #----------------------------------------------------------------------------
770 #----------------------------------------------------------------------------
768 class AutoFormattedTB(FormattedTB):
771 class AutoFormattedTB(FormattedTB):
769 """A traceback printer which can be called on the fly.
772 """A traceback printer which can be called on the fly.
770
773
771 It will find out about exceptions by itself.
774 It will find out about exceptions by itself.
772
775
773 A brief example:
776 A brief example:
774
777
775 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
778 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
776 try:
779 try:
777 ...
780 ...
778 except:
781 except:
779 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
782 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
780 """
783 """
781 def __call__(self,etype=None,evalue=None,etb=None,
784 def __call__(self,etype=None,evalue=None,etb=None,
782 out=None,tb_offset=None):
785 out=None,tb_offset=None):
783 """Print out a formatted exception traceback.
786 """Print out a formatted exception traceback.
784
787
785 Optional arguments:
788 Optional arguments:
786 - out: an open file-like object to direct output to.
789 - out: an open file-like object to direct output to.
787
790
788 - tb_offset: the number of frames to skip over in the stack, on a
791 - tb_offset: the number of frames to skip over in the stack, on a
789 per-call basis (this overrides temporarily the instance's tb_offset
792 per-call basis (this overrides temporarily the instance's tb_offset
790 given at initialization time. """
793 given at initialization time. """
791
794
792 if out is None:
795 if out is None:
793 out = Term.cerr
796 out = Term.cerr
794 if tb_offset is not None:
797 if tb_offset is not None:
795 tb_offset, self.tb_offset = self.tb_offset, tb_offset
798 tb_offset, self.tb_offset = self.tb_offset, tb_offset
796 print >> out, self.text(etype, evalue, etb)
799 print >> out, self.text(etype, evalue, etb)
797 self.tb_offset = tb_offset
800 self.tb_offset = tb_offset
798 else:
801 else:
799 print >> out, self.text(etype, evalue, etb)
802 print >> out, self.text(etype, evalue, etb)
800 self.debugger()
803 self.debugger()
801
804
802 def text(self,etype=None,value=None,tb=None,context=5,mode=None):
805 def text(self,etype=None,value=None,tb=None,context=5,mode=None):
803 if etype is None:
806 if etype is None:
804 etype,value,tb = sys.exc_info()
807 etype,value,tb = sys.exc_info()
805 self.tb = tb
808 self.tb = tb
806 return FormattedTB.text(self,etype,value,tb,context=5,mode=mode)
809 return FormattedTB.text(self,etype,value,tb,context=5,mode=mode)
807
810
808 #---------------------------------------------------------------------------
811 #---------------------------------------------------------------------------
809 # A simple class to preserve Nathan's original functionality.
812 # A simple class to preserve Nathan's original functionality.
810 class ColorTB(FormattedTB):
813 class ColorTB(FormattedTB):
811 """Shorthand to initialize a FormattedTB in Linux colors mode."""
814 """Shorthand to initialize a FormattedTB in Linux colors mode."""
812 def __init__(self,color_scheme='Linux',call_pdb=0):
815 def __init__(self,color_scheme='Linux',call_pdb=0):
813 FormattedTB.__init__(self,color_scheme=color_scheme,
816 FormattedTB.__init__(self,color_scheme=color_scheme,
814 call_pdb=call_pdb)
817 call_pdb=call_pdb)
815
818
816 #----------------------------------------------------------------------------
819 #----------------------------------------------------------------------------
817 # module testing (minimal)
820 # module testing (minimal)
818 if __name__ == "__main__":
821 if __name__ == "__main__":
819 def spam(c, (d, e)):
822 def spam(c, (d, e)):
820 x = c + d
823 x = c + d
821 y = c * d
824 y = c * d
822 foo(x, y)
825 foo(x, y)
823
826
824 def foo(a, b, bar=1):
827 def foo(a, b, bar=1):
825 eggs(a, b + bar)
828 eggs(a, b + bar)
826
829
827 def eggs(f, g, z=globals()):
830 def eggs(f, g, z=globals()):
828 h = f + g
831 h = f + g
829 i = f - g
832 i = f - g
830 return h / i
833 return h / i
831
834
832 print ''
835 print ''
833 print '*** Before ***'
836 print '*** Before ***'
834 try:
837 try:
835 print spam(1, (2, 3))
838 print spam(1, (2, 3))
836 except:
839 except:
837 traceback.print_exc()
840 traceback.print_exc()
838 print ''
841 print ''
839
842
840 handler = ColorTB()
843 handler = ColorTB()
841 print '*** ColorTB ***'
844 print '*** ColorTB ***'
842 try:
845 try:
843 print spam(1, (2, 3))
846 print spam(1, (2, 3))
844 except:
847 except:
845 apply(handler, sys.exc_info() )
848 apply(handler, sys.exc_info() )
846 print ''
849 print ''
847
850
848 handler = VerboseTB()
851 handler = VerboseTB()
849 print '*** VerboseTB ***'
852 print '*** VerboseTB ***'
850 try:
853 try:
851 print spam(1, (2, 3))
854 print spam(1, (2, 3))
852 except:
855 except:
853 apply(handler, sys.exc_info() )
856 apply(handler, sys.exc_info() )
854 print ''
857 print ''
855
858
General Comments 0
You need to be logged in to leave comments. Login now