##// END OF EJS Templates
Fixed bug in ultratb.py and io.py....
Brian Granger -
Show More
@@ -1,1102 +1,1104 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
63
64 #*****************************************************************************
64 #*****************************************************************************
65 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
65 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
66 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
66 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
67 #
67 #
68 # Distributed under the terms of the BSD License. The full license is in
68 # Distributed under the terms of the BSD License. The full license is in
69 # the file COPYING, distributed as part of this software.
69 # the file COPYING, distributed as part of this software.
70 #*****************************************************************************
70 #*****************************************************************************
71
71
72 from __future__ import with_statement
72 from __future__ import with_statement
73
73
74 import inspect
74 import inspect
75 import keyword
75 import keyword
76 import linecache
76 import linecache
77 import os
77 import os
78 import pydoc
78 import pydoc
79 import re
79 import re
80 import string
80 import string
81 import sys
81 import sys
82 import time
82 import time
83 import tokenize
83 import tokenize
84 import traceback
84 import traceback
85 import types
85 import types
86
86
87 # For purposes of monkeypatching inspect to fix a bug in it.
87 # For purposes of monkeypatching inspect to fix a bug in it.
88 from inspect import getsourcefile, getfile, getmodule,\
88 from inspect import getsourcefile, getfile, getmodule,\
89 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
89 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
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.utils import PyColorize
93 from IPython.utils import PyColorize
94 from IPython.core import debugger, ipapi
94 from IPython.core import debugger, ipapi
95 from IPython.core.display_trap import DisplayTrap
95 from IPython.core.display_trap import DisplayTrap
96 from IPython.core.excolors import exception_colors
96 from IPython.core.excolors import exception_colors
97 from IPython.utils.data import uniq_stable
97 from IPython.utils.data import uniq_stable
98 from IPython.utils.io import Term
98 from IPython.utils.io import Term
99 from IPython.utils.warn import info, error
99 from IPython.utils.warn import info, error
100
100
101 # Globals
101 # Globals
102 # amount of space to put line numbers before verbose tracebacks
102 # amount of space to put line numbers before verbose tracebacks
103 INDENT_SIZE = 8
103 INDENT_SIZE = 8
104
104
105 # Default color scheme. This is used, for example, by the traceback
105 # Default color scheme. This is used, for example, by the traceback
106 # formatter. When running in an actual IPython instance, the user's rc.colors
106 # formatter. When running in an actual IPython instance, the user's rc.colors
107 # value is used, but havinga module global makes this functionality available
107 # value is used, but havinga module global makes this functionality available
108 # to users of ultratb who are NOT running inside ipython.
108 # to users of ultratb who are NOT running inside ipython.
109 DEFAULT_SCHEME = 'NoColor'
109 DEFAULT_SCHEME = 'NoColor'
110
110
111 #---------------------------------------------------------------------------
111 #---------------------------------------------------------------------------
112 # Code begins
112 # Code begins
113
113
114 # Utility functions
114 # Utility functions
115 def inspect_error():
115 def inspect_error():
116 """Print a message about internal inspect errors.
116 """Print a message about internal inspect errors.
117
117
118 These are unfortunately quite common."""
118 These are unfortunately quite common."""
119
119
120 error('Internal Python error in the inspect module.\n'
120 error('Internal Python error in the inspect module.\n'
121 'Below is the traceback from this internal error.\n')
121 'Below is the traceback from this internal error.\n')
122
122
123
123
124 def findsource(object):
124 def findsource(object):
125 """Return the entire source file and starting line number for an object.
125 """Return the entire source file and starting line number for an object.
126
126
127 The argument may be a module, class, method, function, traceback, frame,
127 The argument may be a module, class, method, function, traceback, frame,
128 or code object. The source code is returned as a list of all the lines
128 or code object. The source code is returned as a list of all the lines
129 in the file and the line number indexes a line in that list. An IOError
129 in the file and the line number indexes a line in that list. An IOError
130 is raised if the source code cannot be retrieved.
130 is raised if the source code cannot be retrieved.
131
131
132 FIXED version with which we monkeypatch the stdlib to work around a bug."""
132 FIXED version with which we monkeypatch the stdlib to work around a bug."""
133
133
134 file = getsourcefile(object) or getfile(object)
134 file = getsourcefile(object) or getfile(object)
135 # If the object is a frame, then trying to get the globals dict from its
135 # If the object is a frame, then trying to get the globals dict from its
136 # module won't work. Instead, the frame object itself has the globals
136 # module won't work. Instead, the frame object itself has the globals
137 # dictionary.
137 # dictionary.
138 globals_dict = None
138 globals_dict = None
139 if inspect.isframe(object):
139 if inspect.isframe(object):
140 # XXX: can this ever be false?
140 # XXX: can this ever be false?
141 globals_dict = object.f_globals
141 globals_dict = object.f_globals
142 else:
142 else:
143 module = getmodule(object, file)
143 module = getmodule(object, file)
144 if module:
144 if module:
145 globals_dict = module.__dict__
145 globals_dict = module.__dict__
146 lines = linecache.getlines(file, globals_dict)
146 lines = linecache.getlines(file, globals_dict)
147 if not lines:
147 if not lines:
148 raise IOError('could not get source code')
148 raise IOError('could not get source code')
149
149
150 if ismodule(object):
150 if ismodule(object):
151 return lines, 0
151 return lines, 0
152
152
153 if isclass(object):
153 if isclass(object):
154 name = object.__name__
154 name = object.__name__
155 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
155 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
156 # make some effort to find the best matching class definition:
156 # make some effort to find the best matching class definition:
157 # use the one with the least indentation, which is the one
157 # use the one with the least indentation, which is the one
158 # that's most probably not inside a function definition.
158 # that's most probably not inside a function definition.
159 candidates = []
159 candidates = []
160 for i in range(len(lines)):
160 for i in range(len(lines)):
161 match = pat.match(lines[i])
161 match = pat.match(lines[i])
162 if match:
162 if match:
163 # if it's at toplevel, it's already the best one
163 # if it's at toplevel, it's already the best one
164 if lines[i][0] == 'c':
164 if lines[i][0] == 'c':
165 return lines, i
165 return lines, i
166 # else add whitespace to candidate list
166 # else add whitespace to candidate list
167 candidates.append((match.group(1), i))
167 candidates.append((match.group(1), i))
168 if candidates:
168 if candidates:
169 # this will sort by whitespace, and by line number,
169 # this will sort by whitespace, and by line number,
170 # less whitespace first
170 # less whitespace first
171 candidates.sort()
171 candidates.sort()
172 return lines, candidates[0][1]
172 return lines, candidates[0][1]
173 else:
173 else:
174 raise IOError('could not find class definition')
174 raise IOError('could not find class definition')
175
175
176 if ismethod(object):
176 if ismethod(object):
177 object = object.im_func
177 object = object.im_func
178 if isfunction(object):
178 if isfunction(object):
179 object = object.func_code
179 object = object.func_code
180 if istraceback(object):
180 if istraceback(object):
181 object = object.tb_frame
181 object = object.tb_frame
182 if isframe(object):
182 if isframe(object):
183 object = object.f_code
183 object = object.f_code
184 if iscode(object):
184 if iscode(object):
185 if not hasattr(object, 'co_firstlineno'):
185 if not hasattr(object, 'co_firstlineno'):
186 raise IOError('could not find function definition')
186 raise IOError('could not find function definition')
187 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
187 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
188 pmatch = pat.match
188 pmatch = pat.match
189 # fperez - fix: sometimes, co_firstlineno can give a number larger than
189 # fperez - fix: sometimes, co_firstlineno can give a number larger than
190 # the length of lines, which causes an error. Safeguard against that.
190 # the length of lines, which causes an error. Safeguard against that.
191 lnum = min(object.co_firstlineno,len(lines))-1
191 lnum = min(object.co_firstlineno,len(lines))-1
192 while lnum > 0:
192 while lnum > 0:
193 if pmatch(lines[lnum]): break
193 if pmatch(lines[lnum]): break
194 lnum -= 1
194 lnum -= 1
195
195
196 return lines, lnum
196 return lines, lnum
197 raise IOError('could not find code object')
197 raise IOError('could not find code object')
198
198
199 # Monkeypatch inspect to apply our bugfix. This code only works with py25
199 # Monkeypatch inspect to apply our bugfix. This code only works with py25
200 if sys.version_info[:2] >= (2,5):
200 if sys.version_info[:2] >= (2,5):
201 inspect.findsource = findsource
201 inspect.findsource = findsource
202
202
203 def fix_frame_records_filenames(records):
203 def fix_frame_records_filenames(records):
204 """Try to fix the filenames in each record from inspect.getinnerframes().
204 """Try to fix the filenames in each record from inspect.getinnerframes().
205
205
206 Particularly, modules loaded from within zip files have useless filenames
206 Particularly, modules loaded from within zip files have useless filenames
207 attached to their code object, and inspect.getinnerframes() just uses it.
207 attached to their code object, and inspect.getinnerframes() just uses it.
208 """
208 """
209 fixed_records = []
209 fixed_records = []
210 for frame, filename, line_no, func_name, lines, index in records:
210 for frame, filename, line_no, func_name, lines, index in records:
211 # Look inside the frame's globals dictionary for __file__, which should
211 # Look inside the frame's globals dictionary for __file__, which should
212 # be better.
212 # be better.
213 better_fn = frame.f_globals.get('__file__', None)
213 better_fn = frame.f_globals.get('__file__', None)
214 if isinstance(better_fn, str):
214 if isinstance(better_fn, str):
215 # Check the type just in case someone did something weird with
215 # Check the type just in case someone did something weird with
216 # __file__. It might also be None if the error occurred during
216 # __file__. It might also be None if the error occurred during
217 # import.
217 # import.
218 filename = better_fn
218 filename = better_fn
219 fixed_records.append((frame, filename, line_no, func_name, lines, index))
219 fixed_records.append((frame, filename, line_no, func_name, lines, index))
220 return fixed_records
220 return fixed_records
221
221
222
222
223 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
223 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
224 import linecache
224 import linecache
225 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
225 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
226
226
227 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
227 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
228
228
229 # If the error is at the console, don't build any context, since it would
229 # If the error is at the console, don't build any context, since it would
230 # otherwise produce 5 blank lines printed out (there is no file at the
230 # otherwise produce 5 blank lines printed out (there is no file at the
231 # console)
231 # console)
232 rec_check = records[tb_offset:]
232 rec_check = records[tb_offset:]
233 try:
233 try:
234 rname = rec_check[0][1]
234 rname = rec_check[0][1]
235 if rname == '<ipython console>' or rname.endswith('<string>'):
235 if rname == '<ipython console>' or rname.endswith('<string>'):
236 return rec_check
236 return rec_check
237 except IndexError:
237 except IndexError:
238 pass
238 pass
239
239
240 aux = traceback.extract_tb(etb)
240 aux = traceback.extract_tb(etb)
241 assert len(records) == len(aux)
241 assert len(records) == len(aux)
242 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
242 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
243 maybeStart = lnum-1 - context//2
243 maybeStart = lnum-1 - context//2
244 start = max(maybeStart, 0)
244 start = max(maybeStart, 0)
245 end = start + context
245 end = start + context
246 lines = linecache.getlines(file)[start:end]
246 lines = linecache.getlines(file)[start:end]
247 # pad with empty lines if necessary
247 # pad with empty lines if necessary
248 if maybeStart < 0:
248 if maybeStart < 0:
249 lines = (['\n'] * -maybeStart) + lines
249 lines = (['\n'] * -maybeStart) + lines
250 if len(lines) < context:
250 if len(lines) < context:
251 lines += ['\n'] * (context - len(lines))
251 lines += ['\n'] * (context - len(lines))
252 buf = list(records[i])
252 buf = list(records[i])
253 buf[LNUM_POS] = lnum
253 buf[LNUM_POS] = lnum
254 buf[INDEX_POS] = lnum - 1 - start
254 buf[INDEX_POS] = lnum - 1 - start
255 buf[LINES_POS] = lines
255 buf[LINES_POS] = lines
256 records[i] = tuple(buf)
256 records[i] = tuple(buf)
257 return records[tb_offset:]
257 return records[tb_offset:]
258
258
259 # Helper function -- largely belongs to VerboseTB, but we need the same
259 # Helper function -- largely belongs to VerboseTB, but we need the same
260 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
260 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
261 # can be recognized properly by ipython.el's py-traceback-line-re
261 # can be recognized properly by ipython.el's py-traceback-line-re
262 # (SyntaxErrors have to be treated specially because they have no traceback)
262 # (SyntaxErrors have to be treated specially because they have no traceback)
263
263
264 _parser = PyColorize.Parser()
264 _parser = PyColorize.Parser()
265
265
266 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
266 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
267 numbers_width = INDENT_SIZE - 1
267 numbers_width = INDENT_SIZE - 1
268 res = []
268 res = []
269 i = lnum - index
269 i = lnum - index
270
270
271 # This lets us get fully syntax-highlighted tracebacks.
271 # This lets us get fully syntax-highlighted tracebacks.
272 if scheme is None:
272 if scheme is None:
273 ipinst = ipapi.get()
273 ipinst = ipapi.get()
274 if ipinst is not None:
274 if ipinst is not None:
275 scheme = ipinst.colors
275 scheme = ipinst.colors
276 else:
276 else:
277 scheme = DEFAULT_SCHEME
277 scheme = DEFAULT_SCHEME
278
278
279 _line_format = _parser.format2
279 _line_format = _parser.format2
280
280
281 for line in lines:
281 for line in lines:
282 new_line, err = _line_format(line,'str',scheme)
282 new_line, err = _line_format(line,'str',scheme)
283 if not err: line = new_line
283 if not err: line = new_line
284
284
285 if i == lnum:
285 if i == lnum:
286 # This is the line with the error
286 # This is the line with the error
287 pad = numbers_width - len(str(i))
287 pad = numbers_width - len(str(i))
288 if pad >= 3:
288 if pad >= 3:
289 marker = '-'*(pad-3) + '-> '
289 marker = '-'*(pad-3) + '-> '
290 elif pad == 2:
290 elif pad == 2:
291 marker = '> '
291 marker = '> '
292 elif pad == 1:
292 elif pad == 1:
293 marker = '>'
293 marker = '>'
294 else:
294 else:
295 marker = ''
295 marker = ''
296 num = marker + str(i)
296 num = marker + str(i)
297 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
297 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
298 Colors.line, line, Colors.Normal)
298 Colors.line, line, Colors.Normal)
299 else:
299 else:
300 num = '%*s' % (numbers_width,i)
300 num = '%*s' % (numbers_width,i)
301 line = '%s%s%s %s' %(Colors.lineno, num,
301 line = '%s%s%s %s' %(Colors.lineno, num,
302 Colors.Normal, line)
302 Colors.Normal, line)
303
303
304 res.append(line)
304 res.append(line)
305 if lvals and i == lnum:
305 if lvals and i == lnum:
306 res.append(lvals + '\n')
306 res.append(lvals + '\n')
307 i = i + 1
307 i = i + 1
308 return res
308 return res
309
309
310
310
311 #---------------------------------------------------------------------------
311 #---------------------------------------------------------------------------
312 # Module classes
312 # Module classes
313 class TBTools:
313 class TBTools:
314 """Basic tools used by all traceback printer classes."""
314 """Basic tools used by all traceback printer classes."""
315
315
316 #: Default output stream, can be overridden at call time. A special value
316 #: Default output stream, can be overridden at call time. A special value
317 #: of 'stdout' *as a string* can be given to force extraction of sys.stdout
317 #: of 'stdout' *as a string* can be given to force extraction of sys.stdout
318 #: at runtime. This allows testing exception printing with doctests, that
318 #: at runtime. This allows testing exception printing with doctests, that
319 #: swap sys.stdout just at execution time.
319 #: swap sys.stdout just at execution time.
320 #: Warning: be VERY careful to set this to one of the Term streams, NEVER
320 #: Warning: be VERY careful to set this to one of the Term streams, NEVER
321 #: directly to sys.stdout/err, because under win32 the Term streams come from
321 #: directly to sys.stdout/err, because under win32 the Term streams come from
322 #: pyreadline and know how to handle color correctly, whie stdout/err don't.
322 #: pyreadline and know how to handle color correctly, whie stdout/err don't.
323 out_stream = Term.cerr
323 out_stream = Term.cerr
324
324
325 def __init__(self,color_scheme = 'NoColor',call_pdb=False):
325 def __init__(self,color_scheme = 'NoColor',call_pdb=False):
326 # Whether to call the interactive pdb debugger after printing
326 # Whether to call the interactive pdb debugger after printing
327 # tracebacks or not
327 # tracebacks or not
328 self.call_pdb = call_pdb
328 self.call_pdb = call_pdb
329
329
330 # Create color table
330 # Create color table
331 self.color_scheme_table = exception_colors()
331 self.color_scheme_table = exception_colors()
332
332
333 self.set_colors(color_scheme)
333 self.set_colors(color_scheme)
334 self.old_scheme = color_scheme # save initial value for toggles
334 self.old_scheme = color_scheme # save initial value for toggles
335
335
336 if call_pdb:
336 if call_pdb:
337 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
337 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
338 else:
338 else:
339 self.pdb = None
339 self.pdb = None
340
340
341 def set_colors(self,*args,**kw):
341 def set_colors(self,*args,**kw):
342 """Shorthand access to the color table scheme selector method."""
342 """Shorthand access to the color table scheme selector method."""
343
343
344 # Set own color table
344 # Set own color table
345 self.color_scheme_table.set_active_scheme(*args,**kw)
345 self.color_scheme_table.set_active_scheme(*args,**kw)
346 # for convenience, set Colors to the active scheme
346 # for convenience, set Colors to the active scheme
347 self.Colors = self.color_scheme_table.active_colors
347 self.Colors = self.color_scheme_table.active_colors
348 # Also set colors of debugger
348 # Also set colors of debugger
349 if hasattr(self,'pdb') and self.pdb is not None:
349 if hasattr(self,'pdb') and self.pdb is not None:
350 self.pdb.set_colors(*args,**kw)
350 self.pdb.set_colors(*args,**kw)
351
351
352 def color_toggle(self):
352 def color_toggle(self):
353 """Toggle between the currently active color scheme and NoColor."""
353 """Toggle between the currently active color scheme and NoColor."""
354
354
355 if self.color_scheme_table.active_scheme_name == 'NoColor':
355 if self.color_scheme_table.active_scheme_name == 'NoColor':
356 self.color_scheme_table.set_active_scheme(self.old_scheme)
356 self.color_scheme_table.set_active_scheme(self.old_scheme)
357 self.Colors = self.color_scheme_table.active_colors
357 self.Colors = self.color_scheme_table.active_colors
358 else:
358 else:
359 self.old_scheme = self.color_scheme_table.active_scheme_name
359 self.old_scheme = self.color_scheme_table.active_scheme_name
360 self.color_scheme_table.set_active_scheme('NoColor')
360 self.color_scheme_table.set_active_scheme('NoColor')
361 self.Colors = self.color_scheme_table.active_colors
361 self.Colors = self.color_scheme_table.active_colors
362
362
363 #---------------------------------------------------------------------------
363 #---------------------------------------------------------------------------
364 class ListTB(TBTools):
364 class ListTB(TBTools):
365 """Print traceback information from a traceback list, with optional color.
365 """Print traceback information from a traceback list, with optional color.
366
366
367 Calling: requires 3 arguments:
367 Calling: requires 3 arguments:
368 (etype, evalue, elist)
368 (etype, evalue, elist)
369 as would be obtained by:
369 as would be obtained by:
370 etype, evalue, tb = sys.exc_info()
370 etype, evalue, tb = sys.exc_info()
371 if tb:
371 if tb:
372 elist = traceback.extract_tb(tb)
372 elist = traceback.extract_tb(tb)
373 else:
373 else:
374 elist = None
374 elist = None
375
375
376 It can thus be used by programs which need to process the traceback before
376 It can thus be used by programs which need to process the traceback before
377 printing (such as console replacements based on the code module from the
377 printing (such as console replacements based on the code module from the
378 standard library).
378 standard library).
379
379
380 Because they are meant to be called without a full traceback (only a
380 Because they are meant to be called without a full traceback (only a
381 list), instances of this class can't call the interactive pdb debugger."""
381 list), instances of this class can't call the interactive pdb debugger."""
382
382
383 def __init__(self,color_scheme = 'NoColor'):
383 def __init__(self,color_scheme = 'NoColor'):
384 TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0)
384 TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0)
385
385
386 def __call__(self, etype, value, elist):
386 def __call__(self, etype, value, elist):
387 Term.cout.flush()
387 Term.cout.flush()
388 Term.cerr.writeln(self.text(etype,value,elist))
388 Term.cerr.write(self.text(etype,value,elist))
389 Term.cerr.write('\n')
389
390
390 def text(self, etype, value, elist, context=5):
391 def text(self, etype, value, elist, context=5):
391 """Return a color formatted string with the traceback info.
392 """Return a color formatted string with the traceback info.
392
393
393 Parameters
394 Parameters
394 ----------
395 ----------
395 etype : exception type
396 etype : exception type
396 Type of the exception raised.
397 Type of the exception raised.
397
398
398 value : object
399 value : object
399 Data stored in the exception
400 Data stored in the exception
400
401
401 elist : list
402 elist : list
402 List of frames, see class docstring for details.
403 List of frames, see class docstring for details.
403
404
404 Returns
405 Returns
405 -------
406 -------
406 String with formatted exception.
407 String with formatted exception.
407 """
408 """
408
409
409 Colors = self.Colors
410 Colors = self.Colors
410 out_string = []
411 out_string = []
411 if elist:
412 if elist:
412 out_string.append('Traceback %s(most recent call last)%s:' %
413 out_string.append('Traceback %s(most recent call last)%s:' %
413 (Colors.normalEm, Colors.Normal) + '\n')
414 (Colors.normalEm, Colors.Normal) + '\n')
414 out_string.extend(self._format_list(elist))
415 out_string.extend(self._format_list(elist))
415 lines = self._format_exception_only(etype, value)
416 lines = self._format_exception_only(etype, value)
416 for line in lines[:-1]:
417 for line in lines[:-1]:
417 out_string.append(" "+line)
418 out_string.append(" "+line)
418 out_string.append(lines[-1])
419 out_string.append(lines[-1])
419 return ''.join(out_string)
420 return ''.join(out_string)
420
421
421 def _format_list(self, extracted_list):
422 def _format_list(self, extracted_list):
422 """Format a list of traceback entry tuples for printing.
423 """Format a list of traceback entry tuples for printing.
423
424
424 Given a list of tuples as returned by extract_tb() or
425 Given a list of tuples as returned by extract_tb() or
425 extract_stack(), return a list of strings ready for printing.
426 extract_stack(), return a list of strings ready for printing.
426 Each string in the resulting list corresponds to the item with the
427 Each string in the resulting list corresponds to the item with the
427 same index in the argument list. Each string ends in a newline;
428 same index in the argument list. Each string ends in a newline;
428 the strings may contain internal newlines as well, for those items
429 the strings may contain internal newlines as well, for those items
429 whose source text line is not None.
430 whose source text line is not None.
430
431
431 Lifted almost verbatim from traceback.py
432 Lifted almost verbatim from traceback.py
432 """
433 """
433
434
434 Colors = self.Colors
435 Colors = self.Colors
435 list = []
436 list = []
436 for filename, lineno, name, line in extracted_list[:-1]:
437 for filename, lineno, name, line in extracted_list[:-1]:
437 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
438 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
438 (Colors.filename, filename, Colors.Normal,
439 (Colors.filename, filename, Colors.Normal,
439 Colors.lineno, lineno, Colors.Normal,
440 Colors.lineno, lineno, Colors.Normal,
440 Colors.name, name, Colors.Normal)
441 Colors.name, name, Colors.Normal)
441 if line:
442 if line:
442 item = item + ' %s\n' % line.strip()
443 item = item + ' %s\n' % line.strip()
443 list.append(item)
444 list.append(item)
444 # Emphasize the last entry
445 # Emphasize the last entry
445 filename, lineno, name, line = extracted_list[-1]
446 filename, lineno, name, line = extracted_list[-1]
446 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
447 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
447 (Colors.normalEm,
448 (Colors.normalEm,
448 Colors.filenameEm, filename, Colors.normalEm,
449 Colors.filenameEm, filename, Colors.normalEm,
449 Colors.linenoEm, lineno, Colors.normalEm,
450 Colors.linenoEm, lineno, Colors.normalEm,
450 Colors.nameEm, name, Colors.normalEm,
451 Colors.nameEm, name, Colors.normalEm,
451 Colors.Normal)
452 Colors.Normal)
452 if line:
453 if line:
453 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
454 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
454 Colors.Normal)
455 Colors.Normal)
455 list.append(item)
456 list.append(item)
456 return list
457 return list
457
458
458 def _format_exception_only(self, etype, value):
459 def _format_exception_only(self, etype, value):
459 """Format the exception part of a traceback.
460 """Format the exception part of a traceback.
460
461
461 The arguments are the exception type and value such as given by
462 The arguments are the exception type and value such as given by
462 sys.exc_info()[:2]. The return value is a list of strings, each ending
463 sys.exc_info()[:2]. The return value is a list of strings, each ending
463 in a newline. Normally, the list contains a single string; however,
464 in a newline. Normally, the list contains a single string; however,
464 for SyntaxError exceptions, it contains several lines that (when
465 for SyntaxError exceptions, it contains several lines that (when
465 printed) display detailed information about where the syntax error
466 printed) display detailed information about where the syntax error
466 occurred. The message indicating which exception occurred is the
467 occurred. The message indicating which exception occurred is the
467 always last string in the list.
468 always last string in the list.
468
469
469 Also lifted nearly verbatim from traceback.py
470 Also lifted nearly verbatim from traceback.py
470 """
471 """
471
472
472 have_filedata = False
473 have_filedata = False
473 Colors = self.Colors
474 Colors = self.Colors
474 list = []
475 list = []
475 try:
476 try:
476 stype = Colors.excName + etype.__name__ + Colors.Normal
477 stype = Colors.excName + etype.__name__ + Colors.Normal
477 except AttributeError:
478 except AttributeError:
478 stype = etype # String exceptions don't get special coloring
479 stype = etype # String exceptions don't get special coloring
479 if value is None:
480 if value is None:
480 list.append( str(stype) + '\n')
481 list.append( str(stype) + '\n')
481 else:
482 else:
482 if etype is SyntaxError:
483 if etype is SyntaxError:
483 try:
484 try:
484 msg, (filename, lineno, offset, line) = value
485 msg, (filename, lineno, offset, line) = value
485 except:
486 except:
486 have_filedata = False
487 have_filedata = False
487 else:
488 else:
488 have_filedata = True
489 have_filedata = True
489 #print 'filename is',filename # dbg
490 #print 'filename is',filename # dbg
490 if not filename: filename = "<string>"
491 if not filename: filename = "<string>"
491 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
492 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
492 (Colors.normalEm,
493 (Colors.normalEm,
493 Colors.filenameEm, filename, Colors.normalEm,
494 Colors.filenameEm, filename, Colors.normalEm,
494 Colors.linenoEm, lineno, Colors.Normal ))
495 Colors.linenoEm, lineno, Colors.Normal ))
495 if line is not None:
496 if line is not None:
496 i = 0
497 i = 0
497 while i < len(line) and line[i].isspace():
498 while i < len(line) and line[i].isspace():
498 i = i+1
499 i = i+1
499 list.append('%s %s%s\n' % (Colors.line,
500 list.append('%s %s%s\n' % (Colors.line,
500 line.strip(),
501 line.strip(),
501 Colors.Normal))
502 Colors.Normal))
502 if offset is not None:
503 if offset is not None:
503 s = ' '
504 s = ' '
504 for c in line[i:offset-1]:
505 for c in line[i:offset-1]:
505 if c.isspace():
506 if c.isspace():
506 s = s + c
507 s = s + c
507 else:
508 else:
508 s = s + ' '
509 s = s + ' '
509 list.append('%s%s^%s\n' % (Colors.caret, s,
510 list.append('%s%s^%s\n' % (Colors.caret, s,
510 Colors.Normal) )
511 Colors.Normal) )
511 value = msg
512 value = msg
512 s = self._some_str(value)
513 s = self._some_str(value)
513 if s:
514 if s:
514 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
515 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
515 Colors.Normal, s))
516 Colors.Normal, s))
516 else:
517 else:
517 list.append('%s\n' % str(stype))
518 list.append('%s\n' % str(stype))
518
519
519 # sync with user hooks
520 # sync with user hooks
520 if have_filedata:
521 if have_filedata:
521 ipinst = ipapi.get()
522 ipinst = ipapi.get()
522 if ipinst is not None:
523 if ipinst is not None:
523 ipinst.hooks.synchronize_with_editor(filename, lineno, 0)
524 ipinst.hooks.synchronize_with_editor(filename, lineno, 0)
524
525
525 return list
526 return list
526
527
527 def show_exception_only(self, etype, value):
528 def show_exception_only(self, etype, value):
528 """Only print the exception type and message, without a traceback.
529 """Only print the exception type and message, without a traceback.
529
530
530 Parameters
531 Parameters
531 ----------
532 ----------
532 etype : exception type
533 etype : exception type
533 value : exception value
534 value : exception value
534 """
535 """
535 # This method needs to use __call__ from *this* class, not the one from
536 # This method needs to use __call__ from *this* class, not the one from
536 # a subclass whose signature or behavior may be different
537 # a subclass whose signature or behavior may be different
537 Term.cout.flush()
538 Term.cout.flush()
538 ostream = sys.stdout if self.out_stream == 'stdout' else Term.cerr
539 ostream = sys.stdout if self.out_stream == 'stdout' else Term.cerr
539 ostream.write(ListTB.text(self, etype, value, []))
540 ostream.write(ListTB.text(self, etype, value, []))
540 ostream.flush()
541 ostream.flush()
541
542
542 def _some_str(self, value):
543 def _some_str(self, value):
543 # Lifted from traceback.py
544 # Lifted from traceback.py
544 try:
545 try:
545 return str(value)
546 return str(value)
546 except:
547 except:
547 return '<unprintable %s object>' % type(value).__name__
548 return '<unprintable %s object>' % type(value).__name__
548
549
549 #----------------------------------------------------------------------------
550 #----------------------------------------------------------------------------
550 class VerboseTB(TBTools):
551 class VerboseTB(TBTools):
551 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
552 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
552 of HTML. Requires inspect and pydoc. Crazy, man.
553 of HTML. Requires inspect and pydoc. Crazy, man.
553
554
554 Modified version which optionally strips the topmost entries from the
555 Modified version which optionally strips the topmost entries from the
555 traceback, to be used with alternate interpreters (because their own code
556 traceback, to be used with alternate interpreters (because their own code
556 would appear in the traceback)."""
557 would appear in the traceback)."""
557
558
558 def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0,
559 def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0,
559 call_pdb = 0, include_vars=1):
560 call_pdb = 0, include_vars=1):
560 """Specify traceback offset, headers and color scheme.
561 """Specify traceback offset, headers and color scheme.
561
562
562 Define how many frames to drop from the tracebacks. Calling it with
563 Define how many frames to drop from the tracebacks. Calling it with
563 tb_offset=1 allows use of this handler in interpreters which will have
564 tb_offset=1 allows use of this handler in interpreters which will have
564 their own code at the top of the traceback (VerboseTB will first
565 their own code at the top of the traceback (VerboseTB will first
565 remove that frame before printing the traceback info)."""
566 remove that frame before printing the traceback info)."""
566 TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb)
567 TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb)
567 self.tb_offset = tb_offset
568 self.tb_offset = tb_offset
568 self.long_header = long_header
569 self.long_header = long_header
569 self.include_vars = include_vars
570 self.include_vars = include_vars
570
571
571 def text(self, etype, evalue, etb, context=5):
572 def text(self, etype, evalue, etb, context=5):
572 """Return a nice text document describing the traceback."""
573 """Return a nice text document describing the traceback."""
573
574
574 # some locals
575 # some locals
575 try:
576 try:
576 etype = etype.__name__
577 etype = etype.__name__
577 except AttributeError:
578 except AttributeError:
578 pass
579 pass
579 Colors = self.Colors # just a shorthand + quicker name lookup
580 Colors = self.Colors # just a shorthand + quicker name lookup
580 ColorsNormal = Colors.Normal # used a lot
581 ColorsNormal = Colors.Normal # used a lot
581 col_scheme = self.color_scheme_table.active_scheme_name
582 col_scheme = self.color_scheme_table.active_scheme_name
582 indent = ' '*INDENT_SIZE
583 indent = ' '*INDENT_SIZE
583 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
584 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
584 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
585 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
585 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
586 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
586
587
587 # some internal-use functions
588 # some internal-use functions
588 def text_repr(value):
589 def text_repr(value):
589 """Hopefully pretty robust repr equivalent."""
590 """Hopefully pretty robust repr equivalent."""
590 # this is pretty horrible but should always return *something*
591 # this is pretty horrible but should always return *something*
591 try:
592 try:
592 return pydoc.text.repr(value)
593 return pydoc.text.repr(value)
593 except KeyboardInterrupt:
594 except KeyboardInterrupt:
594 raise
595 raise
595 except:
596 except:
596 try:
597 try:
597 return repr(value)
598 return repr(value)
598 except KeyboardInterrupt:
599 except KeyboardInterrupt:
599 raise
600 raise
600 except:
601 except:
601 try:
602 try:
602 # all still in an except block so we catch
603 # all still in an except block so we catch
603 # getattr raising
604 # getattr raising
604 name = getattr(value, '__name__', None)
605 name = getattr(value, '__name__', None)
605 if name:
606 if name:
606 # ick, recursion
607 # ick, recursion
607 return text_repr(name)
608 return text_repr(name)
608 klass = getattr(value, '__class__', None)
609 klass = getattr(value, '__class__', None)
609 if klass:
610 if klass:
610 return '%s instance' % text_repr(klass)
611 return '%s instance' % text_repr(klass)
611 except KeyboardInterrupt:
612 except KeyboardInterrupt:
612 raise
613 raise
613 except:
614 except:
614 return 'UNRECOVERABLE REPR FAILURE'
615 return 'UNRECOVERABLE REPR FAILURE'
615 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
616 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
616 def nullrepr(value, repr=text_repr): return ''
617 def nullrepr(value, repr=text_repr): return ''
617
618
618 # meat of the code begins
619 # meat of the code begins
619 try:
620 try:
620 etype = etype.__name__
621 etype = etype.__name__
621 except AttributeError:
622 except AttributeError:
622 pass
623 pass
623
624
624 if self.long_header:
625 if self.long_header:
625 # Header with the exception type, python version, and date
626 # Header with the exception type, python version, and date
626 pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable
627 pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable
627 date = time.ctime(time.time())
628 date = time.ctime(time.time())
628
629
629 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
630 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
630 exc, ' '*(75-len(str(etype))-len(pyver)),
631 exc, ' '*(75-len(str(etype))-len(pyver)),
631 pyver, string.rjust(date, 75) )
632 pyver, string.rjust(date, 75) )
632 head += "\nA problem occured executing Python code. Here is the sequence of function"\
633 head += "\nA problem occured executing Python code. Here is the sequence of function"\
633 "\ncalls leading up to the error, with the most recent (innermost) call last."
634 "\ncalls leading up to the error, with the most recent (innermost) call last."
634 else:
635 else:
635 # Simplified header
636 # Simplified header
636 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
637 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
637 string.rjust('Traceback (most recent call last)',
638 string.rjust('Traceback (most recent call last)',
638 75 - len(str(etype)) ) )
639 75 - len(str(etype)) ) )
639 frames = []
640 frames = []
640 # Flush cache before calling inspect. This helps alleviate some of the
641 # Flush cache before calling inspect. This helps alleviate some of the
641 # problems with python 2.3's inspect.py.
642 # problems with python 2.3's inspect.py.
642 linecache.checkcache()
643 linecache.checkcache()
643 # Drop topmost frames if requested
644 # Drop topmost frames if requested
644 try:
645 try:
645 # Try the default getinnerframes and Alex's: Alex's fixes some
646 # Try the default getinnerframes and Alex's: Alex's fixes some
646 # problems, but it generates empty tracebacks for console errors
647 # problems, but it generates empty tracebacks for console errors
647 # (5 blanks lines) where none should be returned.
648 # (5 blanks lines) where none should be returned.
648 #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
649 #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
649 #print 'python records:', records # dbg
650 #print 'python records:', records # dbg
650 records = _fixed_getinnerframes(etb, context,self.tb_offset)
651 records = _fixed_getinnerframes(etb, context,self.tb_offset)
651 #print 'alex records:', records # dbg
652 #print 'alex records:', records # dbg
652 except:
653 except:
653
654
654 # FIXME: I've been getting many crash reports from python 2.3
655 # FIXME: I've been getting many crash reports from python 2.3
655 # users, traceable to inspect.py. If I can find a small test-case
656 # users, traceable to inspect.py. If I can find a small test-case
656 # to reproduce this, I should either write a better workaround or
657 # to reproduce this, I should either write a better workaround or
657 # file a bug report against inspect (if that's the real problem).
658 # file a bug report against inspect (if that's the real problem).
658 # So far, I haven't been able to find an isolated example to
659 # So far, I haven't been able to find an isolated example to
659 # reproduce the problem.
660 # reproduce the problem.
660 inspect_error()
661 inspect_error()
661 traceback.print_exc(file=Term.cerr)
662 traceback.print_exc(file=Term.cerr)
662 info('\nUnfortunately, your original traceback can not be constructed.\n')
663 info('\nUnfortunately, your original traceback can not be constructed.\n')
663 return ''
664 return ''
664
665
665 # build some color string templates outside these nested loops
666 # build some color string templates outside these nested loops
666 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
667 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
667 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
668 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
668 ColorsNormal)
669 ColorsNormal)
669 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
670 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
670 (Colors.vName, Colors.valEm, ColorsNormal)
671 (Colors.vName, Colors.valEm, ColorsNormal)
671 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
672 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
672 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
673 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
673 Colors.vName, ColorsNormal)
674 Colors.vName, ColorsNormal)
674 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
675 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
675 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
676 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
676 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
677 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
677 ColorsNormal)
678 ColorsNormal)
678
679
679 # now, loop over all records printing context and info
680 # now, loop over all records printing context and info
680 abspath = os.path.abspath
681 abspath = os.path.abspath
681 for frame, file, lnum, func, lines, index in records:
682 for frame, file, lnum, func, lines, index in records:
682 #print '*** record:',file,lnum,func,lines,index # dbg
683 #print '*** record:',file,lnum,func,lines,index # dbg
683 try:
684 try:
684 file = file and abspath(file) or '?'
685 file = file and abspath(file) or '?'
685 except OSError:
686 except OSError:
686 # if file is '<console>' or something not in the filesystem,
687 # if file is '<console>' or something not in the filesystem,
687 # the abspath call will throw an OSError. Just ignore it and
688 # the abspath call will throw an OSError. Just ignore it and
688 # keep the original file string.
689 # keep the original file string.
689 pass
690 pass
690 link = tpl_link % file
691 link = tpl_link % file
691 try:
692 try:
692 args, varargs, varkw, locals = inspect.getargvalues(frame)
693 args, varargs, varkw, locals = inspect.getargvalues(frame)
693 except:
694 except:
694 # This can happen due to a bug in python2.3. We should be
695 # This can happen due to a bug in python2.3. We should be
695 # able to remove this try/except when 2.4 becomes a
696 # able to remove this try/except when 2.4 becomes a
696 # requirement. Bug details at http://python.org/sf/1005466
697 # requirement. Bug details at http://python.org/sf/1005466
697 inspect_error()
698 inspect_error()
698 traceback.print_exc(file=Term.cerr)
699 traceback.print_exc(file=Term.cerr)
699 info("\nIPython's exception reporting continues...\n")
700 info("\nIPython's exception reporting continues...\n")
700
701
701 if func == '?':
702 if func == '?':
702 call = ''
703 call = ''
703 else:
704 else:
704 # Decide whether to include variable details or not
705 # Decide whether to include variable details or not
705 var_repr = self.include_vars and eqrepr or nullrepr
706 var_repr = self.include_vars and eqrepr or nullrepr
706 try:
707 try:
707 call = tpl_call % (func,inspect.formatargvalues(args,
708 call = tpl_call % (func,inspect.formatargvalues(args,
708 varargs, varkw,
709 varargs, varkw,
709 locals,formatvalue=var_repr))
710 locals,formatvalue=var_repr))
710 except KeyError:
711 except KeyError:
711 # Very odd crash from inspect.formatargvalues(). The
712 # Very odd crash from inspect.formatargvalues(). The
712 # scenario under which it appeared was a call to
713 # scenario under which it appeared was a call to
713 # view(array,scale) in NumTut.view.view(), where scale had
714 # view(array,scale) in NumTut.view.view(), where scale had
714 # been defined as a scalar (it should be a tuple). Somehow
715 # been defined as a scalar (it should be a tuple). Somehow
715 # inspect messes up resolving the argument list of view()
716 # inspect messes up resolving the argument list of view()
716 # and barfs out. At some point I should dig into this one
717 # and barfs out. At some point I should dig into this one
717 # and file a bug report about it.
718 # and file a bug report about it.
718 inspect_error()
719 inspect_error()
719 traceback.print_exc(file=Term.cerr)
720 traceback.print_exc(file=Term.cerr)
720 info("\nIPython's exception reporting continues...\n")
721 info("\nIPython's exception reporting continues...\n")
721 call = tpl_call_fail % func
722 call = tpl_call_fail % func
722
723
723 # Initialize a list of names on the current line, which the
724 # Initialize a list of names on the current line, which the
724 # tokenizer below will populate.
725 # tokenizer below will populate.
725 names = []
726 names = []
726
727
727 def tokeneater(token_type, token, start, end, line):
728 def tokeneater(token_type, token, start, end, line):
728 """Stateful tokeneater which builds dotted names.
729 """Stateful tokeneater which builds dotted names.
729
730
730 The list of names it appends to (from the enclosing scope) can
731 The list of names it appends to (from the enclosing scope) can
731 contain repeated composite names. This is unavoidable, since
732 contain repeated composite names. This is unavoidable, since
732 there is no way to disambguate partial dotted structures until
733 there is no way to disambguate partial dotted structures until
733 the full list is known. The caller is responsible for pruning
734 the full list is known. The caller is responsible for pruning
734 the final list of duplicates before using it."""
735 the final list of duplicates before using it."""
735
736
736 # build composite names
737 # build composite names
737 if token == '.':
738 if token == '.':
738 try:
739 try:
739 names[-1] += '.'
740 names[-1] += '.'
740 # store state so the next token is added for x.y.z names
741 # store state so the next token is added for x.y.z names
741 tokeneater.name_cont = True
742 tokeneater.name_cont = True
742 return
743 return
743 except IndexError:
744 except IndexError:
744 pass
745 pass
745 if token_type == tokenize.NAME and token not in keyword.kwlist:
746 if token_type == tokenize.NAME and token not in keyword.kwlist:
746 if tokeneater.name_cont:
747 if tokeneater.name_cont:
747 # Dotted names
748 # Dotted names
748 names[-1] += token
749 names[-1] += token
749 tokeneater.name_cont = False
750 tokeneater.name_cont = False
750 else:
751 else:
751 # Regular new names. We append everything, the caller
752 # Regular new names. We append everything, the caller
752 # will be responsible for pruning the list later. It's
753 # will be responsible for pruning the list later. It's
753 # very tricky to try to prune as we go, b/c composite
754 # very tricky to try to prune as we go, b/c composite
754 # names can fool us. The pruning at the end is easy
755 # names can fool us. The pruning at the end is easy
755 # to do (or the caller can print a list with repeated
756 # to do (or the caller can print a list with repeated
756 # names if so desired.
757 # names if so desired.
757 names.append(token)
758 names.append(token)
758 elif token_type == tokenize.NEWLINE:
759 elif token_type == tokenize.NEWLINE:
759 raise IndexError
760 raise IndexError
760 # we need to store a bit of state in the tokenizer to build
761 # we need to store a bit of state in the tokenizer to build
761 # dotted names
762 # dotted names
762 tokeneater.name_cont = False
763 tokeneater.name_cont = False
763
764
764 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
765 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
765 line = getline(file, lnum[0])
766 line = getline(file, lnum[0])
766 lnum[0] += 1
767 lnum[0] += 1
767 return line
768 return line
768
769
769 # Build the list of names on this line of code where the exception
770 # Build the list of names on this line of code where the exception
770 # occurred.
771 # occurred.
771 try:
772 try:
772 # This builds the names list in-place by capturing it from the
773 # This builds the names list in-place by capturing it from the
773 # enclosing scope.
774 # enclosing scope.
774 tokenize.tokenize(linereader, tokeneater)
775 tokenize.tokenize(linereader, tokeneater)
775 except IndexError:
776 except IndexError:
776 # signals exit of tokenizer
777 # signals exit of tokenizer
777 pass
778 pass
778 except tokenize.TokenError,msg:
779 except tokenize.TokenError,msg:
779 _m = ("An unexpected error occurred while tokenizing input\n"
780 _m = ("An unexpected error occurred while tokenizing input\n"
780 "The following traceback may be corrupted or invalid\n"
781 "The following traceback may be corrupted or invalid\n"
781 "The error message is: %s\n" % msg)
782 "The error message is: %s\n" % msg)
782 error(_m)
783 error(_m)
783
784
784 # prune names list of duplicates, but keep the right order
785 # prune names list of duplicates, but keep the right order
785 unique_names = uniq_stable(names)
786 unique_names = uniq_stable(names)
786
787
787 # Start loop over vars
788 # Start loop over vars
788 lvals = []
789 lvals = []
789 if self.include_vars:
790 if self.include_vars:
790 for name_full in unique_names:
791 for name_full in unique_names:
791 name_base = name_full.split('.',1)[0]
792 name_base = name_full.split('.',1)[0]
792 if name_base in frame.f_code.co_varnames:
793 if name_base in frame.f_code.co_varnames:
793 if locals.has_key(name_base):
794 if locals.has_key(name_base):
794 try:
795 try:
795 value = repr(eval(name_full,locals))
796 value = repr(eval(name_full,locals))
796 except:
797 except:
797 value = undefined
798 value = undefined
798 else:
799 else:
799 value = undefined
800 value = undefined
800 name = tpl_local_var % name_full
801 name = tpl_local_var % name_full
801 else:
802 else:
802 if frame.f_globals.has_key(name_base):
803 if frame.f_globals.has_key(name_base):
803 try:
804 try:
804 value = repr(eval(name_full,frame.f_globals))
805 value = repr(eval(name_full,frame.f_globals))
805 except:
806 except:
806 value = undefined
807 value = undefined
807 else:
808 else:
808 value = undefined
809 value = undefined
809 name = tpl_global_var % name_full
810 name = tpl_global_var % name_full
810 lvals.append(tpl_name_val % (name,value))
811 lvals.append(tpl_name_val % (name,value))
811 if lvals:
812 if lvals:
812 lvals = '%s%s' % (indent,em_normal.join(lvals))
813 lvals = '%s%s' % (indent,em_normal.join(lvals))
813 else:
814 else:
814 lvals = ''
815 lvals = ''
815
816
816 level = '%s %s\n' % (link,call)
817 level = '%s %s\n' % (link,call)
817
818
818 if index is None:
819 if index is None:
819 frames.append(level)
820 frames.append(level)
820 else:
821 else:
821 frames.append('%s%s' % (level,''.join(
822 frames.append('%s%s' % (level,''.join(
822 _format_traceback_lines(lnum,index,lines,Colors,lvals,
823 _format_traceback_lines(lnum,index,lines,Colors,lvals,
823 col_scheme))))
824 col_scheme))))
824
825
825 # Get (safely) a string form of the exception info
826 # Get (safely) a string form of the exception info
826 try:
827 try:
827 etype_str,evalue_str = map(str,(etype,evalue))
828 etype_str,evalue_str = map(str,(etype,evalue))
828 except:
829 except:
829 # User exception is improperly defined.
830 # User exception is improperly defined.
830 etype,evalue = str,sys.exc_info()[:2]
831 etype,evalue = str,sys.exc_info()[:2]
831 etype_str,evalue_str = map(str,(etype,evalue))
832 etype_str,evalue_str = map(str,(etype,evalue))
832 # ... and format it
833 # ... and format it
833 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
834 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
834 ColorsNormal, evalue_str)]
835 ColorsNormal, evalue_str)]
835 if type(evalue) is types.InstanceType:
836 if type(evalue) is types.InstanceType:
836 try:
837 try:
837 names = [w for w in dir(evalue) if isinstance(w, basestring)]
838 names = [w for w in dir(evalue) if isinstance(w, basestring)]
838 except:
839 except:
839 # Every now and then, an object with funny inernals blows up
840 # Every now and then, an object with funny inernals blows up
840 # when dir() is called on it. We do the best we can to report
841 # when dir() is called on it. We do the best we can to report
841 # the problem and continue
842 # the problem and continue
842 _m = '%sException reporting error (object with broken dir())%s:'
843 _m = '%sException reporting error (object with broken dir())%s:'
843 exception.append(_m % (Colors.excName,ColorsNormal))
844 exception.append(_m % (Colors.excName,ColorsNormal))
844 etype_str,evalue_str = map(str,sys.exc_info()[:2])
845 etype_str,evalue_str = map(str,sys.exc_info()[:2])
845 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
846 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
846 ColorsNormal, evalue_str))
847 ColorsNormal, evalue_str))
847 names = []
848 names = []
848 for name in names:
849 for name in names:
849 value = text_repr(getattr(evalue, name))
850 value = text_repr(getattr(evalue, name))
850 exception.append('\n%s%s = %s' % (indent, name, value))
851 exception.append('\n%s%s = %s' % (indent, name, value))
851
852
852 # vds: >>
853 # vds: >>
853 if records:
854 if records:
854 filepath, lnum = records[-1][1:3]
855 filepath, lnum = records[-1][1:3]
855 #print "file:", str(file), "linenb", str(lnum) # dbg
856 #print "file:", str(file), "linenb", str(lnum) # dbg
856 filepath = os.path.abspath(filepath)
857 filepath = os.path.abspath(filepath)
857 ipinst = ipapi.get()
858 ipinst = ipapi.get()
858 if ipinst is not None:
859 if ipinst is not None:
859 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
860 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
860 # vds: <<
861 # vds: <<
861
862
862 # return all our info assembled as a single string
863 # return all our info assembled as a single string
863 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
864 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
864
865
865 def debugger(self,force=False):
866 def debugger(self,force=False):
866 """Call up the pdb debugger if desired, always clean up the tb
867 """Call up the pdb debugger if desired, always clean up the tb
867 reference.
868 reference.
868
869
869 Keywords:
870 Keywords:
870
871
871 - force(False): by default, this routine checks the instance call_pdb
872 - force(False): by default, this routine checks the instance call_pdb
872 flag and does not actually invoke the debugger if the flag is false.
873 flag and does not actually invoke the debugger if the flag is false.
873 The 'force' option forces the debugger to activate even if the flag
874 The 'force' option forces the debugger to activate even if the flag
874 is false.
875 is false.
875
876
876 If the call_pdb flag is set, the pdb interactive debugger is
877 If the call_pdb flag is set, the pdb interactive debugger is
877 invoked. In all cases, the self.tb reference to the current traceback
878 invoked. In all cases, the self.tb reference to the current traceback
878 is deleted to prevent lingering references which hamper memory
879 is deleted to prevent lingering references which hamper memory
879 management.
880 management.
880
881
881 Note that each call to pdb() does an 'import readline', so if your app
882 Note that each call to pdb() does an 'import readline', so if your app
882 requires a special setup for the readline completers, you'll have to
883 requires a special setup for the readline completers, you'll have to
883 fix that by hand after invoking the exception handler."""
884 fix that by hand after invoking the exception handler."""
884
885
885 if force or self.call_pdb:
886 if force or self.call_pdb:
886 if self.pdb is None:
887 if self.pdb is None:
887 self.pdb = debugger.Pdb(
888 self.pdb = debugger.Pdb(
888 self.color_scheme_table.active_scheme_name)
889 self.color_scheme_table.active_scheme_name)
889 # the system displayhook may have changed, restore the original
890 # the system displayhook may have changed, restore the original
890 # for pdb
891 # for pdb
891 display_trap = DisplayTrap(None, sys.__displayhook__)
892 display_trap = DisplayTrap(None, sys.__displayhook__)
892 with display_trap:
893 with display_trap:
893 self.pdb.reset()
894 self.pdb.reset()
894 # Find the right frame so we don't pop up inside ipython itself
895 # Find the right frame so we don't pop up inside ipython itself
895 if hasattr(self,'tb') and self.tb is not None:
896 if hasattr(self,'tb') and self.tb is not None:
896 etb = self.tb
897 etb = self.tb
897 else:
898 else:
898 etb = self.tb = sys.last_traceback
899 etb = self.tb = sys.last_traceback
899 while self.tb is not None and self.tb.tb_next is not None:
900 while self.tb is not None and self.tb.tb_next is not None:
900 self.tb = self.tb.tb_next
901 self.tb = self.tb.tb_next
901 if etb and etb.tb_next:
902 if etb and etb.tb_next:
902 etb = etb.tb_next
903 etb = etb.tb_next
903 self.pdb.botframe = etb.tb_frame
904 self.pdb.botframe = etb.tb_frame
904 self.pdb.interaction(self.tb.tb_frame, self.tb)
905 self.pdb.interaction(self.tb.tb_frame, self.tb)
905
906
906 if hasattr(self,'tb'):
907 if hasattr(self,'tb'):
907 del self.tb
908 del self.tb
908
909
909 def handler(self, info=None):
910 def handler(self, info=None):
910 (etype, evalue, etb) = info or sys.exc_info()
911 (etype, evalue, etb) = info or sys.exc_info()
911 self.tb = etb
912 self.tb = etb
912 Term.cout.flush()
913 Term.cout.flush()
913 Term.cerr.writeln(self.text(etype, evalue, etb))
914 Term.cerr.write(self.text(etype, evalue, etb))
915 Term.cerr.write('\n')
914
916
915 # Changed so an instance can just be called as VerboseTB_inst() and print
917 # Changed so an instance can just be called as VerboseTB_inst() and print
916 # out the right info on its own.
918 # out the right info on its own.
917 def __call__(self, etype=None, evalue=None, etb=None):
919 def __call__(self, etype=None, evalue=None, etb=None):
918 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
920 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
919 if etb is None:
921 if etb is None:
920 self.handler()
922 self.handler()
921 else:
923 else:
922 self.handler((etype, evalue, etb))
924 self.handler((etype, evalue, etb))
923 try:
925 try:
924 self.debugger()
926 self.debugger()
925 except KeyboardInterrupt:
927 except KeyboardInterrupt:
926 print "\nKeyboardInterrupt"
928 print "\nKeyboardInterrupt"
927
929
928 #----------------------------------------------------------------------------
930 #----------------------------------------------------------------------------
929 class FormattedTB(VerboseTB,ListTB):
931 class FormattedTB(VerboseTB,ListTB):
930 """Subclass ListTB but allow calling with a traceback.
932 """Subclass ListTB but allow calling with a traceback.
931
933
932 It can thus be used as a sys.excepthook for Python > 2.1.
934 It can thus be used as a sys.excepthook for Python > 2.1.
933
935
934 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
936 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
935
937
936 Allows a tb_offset to be specified. This is useful for situations where
938 Allows a tb_offset to be specified. This is useful for situations where
937 one needs to remove a number of topmost frames from the traceback (such as
939 one needs to remove a number of topmost frames from the traceback (such as
938 occurs with python programs that themselves execute other python code,
940 occurs with python programs that themselves execute other python code,
939 like Python shells). """
941 like Python shells). """
940
942
941 def __init__(self, mode = 'Plain', color_scheme='Linux',
943 def __init__(self, mode = 'Plain', color_scheme='Linux',
942 tb_offset = 0,long_header=0,call_pdb=0,include_vars=0):
944 tb_offset = 0,long_header=0,call_pdb=0,include_vars=0):
943
945
944 # NEVER change the order of this list. Put new modes at the end:
946 # NEVER change the order of this list. Put new modes at the end:
945 self.valid_modes = ['Plain','Context','Verbose']
947 self.valid_modes = ['Plain','Context','Verbose']
946 self.verbose_modes = self.valid_modes[1:3]
948 self.verbose_modes = self.valid_modes[1:3]
947
949
948 VerboseTB.__init__(self,color_scheme,tb_offset,long_header,
950 VerboseTB.__init__(self,color_scheme,tb_offset,long_header,
949 call_pdb=call_pdb,include_vars=include_vars)
951 call_pdb=call_pdb,include_vars=include_vars)
950 self.set_mode(mode)
952 self.set_mode(mode)
951
953
952 def _extract_tb(self,tb):
954 def _extract_tb(self,tb):
953 if tb:
955 if tb:
954 return traceback.extract_tb(tb)
956 return traceback.extract_tb(tb)
955 else:
957 else:
956 return None
958 return None
957
959
958 def text(self, etype, value, tb,context=5,mode=None):
960 def text(self, etype, value, tb,context=5,mode=None):
959 """Return formatted traceback.
961 """Return formatted traceback.
960
962
961 If the optional mode parameter is given, it overrides the current
963 If the optional mode parameter is given, it overrides the current
962 mode."""
964 mode."""
963
965
964 if mode is None:
966 if mode is None:
965 mode = self.mode
967 mode = self.mode
966 if mode in self.verbose_modes:
968 if mode in self.verbose_modes:
967 # verbose modes need a full traceback
969 # verbose modes need a full traceback
968 return VerboseTB.text(self,etype, value, tb,context=5)
970 return VerboseTB.text(self,etype, value, tb,context=5)
969 else:
971 else:
970 # We must check the source cache because otherwise we can print
972 # We must check the source cache because otherwise we can print
971 # out-of-date source code.
973 # out-of-date source code.
972 linecache.checkcache()
974 linecache.checkcache()
973 # Now we can extract and format the exception
975 # Now we can extract and format the exception
974 elist = self._extract_tb(tb)
976 elist = self._extract_tb(tb)
975 if len(elist) > self.tb_offset:
977 if len(elist) > self.tb_offset:
976 del elist[:self.tb_offset]
978 del elist[:self.tb_offset]
977 return ListTB.text(self,etype,value,elist)
979 return ListTB.text(self,etype,value,elist)
978
980
979 def set_mode(self,mode=None):
981 def set_mode(self,mode=None):
980 """Switch to the desired mode.
982 """Switch to the desired mode.
981
983
982 If mode is not specified, cycles through the available modes."""
984 If mode is not specified, cycles through the available modes."""
983
985
984 if not mode:
986 if not mode:
985 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
987 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
986 len(self.valid_modes)
988 len(self.valid_modes)
987 self.mode = self.valid_modes[new_idx]
989 self.mode = self.valid_modes[new_idx]
988 elif mode not in self.valid_modes:
990 elif mode not in self.valid_modes:
989 raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
991 raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
990 'Valid modes: '+str(self.valid_modes)
992 'Valid modes: '+str(self.valid_modes)
991 else:
993 else:
992 self.mode = mode
994 self.mode = mode
993 # include variable details only in 'Verbose' mode
995 # include variable details only in 'Verbose' mode
994 self.include_vars = (self.mode == self.valid_modes[2])
996 self.include_vars = (self.mode == self.valid_modes[2])
995
997
996 # some convenient shorcuts
998 # some convenient shorcuts
997 def plain(self):
999 def plain(self):
998 self.set_mode(self.valid_modes[0])
1000 self.set_mode(self.valid_modes[0])
999
1001
1000 def context(self):
1002 def context(self):
1001 self.set_mode(self.valid_modes[1])
1003 self.set_mode(self.valid_modes[1])
1002
1004
1003 def verbose(self):
1005 def verbose(self):
1004 self.set_mode(self.valid_modes[2])
1006 self.set_mode(self.valid_modes[2])
1005
1007
1006 #----------------------------------------------------------------------------
1008 #----------------------------------------------------------------------------
1007 class AutoFormattedTB(FormattedTB):
1009 class AutoFormattedTB(FormattedTB):
1008 """A traceback printer which can be called on the fly.
1010 """A traceback printer which can be called on the fly.
1009
1011
1010 It will find out about exceptions by itself.
1012 It will find out about exceptions by itself.
1011
1013
1012 A brief example:
1014 A brief example:
1013
1015
1014 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1016 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1015 try:
1017 try:
1016 ...
1018 ...
1017 except:
1019 except:
1018 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1020 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1019 """
1021 """
1020
1022
1021 def __call__(self,etype=None,evalue=None,etb=None,
1023 def __call__(self,etype=None,evalue=None,etb=None,
1022 out=None,tb_offset=None):
1024 out=None,tb_offset=None):
1023 """Print out a formatted exception traceback.
1025 """Print out a formatted exception traceback.
1024
1026
1025 Optional arguments:
1027 Optional arguments:
1026 - out: an open file-like object to direct output to.
1028 - out: an open file-like object to direct output to.
1027
1029
1028 - tb_offset: the number of frames to skip over in the stack, on a
1030 - tb_offset: the number of frames to skip over in the stack, on a
1029 per-call basis (this overrides temporarily the instance's tb_offset
1031 per-call basis (this overrides temporarily the instance's tb_offset
1030 given at initialization time. """
1032 given at initialization time. """
1031
1033
1032 if out is None:
1034 if out is None:
1033 out = sys.stdout if self.out_stream=='stdout' else self.out_stream
1035 out = sys.stdout if self.out_stream=='stdout' else self.out_stream
1034 Term.cout.flush()
1036 Term.cout.flush()
1035 if tb_offset is not None:
1037 if tb_offset is not None:
1036 tb_offset, self.tb_offset = self.tb_offset, tb_offset
1038 tb_offset, self.tb_offset = self.tb_offset, tb_offset
1037 out.write(self.text(etype, evalue, etb))
1039 out.write(self.text(etype, evalue, etb))
1038 out.write('\n')
1040 out.write('\n')
1039 self.tb_offset = tb_offset
1041 self.tb_offset = tb_offset
1040 else:
1042 else:
1041 out.write(self.text(etype, evalue, etb))
1043 out.write(self.text(etype, evalue, etb))
1042 out.write('\n')
1044 out.write('\n')
1043 out.flush()
1045 out.flush()
1044 try:
1046 try:
1045 self.debugger()
1047 self.debugger()
1046 except KeyboardInterrupt:
1048 except KeyboardInterrupt:
1047 print "\nKeyboardInterrupt"
1049 print "\nKeyboardInterrupt"
1048
1050
1049 def text(self,etype=None,value=None,tb=None,context=5,mode=None):
1051 def text(self,etype=None,value=None,tb=None,context=5,mode=None):
1050 if etype is None:
1052 if etype is None:
1051 etype,value,tb = sys.exc_info()
1053 etype,value,tb = sys.exc_info()
1052 self.tb = tb
1054 self.tb = tb
1053 return FormattedTB.text(self,etype,value,tb,context=5,mode=mode)
1055 return FormattedTB.text(self,etype,value,tb,context=5,mode=mode)
1054
1056
1055 #---------------------------------------------------------------------------
1057 #---------------------------------------------------------------------------
1056 # A simple class to preserve Nathan's original functionality.
1058 # A simple class to preserve Nathan's original functionality.
1057 class ColorTB(FormattedTB):
1059 class ColorTB(FormattedTB):
1058 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1060 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1059 def __init__(self,color_scheme='Linux',call_pdb=0):
1061 def __init__(self,color_scheme='Linux',call_pdb=0):
1060 FormattedTB.__init__(self,color_scheme=color_scheme,
1062 FormattedTB.__init__(self,color_scheme=color_scheme,
1061 call_pdb=call_pdb)
1063 call_pdb=call_pdb)
1062
1064
1063 #----------------------------------------------------------------------------
1065 #----------------------------------------------------------------------------
1064 # module testing (minimal)
1066 # module testing (minimal)
1065 if __name__ == "__main__":
1067 if __name__ == "__main__":
1066 def spam(c, (d, e)):
1068 def spam(c, (d, e)):
1067 x = c + d
1069 x = c + d
1068 y = c * d
1070 y = c * d
1069 foo(x, y)
1071 foo(x, y)
1070
1072
1071 def foo(a, b, bar=1):
1073 def foo(a, b, bar=1):
1072 eggs(a, b + bar)
1074 eggs(a, b + bar)
1073
1075
1074 def eggs(f, g, z=globals()):
1076 def eggs(f, g, z=globals()):
1075 h = f + g
1077 h = f + g
1076 i = f - g
1078 i = f - g
1077 return h / i
1079 return h / i
1078
1080
1079 print ''
1081 print ''
1080 print '*** Before ***'
1082 print '*** Before ***'
1081 try:
1083 try:
1082 print spam(1, (2, 3))
1084 print spam(1, (2, 3))
1083 except:
1085 except:
1084 traceback.print_exc()
1086 traceback.print_exc()
1085 print ''
1087 print ''
1086
1088
1087 handler = ColorTB()
1089 handler = ColorTB()
1088 print '*** ColorTB ***'
1090 print '*** ColorTB ***'
1089 try:
1091 try:
1090 print spam(1, (2, 3))
1092 print spam(1, (2, 3))
1091 except:
1093 except:
1092 apply(handler, sys.exc_info() )
1094 apply(handler, sys.exc_info() )
1093 print ''
1095 print ''
1094
1096
1095 handler = VerboseTB()
1097 handler = VerboseTB()
1096 print '*** VerboseTB ***'
1098 print '*** VerboseTB ***'
1097 try:
1099 try:
1098 print spam(1, (2, 3))
1100 print spam(1, (2, 3))
1099 except:
1101 except:
1100 apply(handler, sys.exc_info() )
1102 apply(handler, sys.exc_info() )
1101 print ''
1103 print ''
1102
1104
@@ -1,292 +1,292 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 IO related utilities.
3 IO related utilities.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2009 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import sys
17 import sys
18 import tempfile
18 import tempfile
19
19
20 from IPython.external.Itpl import itpl, printpl
20 from IPython.external.Itpl import itpl, printpl
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Code
23 # Code
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26
26
27 class IOStream:
27 class IOStream:
28
28
29 def __init__(self,stream,fallback):
29 def __init__(self,stream,fallback):
30 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
30 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
31 stream = fallback
31 stream = fallback
32 self.stream = stream
32 self.stream = stream
33 self._swrite = stream.write
33 self._swrite = stream.write
34 self.flush = stream.flush
34 self.flush = stream.flush
35
35
36 def write(self,data):
36 def write(self,data):
37 try:
37 try:
38 self._swrite(data)
38 self._swrite(data)
39 except:
39 except:
40 try:
40 try:
41 # print handles some unicode issues which may trip a plain
41 # print handles some unicode issues which may trip a plain
42 # write() call. Attempt to emulate write() by using a
42 # write() call. Attempt to emulate write() by using a
43 # trailing comma
43 # trailing comma
44 print >> self.stream, data,
44 print >> self.stream, data,
45 except:
45 except:
46 # if we get here, something is seriously broken.
46 # if we get here, something is seriously broken.
47 print >> sys.stderr, \
47 print >> sys.stderr, \
48 'ERROR - failed to write data to stream:', self.stream
48 'ERROR - failed to write data to stream:', self.stream
49
49
50 def writeln(self, data):
50 # This class used to have a writeln method, but regular files and streams
51 self.write(data)
51 # in Python don't have this method. We need to keep this completely
52 self.write('\n')
52 # compatible so we removed it.
53
53
54 def close(self):
54 def close(self):
55 pass
55 pass
56
56
57
57
58 class IOTerm:
58 class IOTerm:
59 """ Term holds the file or file-like objects for handling I/O operations.
59 """ Term holds the file or file-like objects for handling I/O operations.
60
60
61 These are normally just sys.stdin, sys.stdout and sys.stderr but for
61 These are normally just sys.stdin, sys.stdout and sys.stderr but for
62 Windows they can can replaced to allow editing the strings before they are
62 Windows they can can replaced to allow editing the strings before they are
63 displayed."""
63 displayed."""
64
64
65 # In the future, having IPython channel all its I/O operations through
65 # In the future, having IPython channel all its I/O operations through
66 # this class will make it easier to embed it into other environments which
66 # this class will make it easier to embed it into other environments which
67 # are not a normal terminal (such as a GUI-based shell)
67 # are not a normal terminal (such as a GUI-based shell)
68 def __init__(self,cin=None,cout=None,cerr=None):
68 def __init__(self,cin=None,cout=None,cerr=None):
69 self.cin = IOStream(cin,sys.stdin)
69 self.cin = IOStream(cin,sys.stdin)
70 self.cout = IOStream(cout,sys.stdout)
70 self.cout = IOStream(cout,sys.stdout)
71 self.cerr = IOStream(cerr,sys.stderr)
71 self.cerr = IOStream(cerr,sys.stderr)
72
72
73
73
74 # Global variable to be used for all I/O
74 # Global variable to be used for all I/O
75 Term = IOTerm()
75 Term = IOTerm()
76
76
77
77
78 import IPython.utils.rlineimpl as readline
78 import IPython.utils.rlineimpl as readline
79 # Remake Term to use the readline i/o facilities
79 # Remake Term to use the readline i/o facilities
80 if sys.platform == 'win32' and readline.have_readline:
80 if sys.platform == 'win32' and readline.have_readline:
81
81
82 Term = IOTerm(cout=readline._outputfile,cerr=readline._outputfile)
82 Term = IOTerm(cout=readline._outputfile,cerr=readline._outputfile)
83
83
84
84
85 class Tee(object):
85 class Tee(object):
86 """A class to duplicate an output stream to stdout/err.
86 """A class to duplicate an output stream to stdout/err.
87
87
88 This works in a manner very similar to the Unix 'tee' command.
88 This works in a manner very similar to the Unix 'tee' command.
89
89
90 When the object is closed or deleted, it closes the original file given to
90 When the object is closed or deleted, it closes the original file given to
91 it for duplication.
91 it for duplication.
92 """
92 """
93 # Inspired by:
93 # Inspired by:
94 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
94 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
95
95
96 def __init__(self, file_or_name, mode=None, channel='stdout'):
96 def __init__(self, file_or_name, mode=None, channel='stdout'):
97 """Construct a new Tee object.
97 """Construct a new Tee object.
98
98
99 Parameters
99 Parameters
100 ----------
100 ----------
101 file_or_name : filename or open filehandle (writable)
101 file_or_name : filename or open filehandle (writable)
102 File that will be duplicated
102 File that will be duplicated
103
103
104 mode : optional, valid mode for open().
104 mode : optional, valid mode for open().
105 If a filename was give, open with this mode.
105 If a filename was give, open with this mode.
106
106
107 channel : str, one of ['stdout', 'stderr']
107 channel : str, one of ['stdout', 'stderr']
108 """
108 """
109 if channel not in ['stdout', 'stderr']:
109 if channel not in ['stdout', 'stderr']:
110 raise ValueError('Invalid channel spec %s' % channel)
110 raise ValueError('Invalid channel spec %s' % channel)
111
111
112 if hasattr(file, 'write') and hasattr(file, 'seek'):
112 if hasattr(file, 'write') and hasattr(file, 'seek'):
113 self.file = file_or_name
113 self.file = file_or_name
114 else:
114 else:
115 self.file = open(file_or_name, mode)
115 self.file = open(file_or_name, mode)
116 self.channel = channel
116 self.channel = channel
117 self.ostream = getattr(sys, channel)
117 self.ostream = getattr(sys, channel)
118 setattr(sys, channel, self)
118 setattr(sys, channel, self)
119 self._closed = False
119 self._closed = False
120
120
121 def close(self):
121 def close(self):
122 """Close the file and restore the channel."""
122 """Close the file and restore the channel."""
123 self.flush()
123 self.flush()
124 setattr(sys, self.channel, self.ostream)
124 setattr(sys, self.channel, self.ostream)
125 self.file.close()
125 self.file.close()
126 self._closed = True
126 self._closed = True
127
127
128 def write(self, data):
128 def write(self, data):
129 """Write data to both channels."""
129 """Write data to both channels."""
130 self.file.write(data)
130 self.file.write(data)
131 self.ostream.write(data)
131 self.ostream.write(data)
132 self.ostream.flush()
132 self.ostream.flush()
133
133
134 def flush(self):
134 def flush(self):
135 """Flush both channels."""
135 """Flush both channels."""
136 self.file.flush()
136 self.file.flush()
137 self.ostream.flush()
137 self.ostream.flush()
138
138
139 def __del__(self):
139 def __del__(self):
140 if not self._closed:
140 if not self._closed:
141 self.close()
141 self.close()
142
142
143
143
144 def file_read(filename):
144 def file_read(filename):
145 """Read a file and close it. Returns the file source."""
145 """Read a file and close it. Returns the file source."""
146 fobj = open(filename,'r');
146 fobj = open(filename,'r');
147 source = fobj.read();
147 source = fobj.read();
148 fobj.close()
148 fobj.close()
149 return source
149 return source
150
150
151
151
152 def file_readlines(filename):
152 def file_readlines(filename):
153 """Read a file and close it. Returns the file source using readlines()."""
153 """Read a file and close it. Returns the file source using readlines()."""
154 fobj = open(filename,'r');
154 fobj = open(filename,'r');
155 lines = fobj.readlines();
155 lines = fobj.readlines();
156 fobj.close()
156 fobj.close()
157 return lines
157 return lines
158
158
159
159
160 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
160 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
161 """Take multiple lines of input.
161 """Take multiple lines of input.
162
162
163 A list with each line of input as a separate element is returned when a
163 A list with each line of input as a separate element is returned when a
164 termination string is entered (defaults to a single '.'). Input can also
164 termination string is entered (defaults to a single '.'). Input can also
165 terminate via EOF (^D in Unix, ^Z-RET in Windows).
165 terminate via EOF (^D in Unix, ^Z-RET in Windows).
166
166
167 Lines of input which end in \\ are joined into single entries (and a
167 Lines of input which end in \\ are joined into single entries (and a
168 secondary continuation prompt is issued as long as the user terminates
168 secondary continuation prompt is issued as long as the user terminates
169 lines with \\). This allows entering very long strings which are still
169 lines with \\). This allows entering very long strings which are still
170 meant to be treated as single entities.
170 meant to be treated as single entities.
171 """
171 """
172
172
173 try:
173 try:
174 if header:
174 if header:
175 header += '\n'
175 header += '\n'
176 lines = [raw_input(header + ps1)]
176 lines = [raw_input(header + ps1)]
177 except EOFError:
177 except EOFError:
178 return []
178 return []
179 terminate = [terminate_str]
179 terminate = [terminate_str]
180 try:
180 try:
181 while lines[-1:] != terminate:
181 while lines[-1:] != terminate:
182 new_line = raw_input(ps1)
182 new_line = raw_input(ps1)
183 while new_line.endswith('\\'):
183 while new_line.endswith('\\'):
184 new_line = new_line[:-1] + raw_input(ps2)
184 new_line = new_line[:-1] + raw_input(ps2)
185 lines.append(new_line)
185 lines.append(new_line)
186
186
187 return lines[:-1] # don't return the termination command
187 return lines[:-1] # don't return the termination command
188 except EOFError:
188 except EOFError:
189 print
189 print
190 return lines
190 return lines
191
191
192
192
193 def raw_input_ext(prompt='', ps2='... '):
193 def raw_input_ext(prompt='', ps2='... '):
194 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
194 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
195
195
196 line = raw_input(prompt)
196 line = raw_input(prompt)
197 while line.endswith('\\'):
197 while line.endswith('\\'):
198 line = line[:-1] + raw_input(ps2)
198 line = line[:-1] + raw_input(ps2)
199 return line
199 return line
200
200
201
201
202 def ask_yes_no(prompt,default=None):
202 def ask_yes_no(prompt,default=None):
203 """Asks a question and returns a boolean (y/n) answer.
203 """Asks a question and returns a boolean (y/n) answer.
204
204
205 If default is given (one of 'y','n'), it is used if the user input is
205 If default is given (one of 'y','n'), it is used if the user input is
206 empty. Otherwise the question is repeated until an answer is given.
206 empty. Otherwise the question is repeated until an answer is given.
207
207
208 An EOF is treated as the default answer. If there is no default, an
208 An EOF is treated as the default answer. If there is no default, an
209 exception is raised to prevent infinite loops.
209 exception is raised to prevent infinite loops.
210
210
211 Valid answers are: y/yes/n/no (match is not case sensitive)."""
211 Valid answers are: y/yes/n/no (match is not case sensitive)."""
212
212
213 answers = {'y':True,'n':False,'yes':True,'no':False}
213 answers = {'y':True,'n':False,'yes':True,'no':False}
214 ans = None
214 ans = None
215 while ans not in answers.keys():
215 while ans not in answers.keys():
216 try:
216 try:
217 ans = raw_input(prompt+' ').lower()
217 ans = raw_input(prompt+' ').lower()
218 if not ans: # response was an empty string
218 if not ans: # response was an empty string
219 ans = default
219 ans = default
220 except KeyboardInterrupt:
220 except KeyboardInterrupt:
221 pass
221 pass
222 except EOFError:
222 except EOFError:
223 if default in answers.keys():
223 if default in answers.keys():
224 ans = default
224 ans = default
225 print
225 print
226 else:
226 else:
227 raise
227 raise
228
228
229 return answers[ans]
229 return answers[ans]
230
230
231
231
232 class NLprinter:
232 class NLprinter:
233 """Print an arbitrarily nested list, indicating index numbers.
233 """Print an arbitrarily nested list, indicating index numbers.
234
234
235 An instance of this class called nlprint is available and callable as a
235 An instance of this class called nlprint is available and callable as a
236 function.
236 function.
237
237
238 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
238 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
239 and using 'sep' to separate the index from the value. """
239 and using 'sep' to separate the index from the value. """
240
240
241 def __init__(self):
241 def __init__(self):
242 self.depth = 0
242 self.depth = 0
243
243
244 def __call__(self,lst,pos='',**kw):
244 def __call__(self,lst,pos='',**kw):
245 """Prints the nested list numbering levels."""
245 """Prints the nested list numbering levels."""
246 kw.setdefault('indent',' ')
246 kw.setdefault('indent',' ')
247 kw.setdefault('sep',': ')
247 kw.setdefault('sep',': ')
248 kw.setdefault('start',0)
248 kw.setdefault('start',0)
249 kw.setdefault('stop',len(lst))
249 kw.setdefault('stop',len(lst))
250 # we need to remove start and stop from kw so they don't propagate
250 # we need to remove start and stop from kw so they don't propagate
251 # into a recursive call for a nested list.
251 # into a recursive call for a nested list.
252 start = kw['start']; del kw['start']
252 start = kw['start']; del kw['start']
253 stop = kw['stop']; del kw['stop']
253 stop = kw['stop']; del kw['stop']
254 if self.depth == 0 and 'header' in kw.keys():
254 if self.depth == 0 and 'header' in kw.keys():
255 print kw['header']
255 print kw['header']
256
256
257 for idx in range(start,stop):
257 for idx in range(start,stop):
258 elem = lst[idx]
258 elem = lst[idx]
259 if type(elem)==type([]):
259 if type(elem)==type([]):
260 self.depth += 1
260 self.depth += 1
261 self.__call__(elem,itpl('$pos$idx,'),**kw)
261 self.__call__(elem,itpl('$pos$idx,'),**kw)
262 self.depth -= 1
262 self.depth -= 1
263 else:
263 else:
264 printpl(kw['indent']*self.depth+'$pos$idx$kw["sep"]$elem')
264 printpl(kw['indent']*self.depth+'$pos$idx$kw["sep"]$elem')
265
265
266 nlprint = NLprinter()
266 nlprint = NLprinter()
267
267
268
268
269 def temp_pyfile(src, ext='.py'):
269 def temp_pyfile(src, ext='.py'):
270 """Make a temporary python file, return filename and filehandle.
270 """Make a temporary python file, return filename and filehandle.
271
271
272 Parameters
272 Parameters
273 ----------
273 ----------
274 src : string or list of strings (no need for ending newlines if list)
274 src : string or list of strings (no need for ending newlines if list)
275 Source code to be written to the file.
275 Source code to be written to the file.
276
276
277 ext : optional, string
277 ext : optional, string
278 Extension for the generated file.
278 Extension for the generated file.
279
279
280 Returns
280 Returns
281 -------
281 -------
282 (filename, open filehandle)
282 (filename, open filehandle)
283 It is the caller's responsibility to close the open file and unlink it.
283 It is the caller's responsibility to close the open file and unlink it.
284 """
284 """
285 fname = tempfile.mkstemp(ext)[1]
285 fname = tempfile.mkstemp(ext)[1]
286 f = open(fname,'w')
286 f = open(fname,'w')
287 f.write(src)
287 f.write(src)
288 f.flush()
288 f.flush()
289 return fname, f
289 return fname, f
290
290
291
291
292
292
General Comments 0
You need to be logged in to leave comments. Login now