##// END OF EJS Templates
Fixes for UltraTB and PyColorize with Python 3
Thomas Kluyver -
Show More
@@ -1,1243 +1,1249 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 sys
80 import sys
81 import time
81 import time
82 import tokenize
82 import tokenize
83 import traceback
83 import traceback
84 import types
84 import types
85
85
86 try: # Python 2
87 generate_tokens = tokenize.generate_tokens
88 except AttributeError: # Python 3
89 generate_tokens = tokenize.tokenize
90
86 # For purposes of monkeypatching inspect to fix a bug in it.
91 # For purposes of monkeypatching inspect to fix a bug in it.
87 from inspect import getsourcefile, getfile, getmodule,\
92 from inspect import getsourcefile, getfile, getmodule,\
88 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
93 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
89
94
90 # IPython's own modules
95 # IPython's own modules
91 # Modified pdb which doesn't damage IPython's readline handling
96 # Modified pdb which doesn't damage IPython's readline handling
92 from IPython.core import debugger, ipapi
97 from IPython.core import debugger, ipapi
93 from IPython.core.display_trap import DisplayTrap
98 from IPython.core.display_trap import DisplayTrap
94 from IPython.core.excolors import exception_colors
99 from IPython.core.excolors import exception_colors
95 from IPython.utils import PyColorize
100 from IPython.utils import PyColorize
96 from IPython.utils import io
101 from IPython.utils import io
102 from IPython.utils import py3compat
97 from IPython.utils.data import uniq_stable
103 from IPython.utils.data import uniq_stable
98 from IPython.utils.warn import info, error
104 from IPython.utils.warn import info, error
99
105
100 # Globals
106 # Globals
101 # amount of space to put line numbers before verbose tracebacks
107 # amount of space to put line numbers before verbose tracebacks
102 INDENT_SIZE = 8
108 INDENT_SIZE = 8
103
109
104 # Default color scheme. This is used, for example, by the traceback
110 # Default color scheme. This is used, for example, by the traceback
105 # formatter. When running in an actual IPython instance, the user's rc.colors
111 # formatter. When running in an actual IPython instance, the user's rc.colors
106 # value is used, but havinga module global makes this functionality available
112 # value is used, but havinga module global makes this functionality available
107 # to users of ultratb who are NOT running inside ipython.
113 # to users of ultratb who are NOT running inside ipython.
108 DEFAULT_SCHEME = 'NoColor'
114 DEFAULT_SCHEME = 'NoColor'
109
115
110 #---------------------------------------------------------------------------
116 #---------------------------------------------------------------------------
111 # Code begins
117 # Code begins
112
118
113 # Utility functions
119 # Utility functions
114 def inspect_error():
120 def inspect_error():
115 """Print a message about internal inspect errors.
121 """Print a message about internal inspect errors.
116
122
117 These are unfortunately quite common."""
123 These are unfortunately quite common."""
118
124
119 error('Internal Python error in the inspect module.\n'
125 error('Internal Python error in the inspect module.\n'
120 'Below is the traceback from this internal error.\n')
126 'Below is the traceback from this internal error.\n')
121
127
122
128
123 def findsource(object):
129 def findsource(object):
124 """Return the entire source file and starting line number for an object.
130 """Return the entire source file and starting line number for an object.
125
131
126 The argument may be a module, class, method, function, traceback, frame,
132 The argument may be a module, class, method, function, traceback, frame,
127 or code object. The source code is returned as a list of all the lines
133 or code object. The source code is returned as a list of all the lines
128 in the file and the line number indexes a line in that list. An IOError
134 in the file and the line number indexes a line in that list. An IOError
129 is raised if the source code cannot be retrieved.
135 is raised if the source code cannot be retrieved.
130
136
131 FIXED version with which we monkeypatch the stdlib to work around a bug."""
137 FIXED version with which we monkeypatch the stdlib to work around a bug."""
132
138
133 file = getsourcefile(object) or getfile(object)
139 file = getsourcefile(object) or getfile(object)
134 # If the object is a frame, then trying to get the globals dict from its
140 # If the object is a frame, then trying to get the globals dict from its
135 # module won't work. Instead, the frame object itself has the globals
141 # module won't work. Instead, the frame object itself has the globals
136 # dictionary.
142 # dictionary.
137 globals_dict = None
143 globals_dict = None
138 if inspect.isframe(object):
144 if inspect.isframe(object):
139 # XXX: can this ever be false?
145 # XXX: can this ever be false?
140 globals_dict = object.f_globals
146 globals_dict = object.f_globals
141 else:
147 else:
142 module = getmodule(object, file)
148 module = getmodule(object, file)
143 if module:
149 if module:
144 globals_dict = module.__dict__
150 globals_dict = module.__dict__
145 lines = linecache.getlines(file, globals_dict)
151 lines = linecache.getlines(file, globals_dict)
146 if not lines:
152 if not lines:
147 raise IOError('could not get source code')
153 raise IOError('could not get source code')
148
154
149 if ismodule(object):
155 if ismodule(object):
150 return lines, 0
156 return lines, 0
151
157
152 if isclass(object):
158 if isclass(object):
153 name = object.__name__
159 name = object.__name__
154 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
160 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
155 # make some effort to find the best matching class definition:
161 # make some effort to find the best matching class definition:
156 # use the one with the least indentation, which is the one
162 # use the one with the least indentation, which is the one
157 # that's most probably not inside a function definition.
163 # that's most probably not inside a function definition.
158 candidates = []
164 candidates = []
159 for i in range(len(lines)):
165 for i in range(len(lines)):
160 match = pat.match(lines[i])
166 match = pat.match(lines[i])
161 if match:
167 if match:
162 # if it's at toplevel, it's already the best one
168 # if it's at toplevel, it's already the best one
163 if lines[i][0] == 'c':
169 if lines[i][0] == 'c':
164 return lines, i
170 return lines, i
165 # else add whitespace to candidate list
171 # else add whitespace to candidate list
166 candidates.append((match.group(1), i))
172 candidates.append((match.group(1), i))
167 if candidates:
173 if candidates:
168 # this will sort by whitespace, and by line number,
174 # this will sort by whitespace, and by line number,
169 # less whitespace first
175 # less whitespace first
170 candidates.sort()
176 candidates.sort()
171 return lines, candidates[0][1]
177 return lines, candidates[0][1]
172 else:
178 else:
173 raise IOError('could not find class definition')
179 raise IOError('could not find class definition')
174
180
175 if ismethod(object):
181 if ismethod(object):
176 object = object.im_func
182 object = object.im_func
177 if isfunction(object):
183 if isfunction(object):
178 object = object.func_code
184 object = object.func_code
179 if istraceback(object):
185 if istraceback(object):
180 object = object.tb_frame
186 object = object.tb_frame
181 if isframe(object):
187 if isframe(object):
182 object = object.f_code
188 object = object.f_code
183 if iscode(object):
189 if iscode(object):
184 if not hasattr(object, 'co_firstlineno'):
190 if not hasattr(object, 'co_firstlineno'):
185 raise IOError('could not find function definition')
191 raise IOError('could not find function definition')
186 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
192 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
187 pmatch = pat.match
193 pmatch = pat.match
188 # fperez - fix: sometimes, co_firstlineno can give a number larger than
194 # fperez - fix: sometimes, co_firstlineno can give a number larger than
189 # the length of lines, which causes an error. Safeguard against that.
195 # the length of lines, which causes an error. Safeguard against that.
190 lnum = min(object.co_firstlineno,len(lines))-1
196 lnum = min(object.co_firstlineno,len(lines))-1
191 while lnum > 0:
197 while lnum > 0:
192 if pmatch(lines[lnum]): break
198 if pmatch(lines[lnum]): break
193 lnum -= 1
199 lnum -= 1
194
200
195 return lines, lnum
201 return lines, lnum
196 raise IOError('could not find code object')
202 raise IOError('could not find code object')
197
203
198 # Monkeypatch inspect to apply our bugfix. This code only works with py25
204 # Monkeypatch inspect to apply our bugfix. This code only works with py25
199 if sys.version_info[:2] >= (2,5):
205 if sys.version_info[:2] >= (2,5):
200 inspect.findsource = findsource
206 inspect.findsource = findsource
201
207
202 def fix_frame_records_filenames(records):
208 def fix_frame_records_filenames(records):
203 """Try to fix the filenames in each record from inspect.getinnerframes().
209 """Try to fix the filenames in each record from inspect.getinnerframes().
204
210
205 Particularly, modules loaded from within zip files have useless filenames
211 Particularly, modules loaded from within zip files have useless filenames
206 attached to their code object, and inspect.getinnerframes() just uses it.
212 attached to their code object, and inspect.getinnerframes() just uses it.
207 """
213 """
208 fixed_records = []
214 fixed_records = []
209 for frame, filename, line_no, func_name, lines, index in records:
215 for frame, filename, line_no, func_name, lines, index in records:
210 # Look inside the frame's globals dictionary for __file__, which should
216 # Look inside the frame's globals dictionary for __file__, which should
211 # be better.
217 # be better.
212 better_fn = frame.f_globals.get('__file__', None)
218 better_fn = frame.f_globals.get('__file__', None)
213 if isinstance(better_fn, str):
219 if isinstance(better_fn, str):
214 # Check the type just in case someone did something weird with
220 # Check the type just in case someone did something weird with
215 # __file__. It might also be None if the error occurred during
221 # __file__. It might also be None if the error occurred during
216 # import.
222 # import.
217 filename = better_fn
223 filename = better_fn
218 fixed_records.append((frame, filename, line_no, func_name, lines, index))
224 fixed_records.append((frame, filename, line_no, func_name, lines, index))
219 return fixed_records
225 return fixed_records
220
226
221
227
222 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
228 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
223 import linecache
229 import linecache
224 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
230 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
225
231
226 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
232 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
227
233
228 # If the error is at the console, don't build any context, since it would
234 # If the error is at the console, don't build any context, since it would
229 # otherwise produce 5 blank lines printed out (there is no file at the
235 # otherwise produce 5 blank lines printed out (there is no file at the
230 # console)
236 # console)
231 rec_check = records[tb_offset:]
237 rec_check = records[tb_offset:]
232 try:
238 try:
233 rname = rec_check[0][1]
239 rname = rec_check[0][1]
234 if rname == '<ipython console>' or rname.endswith('<string>'):
240 if rname == '<ipython console>' or rname.endswith('<string>'):
235 return rec_check
241 return rec_check
236 except IndexError:
242 except IndexError:
237 pass
243 pass
238
244
239 aux = traceback.extract_tb(etb)
245 aux = traceback.extract_tb(etb)
240 assert len(records) == len(aux)
246 assert len(records) == len(aux)
241 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
247 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
242 maybeStart = lnum-1 - context//2
248 maybeStart = lnum-1 - context//2
243 start = max(maybeStart, 0)
249 start = max(maybeStart, 0)
244 end = start + context
250 end = start + context
245 lines = linecache.getlines(file)[start:end]
251 lines = linecache.getlines(file)[start:end]
246 buf = list(records[i])
252 buf = list(records[i])
247 buf[LNUM_POS] = lnum
253 buf[LNUM_POS] = lnum
248 buf[INDEX_POS] = lnum - 1 - start
254 buf[INDEX_POS] = lnum - 1 - start
249 buf[LINES_POS] = lines
255 buf[LINES_POS] = lines
250 records[i] = tuple(buf)
256 records[i] = tuple(buf)
251 return records[tb_offset:]
257 return records[tb_offset:]
252
258
253 # Helper function -- largely belongs to VerboseTB, but we need the same
259 # Helper function -- largely belongs to VerboseTB, but we need the same
254 # 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
255 # 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
256 # (SyntaxErrors have to be treated specially because they have no traceback)
262 # (SyntaxErrors have to be treated specially because they have no traceback)
257
263
258 _parser = PyColorize.Parser()
264 _parser = PyColorize.Parser()
259
265
260 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):
261 numbers_width = INDENT_SIZE - 1
267 numbers_width = INDENT_SIZE - 1
262 res = []
268 res = []
263 i = lnum - index
269 i = lnum - index
264
270
265 # This lets us get fully syntax-highlighted tracebacks.
271 # This lets us get fully syntax-highlighted tracebacks.
266 if scheme is None:
272 if scheme is None:
267 ipinst = ipapi.get()
273 ipinst = ipapi.get()
268 if ipinst is not None:
274 if ipinst is not None:
269 scheme = ipinst.colors
275 scheme = ipinst.colors
270 else:
276 else:
271 scheme = DEFAULT_SCHEME
277 scheme = DEFAULT_SCHEME
272
278
273 _line_format = _parser.format2
279 _line_format = _parser.format2
274
280
275 for line in lines:
281 for line in lines:
276 # FIXME: we need to ensure the source is a pure string at this point,
282 # FIXME: we need to ensure the source is a pure string at this point,
277 # else the coloring code makes a royal mess. This is in need of a
283 # else the coloring code makes a royal mess. This is in need of a
278 # serious refactoring, so that all of the ultratb and PyColorize code
284 # serious refactoring, so that all of the ultratb and PyColorize code
279 # is unicode-safe. So for now this is rather an ugly hack, but
285 # is unicode-safe. So for now this is rather an ugly hack, but
280 # necessary to at least have readable tracebacks. Improvements welcome!
286 # necessary to at least have readable tracebacks. Improvements welcome!
281 if type(line)==unicode:
287 line = py3compat.cast_bytes_py2(line, 'utf-8')
282 line = line.encode('utf-8', 'replace')
283
288
284 new_line, err = _line_format(line, 'str', scheme)
289 new_line, err = _line_format(line, 'str', scheme)
285 if not err: line = new_line
290 if not err: line = new_line
286
291
287 if i == lnum:
292 if i == lnum:
288 # This is the line with the error
293 # This is the line with the error
289 pad = numbers_width - len(str(i))
294 pad = numbers_width - len(str(i))
290 if pad >= 3:
295 if pad >= 3:
291 marker = '-'*(pad-3) + '-> '
296 marker = '-'*(pad-3) + '-> '
292 elif pad == 2:
297 elif pad == 2:
293 marker = '> '
298 marker = '> '
294 elif pad == 1:
299 elif pad == 1:
295 marker = '>'
300 marker = '>'
296 else:
301 else:
297 marker = ''
302 marker = ''
298 num = marker + str(i)
303 num = marker + str(i)
299 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
304 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
300 Colors.line, line, Colors.Normal)
305 Colors.line, line, Colors.Normal)
301 else:
306 else:
302 num = '%*s' % (numbers_width,i)
307 num = '%*s' % (numbers_width,i)
303 line = '%s%s%s %s' %(Colors.lineno, num,
308 line = '%s%s%s %s' %(Colors.lineno, num,
304 Colors.Normal, line)
309 Colors.Normal, line)
305
310
306 res.append(line)
311 res.append(line)
307 if lvals and i == lnum:
312 if lvals and i == lnum:
308 res.append(lvals + '\n')
313 res.append(lvals + '\n')
309 i = i + 1
314 i = i + 1
310 return res
315 return res
311
316
312
317
313 #---------------------------------------------------------------------------
318 #---------------------------------------------------------------------------
314 # Module classes
319 # Module classes
315 class TBTools(object):
320 class TBTools(object):
316 """Basic tools used by all traceback printer classes."""
321 """Basic tools used by all traceback printer classes."""
317
322
318 # Number of frames to skip when reporting tracebacks
323 # Number of frames to skip when reporting tracebacks
319 tb_offset = 0
324 tb_offset = 0
320
325
321 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
326 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
322 # Whether to call the interactive pdb debugger after printing
327 # Whether to call the interactive pdb debugger after printing
323 # tracebacks or not
328 # tracebacks or not
324 self.call_pdb = call_pdb
329 self.call_pdb = call_pdb
325
330
326 # Output stream to write to. Note that we store the original value in
331 # Output stream to write to. Note that we store the original value in
327 # a private attribute and then make the public ostream a property, so
332 # a private attribute and then make the public ostream a property, so
328 # that we can delay accessing io.stdout until runtime. The way
333 # that we can delay accessing io.stdout until runtime. The way
329 # things are written now, the io.stdout object is dynamically managed
334 # things are written now, the io.stdout object is dynamically managed
330 # so a reference to it should NEVER be stored statically. This
335 # so a reference to it should NEVER be stored statically. This
331 # property approach confines this detail to a single location, and all
336 # property approach confines this detail to a single location, and all
332 # subclasses can simply access self.ostream for writing.
337 # subclasses can simply access self.ostream for writing.
333 self._ostream = ostream
338 self._ostream = ostream
334
339
335 # Create color table
340 # Create color table
336 self.color_scheme_table = exception_colors()
341 self.color_scheme_table = exception_colors()
337
342
338 self.set_colors(color_scheme)
343 self.set_colors(color_scheme)
339 self.old_scheme = color_scheme # save initial value for toggles
344 self.old_scheme = color_scheme # save initial value for toggles
340
345
341 if call_pdb:
346 if call_pdb:
342 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
347 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
343 else:
348 else:
344 self.pdb = None
349 self.pdb = None
345
350
346 def _get_ostream(self):
351 def _get_ostream(self):
347 """Output stream that exceptions are written to.
352 """Output stream that exceptions are written to.
348
353
349 Valid values are:
354 Valid values are:
350
355
351 - None: the default, which means that IPython will dynamically resolve
356 - None: the default, which means that IPython will dynamically resolve
352 to io.stdout. This ensures compatibility with most tools, including
357 to io.stdout. This ensures compatibility with most tools, including
353 Windows (where plain stdout doesn't recognize ANSI escapes).
358 Windows (where plain stdout doesn't recognize ANSI escapes).
354
359
355 - Any object with 'write' and 'flush' attributes.
360 - Any object with 'write' and 'flush' attributes.
356 """
361 """
357 return io.stdout if self._ostream is None else self._ostream
362 return io.stdout if self._ostream is None else self._ostream
358
363
359 def _set_ostream(self, val):
364 def _set_ostream(self, val):
360 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
365 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
361 self._ostream = val
366 self._ostream = val
362
367
363 ostream = property(_get_ostream, _set_ostream)
368 ostream = property(_get_ostream, _set_ostream)
364
369
365 def set_colors(self,*args,**kw):
370 def set_colors(self,*args,**kw):
366 """Shorthand access to the color table scheme selector method."""
371 """Shorthand access to the color table scheme selector method."""
367
372
368 # Set own color table
373 # Set own color table
369 self.color_scheme_table.set_active_scheme(*args,**kw)
374 self.color_scheme_table.set_active_scheme(*args,**kw)
370 # for convenience, set Colors to the active scheme
375 # for convenience, set Colors to the active scheme
371 self.Colors = self.color_scheme_table.active_colors
376 self.Colors = self.color_scheme_table.active_colors
372 # Also set colors of debugger
377 # Also set colors of debugger
373 if hasattr(self,'pdb') and self.pdb is not None:
378 if hasattr(self,'pdb') and self.pdb is not None:
374 self.pdb.set_colors(*args,**kw)
379 self.pdb.set_colors(*args,**kw)
375
380
376 def color_toggle(self):
381 def color_toggle(self):
377 """Toggle between the currently active color scheme and NoColor."""
382 """Toggle between the currently active color scheme and NoColor."""
378
383
379 if self.color_scheme_table.active_scheme_name == 'NoColor':
384 if self.color_scheme_table.active_scheme_name == 'NoColor':
380 self.color_scheme_table.set_active_scheme(self.old_scheme)
385 self.color_scheme_table.set_active_scheme(self.old_scheme)
381 self.Colors = self.color_scheme_table.active_colors
386 self.Colors = self.color_scheme_table.active_colors
382 else:
387 else:
383 self.old_scheme = self.color_scheme_table.active_scheme_name
388 self.old_scheme = self.color_scheme_table.active_scheme_name
384 self.color_scheme_table.set_active_scheme('NoColor')
389 self.color_scheme_table.set_active_scheme('NoColor')
385 self.Colors = self.color_scheme_table.active_colors
390 self.Colors = self.color_scheme_table.active_colors
386
391
387 def stb2text(self, stb):
392 def stb2text(self, stb):
388 """Convert a structured traceback (a list) to a string."""
393 """Convert a structured traceback (a list) to a string."""
389 return '\n'.join(stb)
394 return '\n'.join(stb)
390
395
391 def text(self, etype, value, tb, tb_offset=None, context=5):
396 def text(self, etype, value, tb, tb_offset=None, context=5):
392 """Return formatted traceback.
397 """Return formatted traceback.
393
398
394 Subclasses may override this if they add extra arguments.
399 Subclasses may override this if they add extra arguments.
395 """
400 """
396 tb_list = self.structured_traceback(etype, value, tb,
401 tb_list = self.structured_traceback(etype, value, tb,
397 tb_offset, context)
402 tb_offset, context)
398 return self.stb2text(tb_list)
403 return self.stb2text(tb_list)
399
404
400 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
405 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
401 context=5, mode=None):
406 context=5, mode=None):
402 """Return a list of traceback frames.
407 """Return a list of traceback frames.
403
408
404 Must be implemented by each class.
409 Must be implemented by each class.
405 """
410 """
406 raise NotImplementedError()
411 raise NotImplementedError()
407
412
408
413
409 #---------------------------------------------------------------------------
414 #---------------------------------------------------------------------------
410 class ListTB(TBTools):
415 class ListTB(TBTools):
411 """Print traceback information from a traceback list, with optional color.
416 """Print traceback information from a traceback list, with optional color.
412
417
413 Calling: requires 3 arguments:
418 Calling: requires 3 arguments:
414 (etype, evalue, elist)
419 (etype, evalue, elist)
415 as would be obtained by:
420 as would be obtained by:
416 etype, evalue, tb = sys.exc_info()
421 etype, evalue, tb = sys.exc_info()
417 if tb:
422 if tb:
418 elist = traceback.extract_tb(tb)
423 elist = traceback.extract_tb(tb)
419 else:
424 else:
420 elist = None
425 elist = None
421
426
422 It can thus be used by programs which need to process the traceback before
427 It can thus be used by programs which need to process the traceback before
423 printing (such as console replacements based on the code module from the
428 printing (such as console replacements based on the code module from the
424 standard library).
429 standard library).
425
430
426 Because they are meant to be called without a full traceback (only a
431 Because they are meant to be called without a full traceback (only a
427 list), instances of this class can't call the interactive pdb debugger."""
432 list), instances of this class can't call the interactive pdb debugger."""
428
433
429 def __init__(self,color_scheme = 'NoColor', call_pdb=False, ostream=None):
434 def __init__(self,color_scheme = 'NoColor', call_pdb=False, ostream=None):
430 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
435 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
431 ostream=ostream)
436 ostream=ostream)
432
437
433 def __call__(self, etype, value, elist):
438 def __call__(self, etype, value, elist):
434 self.ostream.flush()
439 self.ostream.flush()
435 self.ostream.write(self.text(etype, value, elist))
440 self.ostream.write(self.text(etype, value, elist))
436 self.ostream.write('\n')
441 self.ostream.write('\n')
437
442
438 def structured_traceback(self, etype, value, elist, tb_offset=None,
443 def structured_traceback(self, etype, value, elist, tb_offset=None,
439 context=5):
444 context=5):
440 """Return a color formatted string with the traceback info.
445 """Return a color formatted string with the traceback info.
441
446
442 Parameters
447 Parameters
443 ----------
448 ----------
444 etype : exception type
449 etype : exception type
445 Type of the exception raised.
450 Type of the exception raised.
446
451
447 value : object
452 value : object
448 Data stored in the exception
453 Data stored in the exception
449
454
450 elist : list
455 elist : list
451 List of frames, see class docstring for details.
456 List of frames, see class docstring for details.
452
457
453 tb_offset : int, optional
458 tb_offset : int, optional
454 Number of frames in the traceback to skip. If not given, the
459 Number of frames in the traceback to skip. If not given, the
455 instance value is used (set in constructor).
460 instance value is used (set in constructor).
456
461
457 context : int, optional
462 context : int, optional
458 Number of lines of context information to print.
463 Number of lines of context information to print.
459
464
460 Returns
465 Returns
461 -------
466 -------
462 String with formatted exception.
467 String with formatted exception.
463 """
468 """
464 tb_offset = self.tb_offset if tb_offset is None else tb_offset
469 tb_offset = self.tb_offset if tb_offset is None else tb_offset
465 Colors = self.Colors
470 Colors = self.Colors
466 out_list = []
471 out_list = []
467 if elist:
472 if elist:
468
473
469 if tb_offset and len(elist) > tb_offset:
474 if tb_offset and len(elist) > tb_offset:
470 elist = elist[tb_offset:]
475 elist = elist[tb_offset:]
471
476
472 out_list.append('Traceback %s(most recent call last)%s:' %
477 out_list.append('Traceback %s(most recent call last)%s:' %
473 (Colors.normalEm, Colors.Normal) + '\n')
478 (Colors.normalEm, Colors.Normal) + '\n')
474 out_list.extend(self._format_list(elist))
479 out_list.extend(self._format_list(elist))
475 # The exception info should be a single entry in the list.
480 # The exception info should be a single entry in the list.
476 lines = ''.join(self._format_exception_only(etype, value))
481 lines = ''.join(self._format_exception_only(etype, value))
477 out_list.append(lines)
482 out_list.append(lines)
478
483
479 # Note: this code originally read:
484 # Note: this code originally read:
480
485
481 ## for line in lines[:-1]:
486 ## for line in lines[:-1]:
482 ## out_list.append(" "+line)
487 ## out_list.append(" "+line)
483 ## out_list.append(lines[-1])
488 ## out_list.append(lines[-1])
484
489
485 # This means it was indenting everything but the last line by a little
490 # This means it was indenting everything but the last line by a little
486 # bit. I've disabled this for now, but if we see ugliness somewhre we
491 # bit. I've disabled this for now, but if we see ugliness somewhre we
487 # can restore it.
492 # can restore it.
488
493
489 return out_list
494 return out_list
490
495
491 def _format_list(self, extracted_list):
496 def _format_list(self, extracted_list):
492 """Format a list of traceback entry tuples for printing.
497 """Format a list of traceback entry tuples for printing.
493
498
494 Given a list of tuples as returned by extract_tb() or
499 Given a list of tuples as returned by extract_tb() or
495 extract_stack(), return a list of strings ready for printing.
500 extract_stack(), return a list of strings ready for printing.
496 Each string in the resulting list corresponds to the item with the
501 Each string in the resulting list corresponds to the item with the
497 same index in the argument list. Each string ends in a newline;
502 same index in the argument list. Each string ends in a newline;
498 the strings may contain internal newlines as well, for those items
503 the strings may contain internal newlines as well, for those items
499 whose source text line is not None.
504 whose source text line is not None.
500
505
501 Lifted almost verbatim from traceback.py
506 Lifted almost verbatim from traceback.py
502 """
507 """
503
508
504 Colors = self.Colors
509 Colors = self.Colors
505 list = []
510 list = []
506 for filename, lineno, name, line in extracted_list[:-1]:
511 for filename, lineno, name, line in extracted_list[:-1]:
507 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
512 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
508 (Colors.filename, filename, Colors.Normal,
513 (Colors.filename, filename, Colors.Normal,
509 Colors.lineno, lineno, Colors.Normal,
514 Colors.lineno, lineno, Colors.Normal,
510 Colors.name, name, Colors.Normal)
515 Colors.name, name, Colors.Normal)
511 if line:
516 if line:
512 item = item + ' %s\n' % line.strip()
517 item = item + ' %s\n' % line.strip()
513 list.append(item)
518 list.append(item)
514 # Emphasize the last entry
519 # Emphasize the last entry
515 filename, lineno, name, line = extracted_list[-1]
520 filename, lineno, name, line = extracted_list[-1]
516 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
521 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
517 (Colors.normalEm,
522 (Colors.normalEm,
518 Colors.filenameEm, filename, Colors.normalEm,
523 Colors.filenameEm, filename, Colors.normalEm,
519 Colors.linenoEm, lineno, Colors.normalEm,
524 Colors.linenoEm, lineno, Colors.normalEm,
520 Colors.nameEm, name, Colors.normalEm,
525 Colors.nameEm, name, Colors.normalEm,
521 Colors.Normal)
526 Colors.Normal)
522 if line:
527 if line:
523 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
528 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
524 Colors.Normal)
529 Colors.Normal)
525 list.append(item)
530 list.append(item)
526 #from pprint import pformat; print 'LISTTB', pformat(list) # dbg
531 #from pprint import pformat; print 'LISTTB', pformat(list) # dbg
527 return list
532 return list
528
533
529 def _format_exception_only(self, etype, value):
534 def _format_exception_only(self, etype, value):
530 """Format the exception part of a traceback.
535 """Format the exception part of a traceback.
531
536
532 The arguments are the exception type and value such as given by
537 The arguments are the exception type and value such as given by
533 sys.exc_info()[:2]. The return value is a list of strings, each ending
538 sys.exc_info()[:2]. The return value is a list of strings, each ending
534 in a newline. Normally, the list contains a single string; however,
539 in a newline. Normally, the list contains a single string; however,
535 for SyntaxError exceptions, it contains several lines that (when
540 for SyntaxError exceptions, it contains several lines that (when
536 printed) display detailed information about where the syntax error
541 printed) display detailed information about where the syntax error
537 occurred. The message indicating which exception occurred is the
542 occurred. The message indicating which exception occurred is the
538 always last string in the list.
543 always last string in the list.
539
544
540 Also lifted nearly verbatim from traceback.py
545 Also lifted nearly verbatim from traceback.py
541 """
546 """
542
547
543 have_filedata = False
548 have_filedata = False
544 Colors = self.Colors
549 Colors = self.Colors
545 list = []
550 list = []
546 try:
551 try:
547 stype = Colors.excName + etype.__name__ + Colors.Normal
552 stype = Colors.excName + etype.__name__ + Colors.Normal
548 except AttributeError:
553 except AttributeError:
549 stype = etype # String exceptions don't get special coloring
554 stype = etype # String exceptions don't get special coloring
550 if value is None:
555 if value is None:
551 list.append( str(stype) + '\n')
556 list.append( str(stype) + '\n')
552 else:
557 else:
553 if etype is SyntaxError:
558 if etype is SyntaxError:
554 try:
559 try:
555 msg, (filename, lineno, offset, line) = value
560 msg, (filename, lineno, offset, line) = value
556 except:
561 except:
557 have_filedata = False
562 have_filedata = False
558 else:
563 else:
559 have_filedata = True
564 have_filedata = True
560 #print 'filename is',filename # dbg
565 #print 'filename is',filename # dbg
561 if not filename: filename = "<string>"
566 if not filename: filename = "<string>"
562 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
567 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
563 (Colors.normalEm,
568 (Colors.normalEm,
564 Colors.filenameEm, filename, Colors.normalEm,
569 Colors.filenameEm, filename, Colors.normalEm,
565 Colors.linenoEm, lineno, Colors.Normal ))
570 Colors.linenoEm, lineno, Colors.Normal ))
566 if line is not None:
571 if line is not None:
567 i = 0
572 i = 0
568 while i < len(line) and line[i].isspace():
573 while i < len(line) and line[i].isspace():
569 i = i+1
574 i = i+1
570 list.append('%s %s%s\n' % (Colors.line,
575 list.append('%s %s%s\n' % (Colors.line,
571 line.strip(),
576 line.strip(),
572 Colors.Normal))
577 Colors.Normal))
573 if offset is not None:
578 if offset is not None:
574 s = ' '
579 s = ' '
575 for c in line[i:offset-1]:
580 for c in line[i:offset-1]:
576 if c.isspace():
581 if c.isspace():
577 s = s + c
582 s = s + c
578 else:
583 else:
579 s = s + ' '
584 s = s + ' '
580 list.append('%s%s^%s\n' % (Colors.caret, s,
585 list.append('%s%s^%s\n' % (Colors.caret, s,
581 Colors.Normal) )
586 Colors.Normal) )
582 value = msg
587 value = msg
583 s = self._some_str(value)
588 s = self._some_str(value)
584 if s:
589 if s:
585 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
590 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
586 Colors.Normal, s))
591 Colors.Normal, s))
587 else:
592 else:
588 list.append('%s\n' % str(stype))
593 list.append('%s\n' % str(stype))
589
594
590 # sync with user hooks
595 # sync with user hooks
591 if have_filedata:
596 if have_filedata:
592 ipinst = ipapi.get()
597 ipinst = ipapi.get()
593 if ipinst is not None:
598 if ipinst is not None:
594 ipinst.hooks.synchronize_with_editor(filename, lineno, 0)
599 ipinst.hooks.synchronize_with_editor(filename, lineno, 0)
595
600
596 return list
601 return list
597
602
598 def get_exception_only(self, etype, value):
603 def get_exception_only(self, etype, value):
599 """Only print the exception type and message, without a traceback.
604 """Only print the exception type and message, without a traceback.
600
605
601 Parameters
606 Parameters
602 ----------
607 ----------
603 etype : exception type
608 etype : exception type
604 value : exception value
609 value : exception value
605 """
610 """
606 return ListTB.structured_traceback(self, etype, value, [])
611 return ListTB.structured_traceback(self, etype, value, [])
607
612
608
613
609 def show_exception_only(self, etype, evalue):
614 def show_exception_only(self, etype, evalue):
610 """Only print the exception type and message, without a traceback.
615 """Only print the exception type and message, without a traceback.
611
616
612 Parameters
617 Parameters
613 ----------
618 ----------
614 etype : exception type
619 etype : exception type
615 value : exception value
620 value : exception value
616 """
621 """
617 # This method needs to use __call__ from *this* class, not the one from
622 # This method needs to use __call__ from *this* class, not the one from
618 # a subclass whose signature or behavior may be different
623 # a subclass whose signature or behavior may be different
619 ostream = self.ostream
624 ostream = self.ostream
620 ostream.flush()
625 ostream.flush()
621 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
626 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
622 ostream.flush()
627 ostream.flush()
623
628
624 def _some_str(self, value):
629 def _some_str(self, value):
625 # Lifted from traceback.py
630 # Lifted from traceback.py
626 try:
631 try:
627 return str(value)
632 return str(value)
628 except:
633 except:
629 return '<unprintable %s object>' % type(value).__name__
634 return '<unprintable %s object>' % type(value).__name__
630
635
631 #----------------------------------------------------------------------------
636 #----------------------------------------------------------------------------
632 class VerboseTB(TBTools):
637 class VerboseTB(TBTools):
633 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
638 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
634 of HTML. Requires inspect and pydoc. Crazy, man.
639 of HTML. Requires inspect and pydoc. Crazy, man.
635
640
636 Modified version which optionally strips the topmost entries from the
641 Modified version which optionally strips the topmost entries from the
637 traceback, to be used with alternate interpreters (because their own code
642 traceback, to be used with alternate interpreters (because their own code
638 would appear in the traceback)."""
643 would appear in the traceback)."""
639
644
640 def __init__(self,color_scheme = 'Linux', call_pdb=False, ostream=None,
645 def __init__(self,color_scheme = 'Linux', call_pdb=False, ostream=None,
641 tb_offset=0, long_header=False, include_vars=True,
646 tb_offset=0, long_header=False, include_vars=True,
642 check_cache=None):
647 check_cache=None):
643 """Specify traceback offset, headers and color scheme.
648 """Specify traceback offset, headers and color scheme.
644
649
645 Define how many frames to drop from the tracebacks. Calling it with
650 Define how many frames to drop from the tracebacks. Calling it with
646 tb_offset=1 allows use of this handler in interpreters which will have
651 tb_offset=1 allows use of this handler in interpreters which will have
647 their own code at the top of the traceback (VerboseTB will first
652 their own code at the top of the traceback (VerboseTB will first
648 remove that frame before printing the traceback info)."""
653 remove that frame before printing the traceback info)."""
649 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
654 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
650 ostream=ostream)
655 ostream=ostream)
651 self.tb_offset = tb_offset
656 self.tb_offset = tb_offset
652 self.long_header = long_header
657 self.long_header = long_header
653 self.include_vars = include_vars
658 self.include_vars = include_vars
654 # By default we use linecache.checkcache, but the user can provide a
659 # By default we use linecache.checkcache, but the user can provide a
655 # different check_cache implementation. This is used by the IPython
660 # different check_cache implementation. This is used by the IPython
656 # kernel to provide tracebacks for interactive code that is cached,
661 # kernel to provide tracebacks for interactive code that is cached,
657 # by a compiler instance that flushes the linecache but preserves its
662 # by a compiler instance that flushes the linecache but preserves its
658 # own code cache.
663 # own code cache.
659 if check_cache is None:
664 if check_cache is None:
660 check_cache = linecache.checkcache
665 check_cache = linecache.checkcache
661 self.check_cache = check_cache
666 self.check_cache = check_cache
662
667
663 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
668 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
664 context=5):
669 context=5):
665 """Return a nice text document describing the traceback."""
670 """Return a nice text document describing the traceback."""
666
671
667 tb_offset = self.tb_offset if tb_offset is None else tb_offset
672 tb_offset = self.tb_offset if tb_offset is None else tb_offset
668
673
669 # some locals
674 # some locals
670 try:
675 try:
671 etype = etype.__name__
676 etype = etype.__name__
672 except AttributeError:
677 except AttributeError:
673 pass
678 pass
674 Colors = self.Colors # just a shorthand + quicker name lookup
679 Colors = self.Colors # just a shorthand + quicker name lookup
675 ColorsNormal = Colors.Normal # used a lot
680 ColorsNormal = Colors.Normal # used a lot
676 col_scheme = self.color_scheme_table.active_scheme_name
681 col_scheme = self.color_scheme_table.active_scheme_name
677 indent = ' '*INDENT_SIZE
682 indent = ' '*INDENT_SIZE
678 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
683 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
679 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
684 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
680 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
685 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
681
686
682 # some internal-use functions
687 # some internal-use functions
683 def text_repr(value):
688 def text_repr(value):
684 """Hopefully pretty robust repr equivalent."""
689 """Hopefully pretty robust repr equivalent."""
685 # this is pretty horrible but should always return *something*
690 # this is pretty horrible but should always return *something*
686 try:
691 try:
687 return pydoc.text.repr(value)
692 return pydoc.text.repr(value)
688 except KeyboardInterrupt:
693 except KeyboardInterrupt:
689 raise
694 raise
690 except:
695 except:
691 try:
696 try:
692 return repr(value)
697 return repr(value)
693 except KeyboardInterrupt:
698 except KeyboardInterrupt:
694 raise
699 raise
695 except:
700 except:
696 try:
701 try:
697 # all still in an except block so we catch
702 # all still in an except block so we catch
698 # getattr raising
703 # getattr raising
699 name = getattr(value, '__name__', None)
704 name = getattr(value, '__name__', None)
700 if name:
705 if name:
701 # ick, recursion
706 # ick, recursion
702 return text_repr(name)
707 return text_repr(name)
703 klass = getattr(value, '__class__', None)
708 klass = getattr(value, '__class__', None)
704 if klass:
709 if klass:
705 return '%s instance' % text_repr(klass)
710 return '%s instance' % text_repr(klass)
706 except KeyboardInterrupt:
711 except KeyboardInterrupt:
707 raise
712 raise
708 except:
713 except:
709 return 'UNRECOVERABLE REPR FAILURE'
714 return 'UNRECOVERABLE REPR FAILURE'
710 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
715 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
711 def nullrepr(value, repr=text_repr): return ''
716 def nullrepr(value, repr=text_repr): return ''
712
717
713 # meat of the code begins
718 # meat of the code begins
714 try:
719 try:
715 etype = etype.__name__
720 etype = etype.__name__
716 except AttributeError:
721 except AttributeError:
717 pass
722 pass
718
723
719 if self.long_header:
724 if self.long_header:
720 # Header with the exception type, python version, and date
725 # Header with the exception type, python version, and date
721 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
726 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
722 date = time.ctime(time.time())
727 date = time.ctime(time.time())
723
728
724 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
729 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
725 exc, ' '*(75-len(str(etype))-len(pyver)),
730 exc, ' '*(75-len(str(etype))-len(pyver)),
726 pyver, date.rjust(75) )
731 pyver, date.rjust(75) )
727 head += "\nA problem occured executing Python code. Here is the sequence of function"\
732 head += "\nA problem occured executing Python code. Here is the sequence of function"\
728 "\ncalls leading up to the error, with the most recent (innermost) call last."
733 "\ncalls leading up to the error, with the most recent (innermost) call last."
729 else:
734 else:
730 # Simplified header
735 # Simplified header
731 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
736 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
732 'Traceback (most recent call last)'.\
737 'Traceback (most recent call last)'.\
733 rjust(75 - len(str(etype)) ) )
738 rjust(75 - len(str(etype)) ) )
734 frames = []
739 frames = []
735 # Flush cache before calling inspect. This helps alleviate some of the
740 # Flush cache before calling inspect. This helps alleviate some of the
736 # problems with python 2.3's inspect.py.
741 # problems with python 2.3's inspect.py.
737 ##self.check_cache()
742 ##self.check_cache()
738 # Drop topmost frames if requested
743 # Drop topmost frames if requested
739 try:
744 try:
740 # Try the default getinnerframes and Alex's: Alex's fixes some
745 # Try the default getinnerframes and Alex's: Alex's fixes some
741 # problems, but it generates empty tracebacks for console errors
746 # problems, but it generates empty tracebacks for console errors
742 # (5 blanks lines) where none should be returned.
747 # (5 blanks lines) where none should be returned.
743 #records = inspect.getinnerframes(etb, context)[tb_offset:]
748 #records = inspect.getinnerframes(etb, context)[tb_offset:]
744 #print 'python records:', records # dbg
749 #print 'python records:', records # dbg
745 records = _fixed_getinnerframes(etb, context, tb_offset)
750 records = _fixed_getinnerframes(etb, context, tb_offset)
746 #print 'alex records:', records # dbg
751 #print 'alex records:', records # dbg
747 except:
752 except:
748
753
749 # FIXME: I've been getting many crash reports from python 2.3
754 # FIXME: I've been getting many crash reports from python 2.3
750 # users, traceable to inspect.py. If I can find a small test-case
755 # users, traceable to inspect.py. If I can find a small test-case
751 # to reproduce this, I should either write a better workaround or
756 # to reproduce this, I should either write a better workaround or
752 # file a bug report against inspect (if that's the real problem).
757 # file a bug report against inspect (if that's the real problem).
753 # So far, I haven't been able to find an isolated example to
758 # So far, I haven't been able to find an isolated example to
754 # reproduce the problem.
759 # reproduce the problem.
755 inspect_error()
760 inspect_error()
756 traceback.print_exc(file=self.ostream)
761 traceback.print_exc(file=self.ostream)
757 info('\nUnfortunately, your original traceback can not be constructed.\n')
762 info('\nUnfortunately, your original traceback can not be constructed.\n')
758 return ''
763 return ''
759
764
760 # build some color string templates outside these nested loops
765 # build some color string templates outside these nested loops
761 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
766 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
762 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
767 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
763 ColorsNormal)
768 ColorsNormal)
764 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
769 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
765 (Colors.vName, Colors.valEm, ColorsNormal)
770 (Colors.vName, Colors.valEm, ColorsNormal)
766 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
771 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
767 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
772 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
768 Colors.vName, ColorsNormal)
773 Colors.vName, ColorsNormal)
769 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
774 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
770 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
775 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
771 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
776 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
772 ColorsNormal)
777 ColorsNormal)
773
778
774 # now, loop over all records printing context and info
779 # now, loop over all records printing context and info
775 abspath = os.path.abspath
780 abspath = os.path.abspath
776 for frame, file, lnum, func, lines, index in records:
781 for frame, file, lnum, func, lines, index in records:
777 #print '*** record:',file,lnum,func,lines,index # dbg
782 #print '*** record:',file,lnum,func,lines,index # dbg
778 try:
783 try:
779 file = file and abspath(file) or '?'
784 file = file and abspath(file) or '?'
780 except OSError:
785 except OSError:
781 # if file is '<console>' or something not in the filesystem,
786 # if file is '<console>' or something not in the filesystem,
782 # the abspath call will throw an OSError. Just ignore it and
787 # the abspath call will throw an OSError. Just ignore it and
783 # keep the original file string.
788 # keep the original file string.
784 pass
789 pass
785 link = tpl_link % file
790 link = tpl_link % file
786 try:
791 try:
787 args, varargs, varkw, locals = inspect.getargvalues(frame)
792 args, varargs, varkw, locals = inspect.getargvalues(frame)
788 except:
793 except:
789 # This can happen due to a bug in python2.3. We should be
794 # This can happen due to a bug in python2.3. We should be
790 # able to remove this try/except when 2.4 becomes a
795 # able to remove this try/except when 2.4 becomes a
791 # requirement. Bug details at http://python.org/sf/1005466
796 # requirement. Bug details at http://python.org/sf/1005466
792 inspect_error()
797 inspect_error()
793 traceback.print_exc(file=self.ostream)
798 traceback.print_exc(file=self.ostream)
794 info("\nIPython's exception reporting continues...\n")
799 info("\nIPython's exception reporting continues...\n")
795
800
796 if func == '?':
801 if func == '?':
797 call = ''
802 call = ''
798 else:
803 else:
799 # Decide whether to include variable details or not
804 # Decide whether to include variable details or not
800 var_repr = self.include_vars and eqrepr or nullrepr
805 var_repr = self.include_vars and eqrepr or nullrepr
801 try:
806 try:
802 call = tpl_call % (func,inspect.formatargvalues(args,
807 call = tpl_call % (func,inspect.formatargvalues(args,
803 varargs, varkw,
808 varargs, varkw,
804 locals,formatvalue=var_repr))
809 locals,formatvalue=var_repr))
805 except KeyError:
810 except KeyError:
806 # This happens in situations like errors inside generator
811 # This happens in situations like errors inside generator
807 # expressions, where local variables are listed in the
812 # expressions, where local variables are listed in the
808 # line, but can't be extracted from the frame. I'm not
813 # line, but can't be extracted from the frame. I'm not
809 # 100% sure this isn't actually a bug in inspect itself,
814 # 100% sure this isn't actually a bug in inspect itself,
810 # but since there's no info for us to compute with, the
815 # but since there's no info for us to compute with, the
811 # best we can do is report the failure and move on. Here
816 # best we can do is report the failure and move on. Here
812 # we must *not* call any traceback construction again,
817 # we must *not* call any traceback construction again,
813 # because that would mess up use of %debug later on. So we
818 # because that would mess up use of %debug later on. So we
814 # simply report the failure and move on. The only
819 # simply report the failure and move on. The only
815 # limitation will be that this frame won't have locals
820 # limitation will be that this frame won't have locals
816 # listed in the call signature. Quite subtle problem...
821 # listed in the call signature. Quite subtle problem...
817 # I can't think of a good way to validate this in a unit
822 # I can't think of a good way to validate this in a unit
818 # test, but running a script consisting of:
823 # test, but running a script consisting of:
819 # dict( (k,v.strip()) for (k,v) in range(10) )
824 # dict( (k,v.strip()) for (k,v) in range(10) )
820 # will illustrate the error, if this exception catch is
825 # will illustrate the error, if this exception catch is
821 # disabled.
826 # disabled.
822 call = tpl_call_fail % func
827 call = tpl_call_fail % func
823
828
824 # Initialize a list of names on the current line, which the
829 # Initialize a list of names on the current line, which the
825 # tokenizer below will populate.
830 # tokenizer below will populate.
826 names = []
831 names = []
827
832
828 def tokeneater(token_type, token, start, end, line):
833 def tokeneater(token_type, token, start, end, line):
829 """Stateful tokeneater which builds dotted names.
834 """Stateful tokeneater which builds dotted names.
830
835
831 The list of names it appends to (from the enclosing scope) can
836 The list of names it appends to (from the enclosing scope) can
832 contain repeated composite names. This is unavoidable, since
837 contain repeated composite names. This is unavoidable, since
833 there is no way to disambguate partial dotted structures until
838 there is no way to disambguate partial dotted structures until
834 the full list is known. The caller is responsible for pruning
839 the full list is known. The caller is responsible for pruning
835 the final list of duplicates before using it."""
840 the final list of duplicates before using it."""
836
841
837 # build composite names
842 # build composite names
838 if token == '.':
843 if token == '.':
839 try:
844 try:
840 names[-1] += '.'
845 names[-1] += '.'
841 # store state so the next token is added for x.y.z names
846 # store state so the next token is added for x.y.z names
842 tokeneater.name_cont = True
847 tokeneater.name_cont = True
843 return
848 return
844 except IndexError:
849 except IndexError:
845 pass
850 pass
846 if token_type == tokenize.NAME and token not in keyword.kwlist:
851 if token_type == tokenize.NAME and token not in keyword.kwlist:
847 if tokeneater.name_cont:
852 if tokeneater.name_cont:
848 # Dotted names
853 # Dotted names
849 names[-1] += token
854 names[-1] += token
850 tokeneater.name_cont = False
855 tokeneater.name_cont = False
851 else:
856 else:
852 # Regular new names. We append everything, the caller
857 # Regular new names. We append everything, the caller
853 # will be responsible for pruning the list later. It's
858 # will be responsible for pruning the list later. It's
854 # very tricky to try to prune as we go, b/c composite
859 # very tricky to try to prune as we go, b/c composite
855 # names can fool us. The pruning at the end is easy
860 # names can fool us. The pruning at the end is easy
856 # to do (or the caller can print a list with repeated
861 # to do (or the caller can print a list with repeated
857 # names if so desired.
862 # names if so desired.
858 names.append(token)
863 names.append(token)
859 elif token_type == tokenize.NEWLINE:
864 elif token_type == tokenize.NEWLINE:
860 raise IndexError
865 raise IndexError
861 # we need to store a bit of state in the tokenizer to build
866 # we need to store a bit of state in the tokenizer to build
862 # dotted names
867 # dotted names
863 tokeneater.name_cont = False
868 tokeneater.name_cont = False
864
869
865 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
870 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
866 line = getline(file, lnum[0])
871 line = getline(file, lnum[0])
867 lnum[0] += 1
872 lnum[0] += 1
868 return line
873 return line
869
874
870 # Build the list of names on this line of code where the exception
875 # Build the list of names on this line of code where the exception
871 # occurred.
876 # occurred.
872 try:
877 try:
873 # This builds the names list in-place by capturing it from the
878 # This builds the names list in-place by capturing it from the
874 # enclosing scope.
879 # enclosing scope.
875 tokenize.tokenize(linereader, tokeneater)
880 for token in generate_tokens(linereader):
881 tokeneater(*token)
876 except IndexError:
882 except IndexError:
877 # signals exit of tokenizer
883 # signals exit of tokenizer
878 pass
884 pass
879 except tokenize.TokenError,msg:
885 except tokenize.TokenError,msg:
880 _m = ("An unexpected error occurred while tokenizing input\n"
886 _m = ("An unexpected error occurred while tokenizing input\n"
881 "The following traceback may be corrupted or invalid\n"
887 "The following traceback may be corrupted or invalid\n"
882 "The error message is: %s\n" % msg)
888 "The error message is: %s\n" % msg)
883 error(_m)
889 error(_m)
884
890
885 # prune names list of duplicates, but keep the right order
891 # prune names list of duplicates, but keep the right order
886 unique_names = uniq_stable(names)
892 unique_names = uniq_stable(names)
887
893
888 # Start loop over vars
894 # Start loop over vars
889 lvals = []
895 lvals = []
890 if self.include_vars:
896 if self.include_vars:
891 for name_full in unique_names:
897 for name_full in unique_names:
892 name_base = name_full.split('.',1)[0]
898 name_base = name_full.split('.',1)[0]
893 if name_base in frame.f_code.co_varnames:
899 if name_base in frame.f_code.co_varnames:
894 if locals.has_key(name_base):
900 if locals.has_key(name_base):
895 try:
901 try:
896 value = repr(eval(name_full,locals))
902 value = repr(eval(name_full,locals))
897 except:
903 except:
898 value = undefined
904 value = undefined
899 else:
905 else:
900 value = undefined
906 value = undefined
901 name = tpl_local_var % name_full
907 name = tpl_local_var % name_full
902 else:
908 else:
903 if frame.f_globals.has_key(name_base):
909 if frame.f_globals.has_key(name_base):
904 try:
910 try:
905 value = repr(eval(name_full,frame.f_globals))
911 value = repr(eval(name_full,frame.f_globals))
906 except:
912 except:
907 value = undefined
913 value = undefined
908 else:
914 else:
909 value = undefined
915 value = undefined
910 name = tpl_global_var % name_full
916 name = tpl_global_var % name_full
911 lvals.append(tpl_name_val % (name,value))
917 lvals.append(tpl_name_val % (name,value))
912 if lvals:
918 if lvals:
913 lvals = '%s%s' % (indent,em_normal.join(lvals))
919 lvals = '%s%s' % (indent,em_normal.join(lvals))
914 else:
920 else:
915 lvals = ''
921 lvals = ''
916
922
917 level = '%s %s\n' % (link,call)
923 level = '%s %s\n' % (link,call)
918
924
919 if index is None:
925 if index is None:
920 frames.append(level)
926 frames.append(level)
921 else:
927 else:
922 frames.append('%s%s' % (level,''.join(
928 frames.append('%s%s' % (level,''.join(
923 _format_traceback_lines(lnum,index,lines,Colors,lvals,
929 _format_traceback_lines(lnum,index,lines,Colors,lvals,
924 col_scheme))))
930 col_scheme))))
925
931
926 # Get (safely) a string form of the exception info
932 # Get (safely) a string form of the exception info
927 try:
933 try:
928 etype_str,evalue_str = map(str,(etype,evalue))
934 etype_str,evalue_str = map(str,(etype,evalue))
929 except:
935 except:
930 # User exception is improperly defined.
936 # User exception is improperly defined.
931 etype,evalue = str,sys.exc_info()[:2]
937 etype,evalue = str,sys.exc_info()[:2]
932 etype_str,evalue_str = map(str,(etype,evalue))
938 etype_str,evalue_str = map(str,(etype,evalue))
933 # ... and format it
939 # ... and format it
934 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
940 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
935 ColorsNormal, evalue_str)]
941 ColorsNormal, evalue_str)]
936 if type(evalue) is types.InstanceType:
942 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
937 try:
943 try:
938 names = [w for w in dir(evalue) if isinstance(w, basestring)]
944 names = [w for w in dir(evalue) if isinstance(w, basestring)]
939 except:
945 except:
940 # Every now and then, an object with funny inernals blows up
946 # Every now and then, an object with funny inernals blows up
941 # when dir() is called on it. We do the best we can to report
947 # when dir() is called on it. We do the best we can to report
942 # the problem and continue
948 # the problem and continue
943 _m = '%sException reporting error (object with broken dir())%s:'
949 _m = '%sException reporting error (object with broken dir())%s:'
944 exception.append(_m % (Colors.excName,ColorsNormal))
950 exception.append(_m % (Colors.excName,ColorsNormal))
945 etype_str,evalue_str = map(str,sys.exc_info()[:2])
951 etype_str,evalue_str = map(str,sys.exc_info()[:2])
946 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
952 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
947 ColorsNormal, evalue_str))
953 ColorsNormal, evalue_str))
948 names = []
954 names = []
949 for name in names:
955 for name in names:
950 value = text_repr(getattr(evalue, name))
956 value = text_repr(getattr(evalue, name))
951 exception.append('\n%s%s = %s' % (indent, name, value))
957 exception.append('\n%s%s = %s' % (indent, name, value))
952
958
953 # vds: >>
959 # vds: >>
954 if records:
960 if records:
955 filepath, lnum = records[-1][1:3]
961 filepath, lnum = records[-1][1:3]
956 #print "file:", str(file), "linenb", str(lnum) # dbg
962 #print "file:", str(file), "linenb", str(lnum) # dbg
957 filepath = os.path.abspath(filepath)
963 filepath = os.path.abspath(filepath)
958 ipinst = ipapi.get()
964 ipinst = ipapi.get()
959 if ipinst is not None:
965 if ipinst is not None:
960 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
966 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
961 # vds: <<
967 # vds: <<
962
968
963 # return all our info assembled as a single string
969 # return all our info assembled as a single string
964 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
970 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
965 return [head] + frames + [''.join(exception[0])]
971 return [head] + frames + [''.join(exception[0])]
966
972
967 def debugger(self,force=False):
973 def debugger(self,force=False):
968 """Call up the pdb debugger if desired, always clean up the tb
974 """Call up the pdb debugger if desired, always clean up the tb
969 reference.
975 reference.
970
976
971 Keywords:
977 Keywords:
972
978
973 - force(False): by default, this routine checks the instance call_pdb
979 - force(False): by default, this routine checks the instance call_pdb
974 flag and does not actually invoke the debugger if the flag is false.
980 flag and does not actually invoke the debugger if the flag is false.
975 The 'force' option forces the debugger to activate even if the flag
981 The 'force' option forces the debugger to activate even if the flag
976 is false.
982 is false.
977
983
978 If the call_pdb flag is set, the pdb interactive debugger is
984 If the call_pdb flag is set, the pdb interactive debugger is
979 invoked. In all cases, the self.tb reference to the current traceback
985 invoked. In all cases, the self.tb reference to the current traceback
980 is deleted to prevent lingering references which hamper memory
986 is deleted to prevent lingering references which hamper memory
981 management.
987 management.
982
988
983 Note that each call to pdb() does an 'import readline', so if your app
989 Note that each call to pdb() does an 'import readline', so if your app
984 requires a special setup for the readline completers, you'll have to
990 requires a special setup for the readline completers, you'll have to
985 fix that by hand after invoking the exception handler."""
991 fix that by hand after invoking the exception handler."""
986
992
987 if force or self.call_pdb:
993 if force or self.call_pdb:
988 if self.pdb is None:
994 if self.pdb is None:
989 self.pdb = debugger.Pdb(
995 self.pdb = debugger.Pdb(
990 self.color_scheme_table.active_scheme_name)
996 self.color_scheme_table.active_scheme_name)
991 # the system displayhook may have changed, restore the original
997 # the system displayhook may have changed, restore the original
992 # for pdb
998 # for pdb
993 display_trap = DisplayTrap(hook=sys.__displayhook__)
999 display_trap = DisplayTrap(hook=sys.__displayhook__)
994 with display_trap:
1000 with display_trap:
995 self.pdb.reset()
1001 self.pdb.reset()
996 # Find the right frame so we don't pop up inside ipython itself
1002 # Find the right frame so we don't pop up inside ipython itself
997 if hasattr(self,'tb') and self.tb is not None:
1003 if hasattr(self,'tb') and self.tb is not None:
998 etb = self.tb
1004 etb = self.tb
999 else:
1005 else:
1000 etb = self.tb = sys.last_traceback
1006 etb = self.tb = sys.last_traceback
1001 while self.tb is not None and self.tb.tb_next is not None:
1007 while self.tb is not None and self.tb.tb_next is not None:
1002 self.tb = self.tb.tb_next
1008 self.tb = self.tb.tb_next
1003 if etb and etb.tb_next:
1009 if etb and etb.tb_next:
1004 etb = etb.tb_next
1010 etb = etb.tb_next
1005 self.pdb.botframe = etb.tb_frame
1011 self.pdb.botframe = etb.tb_frame
1006 self.pdb.interaction(self.tb.tb_frame, self.tb)
1012 self.pdb.interaction(self.tb.tb_frame, self.tb)
1007
1013
1008 if hasattr(self,'tb'):
1014 if hasattr(self,'tb'):
1009 del self.tb
1015 del self.tb
1010
1016
1011 def handler(self, info=None):
1017 def handler(self, info=None):
1012 (etype, evalue, etb) = info or sys.exc_info()
1018 (etype, evalue, etb) = info or sys.exc_info()
1013 self.tb = etb
1019 self.tb = etb
1014 ostream = self.ostream
1020 ostream = self.ostream
1015 ostream.flush()
1021 ostream.flush()
1016 ostream.write(self.text(etype, evalue, etb))
1022 ostream.write(self.text(etype, evalue, etb))
1017 ostream.write('\n')
1023 ostream.write('\n')
1018 ostream.flush()
1024 ostream.flush()
1019
1025
1020 # Changed so an instance can just be called as VerboseTB_inst() and print
1026 # Changed so an instance can just be called as VerboseTB_inst() and print
1021 # out the right info on its own.
1027 # out the right info on its own.
1022 def __call__(self, etype=None, evalue=None, etb=None):
1028 def __call__(self, etype=None, evalue=None, etb=None):
1023 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1029 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1024 if etb is None:
1030 if etb is None:
1025 self.handler()
1031 self.handler()
1026 else:
1032 else:
1027 self.handler((etype, evalue, etb))
1033 self.handler((etype, evalue, etb))
1028 try:
1034 try:
1029 self.debugger()
1035 self.debugger()
1030 except KeyboardInterrupt:
1036 except KeyboardInterrupt:
1031 print "\nKeyboardInterrupt"
1037 print "\nKeyboardInterrupt"
1032
1038
1033 #----------------------------------------------------------------------------
1039 #----------------------------------------------------------------------------
1034 class FormattedTB(VerboseTB, ListTB):
1040 class FormattedTB(VerboseTB, ListTB):
1035 """Subclass ListTB but allow calling with a traceback.
1041 """Subclass ListTB but allow calling with a traceback.
1036
1042
1037 It can thus be used as a sys.excepthook for Python > 2.1.
1043 It can thus be used as a sys.excepthook for Python > 2.1.
1038
1044
1039 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1045 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1040
1046
1041 Allows a tb_offset to be specified. This is useful for situations where
1047 Allows a tb_offset to be specified. This is useful for situations where
1042 one needs to remove a number of topmost frames from the traceback (such as
1048 one needs to remove a number of topmost frames from the traceback (such as
1043 occurs with python programs that themselves execute other python code,
1049 occurs with python programs that themselves execute other python code,
1044 like Python shells). """
1050 like Python shells). """
1045
1051
1046 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1052 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1047 ostream=None,
1053 ostream=None,
1048 tb_offset=0, long_header=False, include_vars=False,
1054 tb_offset=0, long_header=False, include_vars=False,
1049 check_cache=None):
1055 check_cache=None):
1050
1056
1051 # NEVER change the order of this list. Put new modes at the end:
1057 # NEVER change the order of this list. Put new modes at the end:
1052 self.valid_modes = ['Plain','Context','Verbose']
1058 self.valid_modes = ['Plain','Context','Verbose']
1053 self.verbose_modes = self.valid_modes[1:3]
1059 self.verbose_modes = self.valid_modes[1:3]
1054
1060
1055 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1061 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1056 ostream=ostream, tb_offset=tb_offset,
1062 ostream=ostream, tb_offset=tb_offset,
1057 long_header=long_header, include_vars=include_vars,
1063 long_header=long_header, include_vars=include_vars,
1058 check_cache=check_cache)
1064 check_cache=check_cache)
1059
1065
1060 # Different types of tracebacks are joined with different separators to
1066 # Different types of tracebacks are joined with different separators to
1061 # form a single string. They are taken from this dict
1067 # form a single string. They are taken from this dict
1062 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1068 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1063 # set_mode also sets the tb_join_char attribute
1069 # set_mode also sets the tb_join_char attribute
1064 self.set_mode(mode)
1070 self.set_mode(mode)
1065
1071
1066 def _extract_tb(self,tb):
1072 def _extract_tb(self,tb):
1067 if tb:
1073 if tb:
1068 return traceback.extract_tb(tb)
1074 return traceback.extract_tb(tb)
1069 else:
1075 else:
1070 return None
1076 return None
1071
1077
1072 def structured_traceback(self, etype, value, tb, tb_offset=None, context=5):
1078 def structured_traceback(self, etype, value, tb, tb_offset=None, context=5):
1073 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1079 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1074 mode = self.mode
1080 mode = self.mode
1075 if mode in self.verbose_modes:
1081 if mode in self.verbose_modes:
1076 # Verbose modes need a full traceback
1082 # Verbose modes need a full traceback
1077 return VerboseTB.structured_traceback(
1083 return VerboseTB.structured_traceback(
1078 self, etype, value, tb, tb_offset, context
1084 self, etype, value, tb, tb_offset, context
1079 )
1085 )
1080 else:
1086 else:
1081 # We must check the source cache because otherwise we can print
1087 # We must check the source cache because otherwise we can print
1082 # out-of-date source code.
1088 # out-of-date source code.
1083 self.check_cache()
1089 self.check_cache()
1084 # Now we can extract and format the exception
1090 # Now we can extract and format the exception
1085 elist = self._extract_tb(tb)
1091 elist = self._extract_tb(tb)
1086 return ListTB.structured_traceback(
1092 return ListTB.structured_traceback(
1087 self, etype, value, elist, tb_offset, context
1093 self, etype, value, elist, tb_offset, context
1088 )
1094 )
1089
1095
1090 def stb2text(self, stb):
1096 def stb2text(self, stb):
1091 """Convert a structured traceback (a list) to a string."""
1097 """Convert a structured traceback (a list) to a string."""
1092 return self.tb_join_char.join(stb)
1098 return self.tb_join_char.join(stb)
1093
1099
1094
1100
1095 def set_mode(self,mode=None):
1101 def set_mode(self,mode=None):
1096 """Switch to the desired mode.
1102 """Switch to the desired mode.
1097
1103
1098 If mode is not specified, cycles through the available modes."""
1104 If mode is not specified, cycles through the available modes."""
1099
1105
1100 if not mode:
1106 if not mode:
1101 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
1107 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
1102 len(self.valid_modes)
1108 len(self.valid_modes)
1103 self.mode = self.valid_modes[new_idx]
1109 self.mode = self.valid_modes[new_idx]
1104 elif mode not in self.valid_modes:
1110 elif mode not in self.valid_modes:
1105 raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
1111 raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
1106 'Valid modes: '+str(self.valid_modes)
1112 'Valid modes: '+str(self.valid_modes)
1107 else:
1113 else:
1108 self.mode = mode
1114 self.mode = mode
1109 # include variable details only in 'Verbose' mode
1115 # include variable details only in 'Verbose' mode
1110 self.include_vars = (self.mode == self.valid_modes[2])
1116 self.include_vars = (self.mode == self.valid_modes[2])
1111 # Set the join character for generating text tracebacks
1117 # Set the join character for generating text tracebacks
1112 self.tb_join_char = self._join_chars[self.mode]
1118 self.tb_join_char = self._join_chars[self.mode]
1113
1119
1114 # some convenient shorcuts
1120 # some convenient shorcuts
1115 def plain(self):
1121 def plain(self):
1116 self.set_mode(self.valid_modes[0])
1122 self.set_mode(self.valid_modes[0])
1117
1123
1118 def context(self):
1124 def context(self):
1119 self.set_mode(self.valid_modes[1])
1125 self.set_mode(self.valid_modes[1])
1120
1126
1121 def verbose(self):
1127 def verbose(self):
1122 self.set_mode(self.valid_modes[2])
1128 self.set_mode(self.valid_modes[2])
1123
1129
1124 #----------------------------------------------------------------------------
1130 #----------------------------------------------------------------------------
1125 class AutoFormattedTB(FormattedTB):
1131 class AutoFormattedTB(FormattedTB):
1126 """A traceback printer which can be called on the fly.
1132 """A traceback printer which can be called on the fly.
1127
1133
1128 It will find out about exceptions by itself.
1134 It will find out about exceptions by itself.
1129
1135
1130 A brief example:
1136 A brief example:
1131
1137
1132 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1138 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1133 try:
1139 try:
1134 ...
1140 ...
1135 except:
1141 except:
1136 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1142 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1137 """
1143 """
1138
1144
1139 def __call__(self,etype=None,evalue=None,etb=None,
1145 def __call__(self,etype=None,evalue=None,etb=None,
1140 out=None,tb_offset=None):
1146 out=None,tb_offset=None):
1141 """Print out a formatted exception traceback.
1147 """Print out a formatted exception traceback.
1142
1148
1143 Optional arguments:
1149 Optional arguments:
1144 - out: an open file-like object to direct output to.
1150 - out: an open file-like object to direct output to.
1145
1151
1146 - tb_offset: the number of frames to skip over in the stack, on a
1152 - tb_offset: the number of frames to skip over in the stack, on a
1147 per-call basis (this overrides temporarily the instance's tb_offset
1153 per-call basis (this overrides temporarily the instance's tb_offset
1148 given at initialization time. """
1154 given at initialization time. """
1149
1155
1150
1156
1151 if out is None:
1157 if out is None:
1152 out = self.ostream
1158 out = self.ostream
1153 out.flush()
1159 out.flush()
1154 out.write(self.text(etype, evalue, etb, tb_offset))
1160 out.write(self.text(etype, evalue, etb, tb_offset))
1155 out.write('\n')
1161 out.write('\n')
1156 out.flush()
1162 out.flush()
1157 # FIXME: we should remove the auto pdb behavior from here and leave
1163 # FIXME: we should remove the auto pdb behavior from here and leave
1158 # that to the clients.
1164 # that to the clients.
1159 try:
1165 try:
1160 self.debugger()
1166 self.debugger()
1161 except KeyboardInterrupt:
1167 except KeyboardInterrupt:
1162 print "\nKeyboardInterrupt"
1168 print "\nKeyboardInterrupt"
1163
1169
1164 def structured_traceback(self, etype=None, value=None, tb=None,
1170 def structured_traceback(self, etype=None, value=None, tb=None,
1165 tb_offset=None, context=5):
1171 tb_offset=None, context=5):
1166 if etype is None:
1172 if etype is None:
1167 etype,value,tb = sys.exc_info()
1173 etype,value,tb = sys.exc_info()
1168 self.tb = tb
1174 self.tb = tb
1169 return FormattedTB.structured_traceback(
1175 return FormattedTB.structured_traceback(
1170 self, etype, value, tb, tb_offset, context)
1176 self, etype, value, tb, tb_offset, context)
1171
1177
1172 #---------------------------------------------------------------------------
1178 #---------------------------------------------------------------------------
1173
1179
1174 # A simple class to preserve Nathan's original functionality.
1180 # A simple class to preserve Nathan's original functionality.
1175 class ColorTB(FormattedTB):
1181 class ColorTB(FormattedTB):
1176 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1182 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1177 def __init__(self,color_scheme='Linux',call_pdb=0):
1183 def __init__(self,color_scheme='Linux',call_pdb=0):
1178 FormattedTB.__init__(self,color_scheme=color_scheme,
1184 FormattedTB.__init__(self,color_scheme=color_scheme,
1179 call_pdb=call_pdb)
1185 call_pdb=call_pdb)
1180
1186
1181
1187
1182 class SyntaxTB(ListTB):
1188 class SyntaxTB(ListTB):
1183 """Extension which holds some state: the last exception value"""
1189 """Extension which holds some state: the last exception value"""
1184
1190
1185 def __init__(self,color_scheme = 'NoColor'):
1191 def __init__(self,color_scheme = 'NoColor'):
1186 ListTB.__init__(self,color_scheme)
1192 ListTB.__init__(self,color_scheme)
1187 self.last_syntax_error = None
1193 self.last_syntax_error = None
1188
1194
1189 def __call__(self, etype, value, elist):
1195 def __call__(self, etype, value, elist):
1190 self.last_syntax_error = value
1196 self.last_syntax_error = value
1191 ListTB.__call__(self,etype,value,elist)
1197 ListTB.__call__(self,etype,value,elist)
1192
1198
1193 def clear_err_state(self):
1199 def clear_err_state(self):
1194 """Return the current error state and clear it"""
1200 """Return the current error state and clear it"""
1195 e = self.last_syntax_error
1201 e = self.last_syntax_error
1196 self.last_syntax_error = None
1202 self.last_syntax_error = None
1197 return e
1203 return e
1198
1204
1199 def stb2text(self, stb):
1205 def stb2text(self, stb):
1200 """Convert a structured traceback (a list) to a string."""
1206 """Convert a structured traceback (a list) to a string."""
1201 return ''.join(stb)
1207 return ''.join(stb)
1202
1208
1203
1209
1204 #----------------------------------------------------------------------------
1210 #----------------------------------------------------------------------------
1205 # module testing (minimal)
1211 # module testing (minimal)
1206 if __name__ == "__main__":
1212 if __name__ == "__main__":
1207 def spam(c, (d, e)):
1213 def spam(c, (d, e)):
1208 x = c + d
1214 x = c + d
1209 y = c * d
1215 y = c * d
1210 foo(x, y)
1216 foo(x, y)
1211
1217
1212 def foo(a, b, bar=1):
1218 def foo(a, b, bar=1):
1213 eggs(a, b + bar)
1219 eggs(a, b + bar)
1214
1220
1215 def eggs(f, g, z=globals()):
1221 def eggs(f, g, z=globals()):
1216 h = f + g
1222 h = f + g
1217 i = f - g
1223 i = f - g
1218 return h / i
1224 return h / i
1219
1225
1220 print ''
1226 print ''
1221 print '*** Before ***'
1227 print '*** Before ***'
1222 try:
1228 try:
1223 print spam(1, (2, 3))
1229 print spam(1, (2, 3))
1224 except:
1230 except:
1225 traceback.print_exc()
1231 traceback.print_exc()
1226 print ''
1232 print ''
1227
1233
1228 handler = ColorTB()
1234 handler = ColorTB()
1229 print '*** ColorTB ***'
1235 print '*** ColorTB ***'
1230 try:
1236 try:
1231 print spam(1, (2, 3))
1237 print spam(1, (2, 3))
1232 except:
1238 except:
1233 apply(handler, sys.exc_info() )
1239 apply(handler, sys.exc_info() )
1234 print ''
1240 print ''
1235
1241
1236 handler = VerboseTB()
1242 handler = VerboseTB()
1237 print '*** VerboseTB ***'
1243 print '*** VerboseTB ***'
1238 try:
1244 try:
1239 print spam(1, (2, 3))
1245 print spam(1, (2, 3))
1240 except:
1246 except:
1241 apply(handler, sys.exc_info() )
1247 apply(handler, sys.exc_info() )
1242 print ''
1248 print ''
1243
1249
@@ -1,303 +1,311 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Class and program to colorize python source code for ANSI terminals.
3 Class and program to colorize python source code for ANSI terminals.
4
4
5 Based on an HTML code highlighter by Jurgen Hermann found at:
5 Based on an HTML code highlighter by Jurgen Hermann found at:
6 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52298
6 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52298
7
7
8 Modifications by Fernando Perez (fperez@colorado.edu).
8 Modifications by Fernando Perez (fperez@colorado.edu).
9
9
10 Information on the original HTML highlighter follows:
10 Information on the original HTML highlighter follows:
11
11
12 MoinMoin - Python Source Parser
12 MoinMoin - Python Source Parser
13
13
14 Title: Colorize Python source using the built-in tokenizer
14 Title: Colorize Python source using the built-in tokenizer
15
15
16 Submitter: Jurgen Hermann
16 Submitter: Jurgen Hermann
17 Last Updated:2001/04/06
17 Last Updated:2001/04/06
18
18
19 Version no:1.2
19 Version no:1.2
20
20
21 Description:
21 Description:
22
22
23 This code is part of MoinMoin (http://moin.sourceforge.net/) and converts
23 This code is part of MoinMoin (http://moin.sourceforge.net/) and converts
24 Python source code to HTML markup, rendering comments, keywords,
24 Python source code to HTML markup, rendering comments, keywords,
25 operators, numeric and string literals in different colors.
25 operators, numeric and string literals in different colors.
26
26
27 It shows how to use the built-in keyword, token and tokenize modules to
27 It shows how to use the built-in keyword, token and tokenize modules to
28 scan Python source code and re-emit it with no changes to its original
28 scan Python source code and re-emit it with no changes to its original
29 formatting (which is the hard part).
29 formatting (which is the hard part).
30 """
30 """
31
31
32 __all__ = ['ANSICodeColors','Parser']
32 __all__ = ['ANSICodeColors','Parser']
33
33
34 _scheme_default = 'Linux'
34 _scheme_default = 'Linux'
35
35
36 # Imports
36 # Imports
37 import cStringIO
37 import cStringIO
38 import keyword
38 import keyword
39 import os
39 import os
40 import optparse
40 import optparse
41 import sys
41 import sys
42 import token
42 import token
43 import tokenize
43 import tokenize
44
44
45 try:
46 generate_tokens = tokenize.generate_tokens
47 except AttributeError:
48 # Python 3. Note that we use the undocumented _tokenize because it expects
49 # strings, not bytes. See also Python issue #9969.
50 generate_tokens = tokenize._tokenize
51
45 from IPython.utils.coloransi import *
52 from IPython.utils.coloransi import *
46
53
47 #############################################################################
54 #############################################################################
48 ### Python Source Parser (does Hilighting)
55 ### Python Source Parser (does Hilighting)
49 #############################################################################
56 #############################################################################
50
57
51 _KEYWORD = token.NT_OFFSET + 1
58 _KEYWORD = token.NT_OFFSET + 1
52 _TEXT = token.NT_OFFSET + 2
59 _TEXT = token.NT_OFFSET + 2
53
60
54 #****************************************************************************
61 #****************************************************************************
55 # Builtin color schemes
62 # Builtin color schemes
56
63
57 Colors = TermColors # just a shorthand
64 Colors = TermColors # just a shorthand
58
65
59 # Build a few color schemes
66 # Build a few color schemes
60 NoColor = ColorScheme(
67 NoColor = ColorScheme(
61 'NoColor',{
68 'NoColor',{
62 token.NUMBER : Colors.NoColor,
69 token.NUMBER : Colors.NoColor,
63 token.OP : Colors.NoColor,
70 token.OP : Colors.NoColor,
64 token.STRING : Colors.NoColor,
71 token.STRING : Colors.NoColor,
65 tokenize.COMMENT : Colors.NoColor,
72 tokenize.COMMENT : Colors.NoColor,
66 token.NAME : Colors.NoColor,
73 token.NAME : Colors.NoColor,
67 token.ERRORTOKEN : Colors.NoColor,
74 token.ERRORTOKEN : Colors.NoColor,
68
75
69 _KEYWORD : Colors.NoColor,
76 _KEYWORD : Colors.NoColor,
70 _TEXT : Colors.NoColor,
77 _TEXT : Colors.NoColor,
71
78
72 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
79 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
73 } )
80 } )
74
81
75 LinuxColors = ColorScheme(
82 LinuxColors = ColorScheme(
76 'Linux',{
83 'Linux',{
77 token.NUMBER : Colors.LightCyan,
84 token.NUMBER : Colors.LightCyan,
78 token.OP : Colors.Yellow,
85 token.OP : Colors.Yellow,
79 token.STRING : Colors.LightBlue,
86 token.STRING : Colors.LightBlue,
80 tokenize.COMMENT : Colors.LightRed,
87 tokenize.COMMENT : Colors.LightRed,
81 token.NAME : Colors.Normal,
88 token.NAME : Colors.Normal,
82 token.ERRORTOKEN : Colors.Red,
89 token.ERRORTOKEN : Colors.Red,
83
90
84 _KEYWORD : Colors.LightGreen,
91 _KEYWORD : Colors.LightGreen,
85 _TEXT : Colors.Yellow,
92 _TEXT : Colors.Yellow,
86
93
87 'normal' : Colors.Normal # color off (usu. Colors.Normal)
94 'normal' : Colors.Normal # color off (usu. Colors.Normal)
88 } )
95 } )
89
96
90 LightBGColors = ColorScheme(
97 LightBGColors = ColorScheme(
91 'LightBG',{
98 'LightBG',{
92 token.NUMBER : Colors.Cyan,
99 token.NUMBER : Colors.Cyan,
93 token.OP : Colors.Blue,
100 token.OP : Colors.Blue,
94 token.STRING : Colors.Blue,
101 token.STRING : Colors.Blue,
95 tokenize.COMMENT : Colors.Red,
102 tokenize.COMMENT : Colors.Red,
96 token.NAME : Colors.Normal,
103 token.NAME : Colors.Normal,
97 token.ERRORTOKEN : Colors.Red,
104 token.ERRORTOKEN : Colors.Red,
98
105
99 _KEYWORD : Colors.Green,
106 _KEYWORD : Colors.Green,
100 _TEXT : Colors.Blue,
107 _TEXT : Colors.Blue,
101
108
102 'normal' : Colors.Normal # color off (usu. Colors.Normal)
109 'normal' : Colors.Normal # color off (usu. Colors.Normal)
103 } )
110 } )
104
111
105 # Build table of color schemes (needed by the parser)
112 # Build table of color schemes (needed by the parser)
106 ANSICodeColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
113 ANSICodeColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
107 _scheme_default)
114 _scheme_default)
108
115
109 class Parser:
116 class Parser:
110 """ Format colored Python source.
117 """ Format colored Python source.
111 """
118 """
112
119
113 def __init__(self, color_table=None,out = sys.stdout):
120 def __init__(self, color_table=None,out = sys.stdout):
114 """ Create a parser with a specified color table and output channel.
121 """ Create a parser with a specified color table and output channel.
115
122
116 Call format() to process code.
123 Call format() to process code.
117 """
124 """
118 self.color_table = color_table and color_table or ANSICodeColors
125 self.color_table = color_table and color_table or ANSICodeColors
119 self.out = out
126 self.out = out
120
127
121 def format(self, raw, out = None, scheme = ''):
128 def format(self, raw, out = None, scheme = ''):
122 return self.format2(raw, out, scheme)[0]
129 return self.format2(raw, out, scheme)[0]
123
130
124 def format2(self, raw, out = None, scheme = ''):
131 def format2(self, raw, out = None, scheme = ''):
125 """ Parse and send the colored source.
132 """ Parse and send the colored source.
126
133
127 If out and scheme are not specified, the defaults (given to
134 If out and scheme are not specified, the defaults (given to
128 constructor) are used.
135 constructor) are used.
129
136
130 out should be a file-type object. Optionally, out can be given as the
137 out should be a file-type object. Optionally, out can be given as the
131 string 'str' and the parser will automatically return the output in a
138 string 'str' and the parser will automatically return the output in a
132 string."""
139 string."""
133
140
134 string_output = 0
141 string_output = 0
135 if out == 'str' or self.out == 'str' or \
142 if out == 'str' or self.out == 'str' or \
136 isinstance(self.out,cStringIO.OutputType):
143 isinstance(self.out,cStringIO.OutputType):
137 # XXX - I don't really like this state handling logic, but at this
144 # XXX - I don't really like this state handling logic, but at this
138 # point I don't want to make major changes, so adding the
145 # point I don't want to make major changes, so adding the
139 # isinstance() check is the simplest I can do to ensure correct
146 # isinstance() check is the simplest I can do to ensure correct
140 # behavior.
147 # behavior.
141 out_old = self.out
148 out_old = self.out
142 self.out = cStringIO.StringIO()
149 self.out = cStringIO.StringIO()
143 string_output = 1
150 string_output = 1
144 elif out is not None:
151 elif out is not None:
145 self.out = out
152 self.out = out
146
153
147 # Fast return of the unmodified input for NoColor scheme
154 # Fast return of the unmodified input for NoColor scheme
148 if scheme == 'NoColor':
155 if scheme == 'NoColor':
149 error = False
156 error = False
150 self.out.write(raw)
157 self.out.write(raw)
151 if string_output:
158 if string_output:
152 return raw,error
159 return raw,error
153 else:
160 else:
154 return None,error
161 return None,error
155
162
156 # local shorthands
163 # local shorthands
157 colors = self.color_table[scheme].colors
164 colors = self.color_table[scheme].colors
158 self.colors = colors # put in object so __call__ sees it
165 self.colors = colors # put in object so __call__ sees it
159
166
160 # Remove trailing whitespace and normalize tabs
167 # Remove trailing whitespace and normalize tabs
161 self.raw = raw.expandtabs().rstrip()
168 self.raw = raw.expandtabs().rstrip()
162
169
163 # store line offsets in self.lines
170 # store line offsets in self.lines
164 self.lines = [0, 0]
171 self.lines = [0, 0]
165 pos = 0
172 pos = 0
166 raw_find = self.raw.find
173 raw_find = self.raw.find
167 lines_append = self.lines.append
174 lines_append = self.lines.append
168 while 1:
175 while 1:
169 pos = raw_find('\n', pos) + 1
176 pos = raw_find('\n', pos) + 1
170 if not pos: break
177 if not pos: break
171 lines_append(pos)
178 lines_append(pos)
172 lines_append(len(self.raw))
179 lines_append(len(self.raw))
173
180
174 # parse the source and write it
181 # parse the source and write it
175 self.pos = 0
182 self.pos = 0
176 text = cStringIO.StringIO(self.raw)
183 text = cStringIO.StringIO(self.raw)
177
184
178 error = False
185 error = False
179 try:
186 try:
180 tokenize.tokenize(text.readline, self)
187 for token in generate_tokens(text.readline):
188 self(*token)
181 except tokenize.TokenError, ex:
189 except tokenize.TokenError, ex:
182 msg = ex[0]
190 msg = ex[0]
183 line = ex[1][0]
191 line = ex[1][0]
184 self.out.write("%s\n\n*** ERROR: %s%s%s\n" %
192 self.out.write("%s\n\n*** ERROR: %s%s%s\n" %
185 (colors[token.ERRORTOKEN],
193 (colors[token.ERRORTOKEN],
186 msg, self.raw[self.lines[line]:],
194 msg, self.raw[self.lines[line]:],
187 colors.normal)
195 colors.normal)
188 )
196 )
189 error = True
197 error = True
190 self.out.write(colors.normal+'\n')
198 self.out.write(colors.normal+'\n')
191 if string_output:
199 if string_output:
192 output = self.out.getvalue()
200 output = self.out.getvalue()
193 self.out = out_old
201 self.out = out_old
194 return (output, error)
202 return (output, error)
195 return (None, error)
203 return (None, error)
196
204
197 def __call__(self, toktype, toktext, (srow,scol), (erow,ecol), line):
205 def __call__(self, toktype, toktext, (srow,scol), (erow,ecol), line):
198 """ Token handler, with syntax highlighting."""
206 """ Token handler, with syntax highlighting."""
199
207
200 # local shorthands
208 # local shorthands
201 colors = self.colors
209 colors = self.colors
202 owrite = self.out.write
210 owrite = self.out.write
203
211
204 # line separator, so this works across platforms
212 # line separator, so this works across platforms
205 linesep = os.linesep
213 linesep = os.linesep
206
214
207 # calculate new positions
215 # calculate new positions
208 oldpos = self.pos
216 oldpos = self.pos
209 newpos = self.lines[srow] + scol
217 newpos = self.lines[srow] + scol
210 self.pos = newpos + len(toktext)
218 self.pos = newpos + len(toktext)
211
219
212 # handle newlines
220 # handle newlines
213 if toktype in [token.NEWLINE, tokenize.NL]:
221 if toktype in [token.NEWLINE, tokenize.NL]:
214 owrite(linesep)
222 owrite(linesep)
215 return
223 return
216
224
217 # send the original whitespace, if needed
225 # send the original whitespace, if needed
218 if newpos > oldpos:
226 if newpos > oldpos:
219 owrite(self.raw[oldpos:newpos])
227 owrite(self.raw[oldpos:newpos])
220
228
221 # skip indenting tokens
229 # skip indenting tokens
222 if toktype in [token.INDENT, token.DEDENT]:
230 if toktype in [token.INDENT, token.DEDENT]:
223 self.pos = newpos
231 self.pos = newpos
224 return
232 return
225
233
226 # map token type to a color group
234 # map token type to a color group
227 if token.LPAR <= toktype and toktype <= token.OP:
235 if token.LPAR <= toktype and toktype <= token.OP:
228 toktype = token.OP
236 toktype = token.OP
229 elif toktype == token.NAME and keyword.iskeyword(toktext):
237 elif toktype == token.NAME and keyword.iskeyword(toktext):
230 toktype = _KEYWORD
238 toktype = _KEYWORD
231 color = colors.get(toktype, colors[_TEXT])
239 color = colors.get(toktype, colors[_TEXT])
232
240
233 #print '<%s>' % toktext, # dbg
241 #print '<%s>' % toktext, # dbg
234
242
235 # Triple quoted strings must be handled carefully so that backtracking
243 # Triple quoted strings must be handled carefully so that backtracking
236 # in pagers works correctly. We need color terminators on _each_ line.
244 # in pagers works correctly. We need color terminators on _each_ line.
237 if linesep in toktext:
245 if linesep in toktext:
238 toktext = toktext.replace(linesep, '%s%s%s' %
246 toktext = toktext.replace(linesep, '%s%s%s' %
239 (colors.normal,linesep,color))
247 (colors.normal,linesep,color))
240
248
241 # send text
249 # send text
242 owrite('%s%s%s' % (color,toktext,colors.normal))
250 owrite('%s%s%s' % (color,toktext,colors.normal))
243
251
244 def main(argv=None):
252 def main(argv=None):
245 """Run as a command-line script: colorize a python file or stdin using ANSI
253 """Run as a command-line script: colorize a python file or stdin using ANSI
246 color escapes and print to stdout.
254 color escapes and print to stdout.
247
255
248 Inputs:
256 Inputs:
249
257
250 - argv(None): a list of strings like sys.argv[1:] giving the command-line
258 - argv(None): a list of strings like sys.argv[1:] giving the command-line
251 arguments. If None, use sys.argv[1:].
259 arguments. If None, use sys.argv[1:].
252 """
260 """
253
261
254 usage_msg = """%prog [options] [filename]
262 usage_msg = """%prog [options] [filename]
255
263
256 Colorize a python file or stdin using ANSI color escapes and print to stdout.
264 Colorize a python file or stdin using ANSI color escapes and print to stdout.
257 If no filename is given, or if filename is -, read standard input."""
265 If no filename is given, or if filename is -, read standard input."""
258
266
259 parser = optparse.OptionParser(usage=usage_msg)
267 parser = optparse.OptionParser(usage=usage_msg)
260 newopt = parser.add_option
268 newopt = parser.add_option
261 newopt('-s','--scheme',metavar='NAME',dest='scheme_name',action='store',
269 newopt('-s','--scheme',metavar='NAME',dest='scheme_name',action='store',
262 choices=['Linux','LightBG','NoColor'],default=_scheme_default,
270 choices=['Linux','LightBG','NoColor'],default=_scheme_default,
263 help="give the color scheme to use. Currently only 'Linux'\
271 help="give the color scheme to use. Currently only 'Linux'\
264 (default) and 'LightBG' and 'NoColor' are implemented (give without\
272 (default) and 'LightBG' and 'NoColor' are implemented (give without\
265 quotes)")
273 quotes)")
266
274
267 opts,args = parser.parse_args(argv)
275 opts,args = parser.parse_args(argv)
268
276
269 if len(args) > 1:
277 if len(args) > 1:
270 parser.error("you must give at most one filename.")
278 parser.error("you must give at most one filename.")
271
279
272 if len(args) == 0:
280 if len(args) == 0:
273 fname = '-' # no filename given; setup to read from stdin
281 fname = '-' # no filename given; setup to read from stdin
274 else:
282 else:
275 fname = args[0]
283 fname = args[0]
276
284
277 if fname == '-':
285 if fname == '-':
278 stream = sys.stdin
286 stream = sys.stdin
279 else:
287 else:
280 try:
288 try:
281 stream = file(fname)
289 stream = file(fname)
282 except IOError,msg:
290 except IOError,msg:
283 print >> sys.stderr, msg
291 print >> sys.stderr, msg
284 sys.exit(1)
292 sys.exit(1)
285
293
286 parser = Parser()
294 parser = Parser()
287
295
288 # we need nested try blocks because pre-2.5 python doesn't support unified
296 # we need nested try blocks because pre-2.5 python doesn't support unified
289 # try-except-finally
297 # try-except-finally
290 try:
298 try:
291 try:
299 try:
292 # write colorized version to stdout
300 # write colorized version to stdout
293 parser.format(stream.read(),scheme=opts.scheme_name)
301 parser.format(stream.read(),scheme=opts.scheme_name)
294 except IOError,msg:
302 except IOError,msg:
295 # if user reads through a pager and quits, don't print traceback
303 # if user reads through a pager and quits, don't print traceback
296 if msg.args != (32,'Broken pipe'):
304 if msg.args != (32,'Broken pipe'):
297 raise
305 raise
298 finally:
306 finally:
299 if stream is not sys.stdin:
307 if stream is not sys.stdin:
300 stream.close() # in case a non-handled exception happened above
308 stream.close() # in case a non-handled exception happened above
301
309
302 if __name__ == "__main__":
310 if __name__ == "__main__":
303 main()
311 main()
@@ -1,87 +1,89 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Compatibility tricks for Python 3. Mainly to do with unicode."""
2 """Compatibility tricks for Python 3. Mainly to do with unicode."""
3 import sys
3 import sys
4
4
5 orig_open = open
5 orig_open = open
6
6
7 def no_code(x, encoding=None):
7 def no_code(x, encoding=None):
8 return x
8 return x
9
9
10 def decode(s, encoding=None):
10 def decode(s, encoding=None):
11 encoding = encoding or sys.stdin.encoding or sys.getdefaultencoding()
11 encoding = encoding or sys.stdin.encoding or sys.getdefaultencoding()
12 return s.decode(encoding, "replace")
12 return s.decode(encoding, "replace")
13
13
14 def encode(u, encoding=None):
14 def encode(u, encoding=None):
15 encoding = encoding or sys.stdin.encoding or sys.getdefaultencoding()
15 encoding = encoding or sys.stdin.encoding or sys.getdefaultencoding()
16 return u.encode(encoding, "replace")
16 return u.encode(encoding, "replace")
17
17
18 def cast_unicode(s, encoding=None):
18 def cast_unicode(s, encoding=None):
19 if isinstance(s, bytes):
19 if isinstance(s, bytes):
20 return decode(s, encoding)
20 return decode(s, encoding)
21 return s
21 return s
22
22
23 def cast_bytes(s, encoding=None):
23 def cast_bytes(s, encoding=None):
24 if not isinstance(s, bytes):
24 if not isinstance(s, bytes):
25 return encode(s, encoding)
25 return encode(s, encoding)
26 return s
26 return s
27
27
28 if sys.version_info[0] >= 3:
28 if sys.version_info[0] >= 3:
29 PY3 = True
29 PY3 = True
30
30
31 input = input
31 input = input
32 builtin_mod_name = "builtins"
32 builtin_mod_name = "builtins"
33
33
34 str_to_unicode = no_code
34 str_to_unicode = no_code
35 unicode_to_str = no_code
35 unicode_to_str = no_code
36 str_to_bytes = encode
36 str_to_bytes = encode
37 bytes_to_str = decode
37 bytes_to_str = decode
38 cast_bytes_py2 = no_code
38
39
39 def isidentifier(s, dotted=False):
40 def isidentifier(s, dotted=False):
40 if dotted:
41 if dotted:
41 return all(isidentifier(a) for a in s.split("."))
42 return all(isidentifier(a) for a in s.split("."))
42 return s.isidentifier()
43 return s.isidentifier()
43
44
44 open = orig_open
45 open = orig_open
45
46
46 else:
47 else:
47 PY3 = False
48 PY3 = False
48
49
49 input = raw_input
50 input = raw_input
50 builtin_mod_name = "__builtin__"
51 builtin_mod_name = "__builtin__"
51
52
52 str_to_unicode = decode
53 str_to_unicode = decode
53 unicode_to_str = encode
54 unicode_to_str = encode
54 str_to_bytes = no_code
55 str_to_bytes = no_code
55 bytes_to_str = no_code
56 bytes_to_str = no_code
57 cast_bytes_py2 = cast_bytes
56
58
57 import re
59 import re
58 _name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
60 _name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
59 def isidentifier(s, dotted=False):
61 def isidentifier(s, dotted=False):
60 if dotted:
62 if dotted:
61 return all(isidentifier(a) for a in s.split("."))
63 return all(isidentifier(a) for a in s.split("."))
62 return bool(_name_re.match(s))
64 return bool(_name_re.match(s))
63
65
64 class open(object):
66 class open(object):
65 """Wrapper providing key part of Python 3 open() interface."""
67 """Wrapper providing key part of Python 3 open() interface."""
66 def __init__(self, fname, mode="r", encoding="utf-8"):
68 def __init__(self, fname, mode="r", encoding="utf-8"):
67 self.f = orig_open(fname, mode)
69 self.f = orig_open(fname, mode)
68 self.enc = encoding
70 self.enc = encoding
69
71
70 def write(self, s):
72 def write(self, s):
71 return self.f.write(s.encode(self.enc))
73 return self.f.write(s.encode(self.enc))
72
74
73 def read(self, size=-1):
75 def read(self, size=-1):
74 return self.f.read(size).decode(self.enc)
76 return self.f.read(size).decode(self.enc)
75
77
76 def close(self):
78 def close(self):
77 return self.f.close()
79 return self.f.close()
78
80
79 def __enter__(self):
81 def __enter__(self):
80 return self
82 return self
81
83
82 def __exit__(self, etype, value, traceback):
84 def __exit__(self, etype, value, traceback):
83 self.f.close()
85 self.f.close()
84
86
85 def execfile(fname, glob, loc=None):
87 def execfile(fname, glob, loc=None):
86 loc = loc if (loc is not None) else glob
88 loc = loc if (loc is not None) else glob
87 exec compile(open(fname).read(), fname, 'exec') in glob, loc
89 exec compile(open(fname).read(), fname, 'exec') in glob, loc
General Comments 0
You need to be logged in to leave comments. Login now