##// END OF EJS Templates
Consolidate utils.pyfile into utils.openpy
Thomas Kluyver -
Show More
@@ -1,1246 +1,1246 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 Inheritance diagram:
63 Inheritance diagram:
64
64
65 .. inheritance-diagram:: IPython.core.ultratb
65 .. inheritance-diagram:: IPython.core.ultratb
66 :parts: 3
66 :parts: 3
67 """
67 """
68
68
69 #*****************************************************************************
69 #*****************************************************************************
70 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
70 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
71 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
71 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
72 #
72 #
73 # Distributed under the terms of the BSD License. The full license is in
73 # Distributed under the terms of the BSD License. The full license is in
74 # the file COPYING, distributed as part of this software.
74 # the file COPYING, distributed as part of this software.
75 #*****************************************************************************
75 #*****************************************************************************
76
76
77 from __future__ import unicode_literals
77 from __future__ import unicode_literals
78
78
79 import inspect
79 import inspect
80 import keyword
80 import keyword
81 import linecache
81 import linecache
82 import os
82 import os
83 import pydoc
83 import pydoc
84 import re
84 import re
85 import sys
85 import sys
86 import time
86 import time
87 import tokenize
87 import tokenize
88 import traceback
88 import traceback
89 import types
89 import types
90
90
91 try: # Python 2
91 try: # Python 2
92 generate_tokens = tokenize.generate_tokens
92 generate_tokens = tokenize.generate_tokens
93 except AttributeError: # Python 3
93 except AttributeError: # Python 3
94 generate_tokens = tokenize.tokenize
94 generate_tokens = tokenize.tokenize
95
95
96 # For purposes of monkeypatching inspect to fix a bug in it.
96 # For purposes of monkeypatching inspect to fix a bug in it.
97 from inspect import getsourcefile, getfile, getmodule,\
97 from inspect import getsourcefile, getfile, getmodule,\
98 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
98 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
99
99
100 # IPython's own modules
100 # IPython's own modules
101 # Modified pdb which doesn't damage IPython's readline handling
101 # Modified pdb which doesn't damage IPython's readline handling
102 from IPython.core import debugger, ipapi
102 from IPython.core import debugger, ipapi
103 from IPython.core.display_trap import DisplayTrap
103 from IPython.core.display_trap import DisplayTrap
104 from IPython.core.excolors import exception_colors
104 from IPython.core.excolors import exception_colors
105 from IPython.utils import PyColorize
105 from IPython.utils import PyColorize
106 from IPython.utils import io
106 from IPython.utils import io
107 from IPython.utils import openpy
107 from IPython.utils import path as util_path
108 from IPython.utils import path as util_path
108 from IPython.utils import py3compat
109 from IPython.utils import py3compat
109 from IPython.utils import pyfile
110 from IPython.utils import ulinecache
110 from IPython.utils import ulinecache
111 from IPython.utils.data import uniq_stable
111 from IPython.utils.data import uniq_stable
112 from IPython.utils.warn import info, error
112 from IPython.utils.warn import info, error
113
113
114 # Globals
114 # Globals
115 # amount of space to put line numbers before verbose tracebacks
115 # amount of space to put line numbers before verbose tracebacks
116 INDENT_SIZE = 8
116 INDENT_SIZE = 8
117
117
118 # Default color scheme. This is used, for example, by the traceback
118 # Default color scheme. This is used, for example, by the traceback
119 # formatter. When running in an actual IPython instance, the user's rc.colors
119 # formatter. When running in an actual IPython instance, the user's rc.colors
120 # value is used, but havinga module global makes this functionality available
120 # value is used, but havinga module global makes this functionality available
121 # to users of ultratb who are NOT running inside ipython.
121 # to users of ultratb who are NOT running inside ipython.
122 DEFAULT_SCHEME = 'NoColor'
122 DEFAULT_SCHEME = 'NoColor'
123
123
124 #---------------------------------------------------------------------------
124 #---------------------------------------------------------------------------
125 # Code begins
125 # Code begins
126
126
127 # Utility functions
127 # Utility functions
128 def inspect_error():
128 def inspect_error():
129 """Print a message about internal inspect errors.
129 """Print a message about internal inspect errors.
130
130
131 These are unfortunately quite common."""
131 These are unfortunately quite common."""
132
132
133 error('Internal Python error in the inspect module.\n'
133 error('Internal Python error in the inspect module.\n'
134 'Below is the traceback from this internal error.\n')
134 'Below is the traceback from this internal error.\n')
135
135
136 # This function is a monkeypatch we apply to the Python inspect module. We have
136 # This function is a monkeypatch we apply to the Python inspect module. We have
137 # now found when it's needed (see discussion on issue gh-1456), and we have a
137 # now found when it's needed (see discussion on issue gh-1456), and we have a
138 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
138 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
139 # the monkeypatch is not applied. TK, Aug 2012.
139 # the monkeypatch is not applied. TK, Aug 2012.
140 def findsource(object):
140 def findsource(object):
141 """Return the entire source file and starting line number for an object.
141 """Return the entire source file and starting line number for an object.
142
142
143 The argument may be a module, class, method, function, traceback, frame,
143 The argument may be a module, class, method, function, traceback, frame,
144 or code object. The source code is returned as a list of all the lines
144 or code object. The source code is returned as a list of all the lines
145 in the file and the line number indexes a line in that list. An IOError
145 in the file and the line number indexes a line in that list. An IOError
146 is raised if the source code cannot be retrieved.
146 is raised if the source code cannot be retrieved.
147
147
148 FIXED version with which we monkeypatch the stdlib to work around a bug."""
148 FIXED version with which we monkeypatch the stdlib to work around a bug."""
149
149
150 file = getsourcefile(object) or getfile(object)
150 file = getsourcefile(object) or getfile(object)
151 # If the object is a frame, then trying to get the globals dict from its
151 # If the object is a frame, then trying to get the globals dict from its
152 # module won't work. Instead, the frame object itself has the globals
152 # module won't work. Instead, the frame object itself has the globals
153 # dictionary.
153 # dictionary.
154 globals_dict = None
154 globals_dict = None
155 if inspect.isframe(object):
155 if inspect.isframe(object):
156 # XXX: can this ever be false?
156 # XXX: can this ever be false?
157 globals_dict = object.f_globals
157 globals_dict = object.f_globals
158 else:
158 else:
159 module = getmodule(object, file)
159 module = getmodule(object, file)
160 if module:
160 if module:
161 globals_dict = module.__dict__
161 globals_dict = module.__dict__
162 lines = linecache.getlines(file, globals_dict)
162 lines = linecache.getlines(file, globals_dict)
163 if not lines:
163 if not lines:
164 raise IOError('could not get source code')
164 raise IOError('could not get source code')
165
165
166 if ismodule(object):
166 if ismodule(object):
167 return lines, 0
167 return lines, 0
168
168
169 if isclass(object):
169 if isclass(object):
170 name = object.__name__
170 name = object.__name__
171 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
171 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
172 # make some effort to find the best matching class definition:
172 # make some effort to find the best matching class definition:
173 # use the one with the least indentation, which is the one
173 # use the one with the least indentation, which is the one
174 # that's most probably not inside a function definition.
174 # that's most probably not inside a function definition.
175 candidates = []
175 candidates = []
176 for i in range(len(lines)):
176 for i in range(len(lines)):
177 match = pat.match(lines[i])
177 match = pat.match(lines[i])
178 if match:
178 if match:
179 # if it's at toplevel, it's already the best one
179 # if it's at toplevel, it's already the best one
180 if lines[i][0] == 'c':
180 if lines[i][0] == 'c':
181 return lines, i
181 return lines, i
182 # else add whitespace to candidate list
182 # else add whitespace to candidate list
183 candidates.append((match.group(1), i))
183 candidates.append((match.group(1), i))
184 if candidates:
184 if candidates:
185 # this will sort by whitespace, and by line number,
185 # this will sort by whitespace, and by line number,
186 # less whitespace first
186 # less whitespace first
187 candidates.sort()
187 candidates.sort()
188 return lines, candidates[0][1]
188 return lines, candidates[0][1]
189 else:
189 else:
190 raise IOError('could not find class definition')
190 raise IOError('could not find class definition')
191
191
192 if ismethod(object):
192 if ismethod(object):
193 object = object.im_func
193 object = object.im_func
194 if isfunction(object):
194 if isfunction(object):
195 object = object.func_code
195 object = object.func_code
196 if istraceback(object):
196 if istraceback(object):
197 object = object.tb_frame
197 object = object.tb_frame
198 if isframe(object):
198 if isframe(object):
199 object = object.f_code
199 object = object.f_code
200 if iscode(object):
200 if iscode(object):
201 if not hasattr(object, 'co_firstlineno'):
201 if not hasattr(object, 'co_firstlineno'):
202 raise IOError('could not find function definition')
202 raise IOError('could not find function definition')
203 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
203 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
204 pmatch = pat.match
204 pmatch = pat.match
205 # fperez - fix: sometimes, co_firstlineno can give a number larger than
205 # fperez - fix: sometimes, co_firstlineno can give a number larger than
206 # the length of lines, which causes an error. Safeguard against that.
206 # the length of lines, which causes an error. Safeguard against that.
207 lnum = min(object.co_firstlineno,len(lines))-1
207 lnum = min(object.co_firstlineno,len(lines))-1
208 while lnum > 0:
208 while lnum > 0:
209 if pmatch(lines[lnum]): break
209 if pmatch(lines[lnum]): break
210 lnum -= 1
210 lnum -= 1
211
211
212 return lines, lnum
212 return lines, lnum
213 raise IOError('could not find code object')
213 raise IOError('could not find code object')
214
214
215 # Monkeypatch inspect to apply our bugfix. This code only works with Python >= 2.5
215 # Monkeypatch inspect to apply our bugfix. This code only works with Python >= 2.5
216 inspect.findsource = findsource
216 inspect.findsource = findsource
217
217
218 def fix_frame_records_filenames(records):
218 def fix_frame_records_filenames(records):
219 """Try to fix the filenames in each record from inspect.getinnerframes().
219 """Try to fix the filenames in each record from inspect.getinnerframes().
220
220
221 Particularly, modules loaded from within zip files have useless filenames
221 Particularly, modules loaded from within zip files have useless filenames
222 attached to their code object, and inspect.getinnerframes() just uses it.
222 attached to their code object, and inspect.getinnerframes() just uses it.
223 """
223 """
224 fixed_records = []
224 fixed_records = []
225 for frame, filename, line_no, func_name, lines, index in records:
225 for frame, filename, line_no, func_name, lines, index in records:
226 # Look inside the frame's globals dictionary for __file__, which should
226 # Look inside the frame's globals dictionary for __file__, which should
227 # be better.
227 # be better.
228 better_fn = frame.f_globals.get('__file__', None)
228 better_fn = frame.f_globals.get('__file__', None)
229 if isinstance(better_fn, str):
229 if isinstance(better_fn, str):
230 # Check the type just in case someone did something weird with
230 # Check the type just in case someone did something weird with
231 # __file__. It might also be None if the error occurred during
231 # __file__. It might also be None if the error occurred during
232 # import.
232 # import.
233 filename = better_fn
233 filename = better_fn
234 fixed_records.append((frame, filename, line_no, func_name, lines, index))
234 fixed_records.append((frame, filename, line_no, func_name, lines, index))
235 return fixed_records
235 return fixed_records
236
236
237
237
238 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
238 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
239 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
239 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
240
240
241 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
241 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
242
242
243 # If the error is at the console, don't build any context, since it would
243 # If the error is at the console, don't build any context, since it would
244 # otherwise produce 5 blank lines printed out (there is no file at the
244 # otherwise produce 5 blank lines printed out (there is no file at the
245 # console)
245 # console)
246 rec_check = records[tb_offset:]
246 rec_check = records[tb_offset:]
247 try:
247 try:
248 rname = rec_check[0][1]
248 rname = rec_check[0][1]
249 if rname == '<ipython console>' or rname.endswith('<string>'):
249 if rname == '<ipython console>' or rname.endswith('<string>'):
250 return rec_check
250 return rec_check
251 except IndexError:
251 except IndexError:
252 pass
252 pass
253
253
254 aux = traceback.extract_tb(etb)
254 aux = traceback.extract_tb(etb)
255 assert len(records) == len(aux)
255 assert len(records) == len(aux)
256 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
256 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
257 maybeStart = lnum-1 - context//2
257 maybeStart = lnum-1 - context//2
258 start = max(maybeStart, 0)
258 start = max(maybeStart, 0)
259 end = start + context
259 end = start + context
260 lines = ulinecache.getlines(file)[start:end]
260 lines = ulinecache.getlines(file)[start:end]
261 buf = list(records[i])
261 buf = list(records[i])
262 buf[LNUM_POS] = lnum
262 buf[LNUM_POS] = lnum
263 buf[INDEX_POS] = lnum - 1 - start
263 buf[INDEX_POS] = lnum - 1 - start
264 buf[LINES_POS] = lines
264 buf[LINES_POS] = lines
265 records[i] = tuple(buf)
265 records[i] = tuple(buf)
266 return records[tb_offset:]
266 return records[tb_offset:]
267
267
268 # Helper function -- largely belongs to VerboseTB, but we need the same
268 # Helper function -- largely belongs to VerboseTB, but we need the same
269 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
269 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
270 # can be recognized properly by ipython.el's py-traceback-line-re
270 # can be recognized properly by ipython.el's py-traceback-line-re
271 # (SyntaxErrors have to be treated specially because they have no traceback)
271 # (SyntaxErrors have to be treated specially because they have no traceback)
272
272
273 _parser = PyColorize.Parser()
273 _parser = PyColorize.Parser()
274
274
275 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
275 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
276 numbers_width = INDENT_SIZE - 1
276 numbers_width = INDENT_SIZE - 1
277 res = []
277 res = []
278 i = lnum - index
278 i = lnum - index
279
279
280 # This lets us get fully syntax-highlighted tracebacks.
280 # This lets us get fully syntax-highlighted tracebacks.
281 if scheme is None:
281 if scheme is None:
282 ipinst = ipapi.get()
282 ipinst = ipapi.get()
283 if ipinst is not None:
283 if ipinst is not None:
284 scheme = ipinst.colors
284 scheme = ipinst.colors
285 else:
285 else:
286 scheme = DEFAULT_SCHEME
286 scheme = DEFAULT_SCHEME
287
287
288 _line_format = _parser.format2
288 _line_format = _parser.format2
289
289
290 for line in lines:
290 for line in lines:
291 line = py3compat.cast_unicode(line)
291 line = py3compat.cast_unicode(line)
292
292
293 new_line, err = _line_format(line, 'str', scheme)
293 new_line, err = _line_format(line, 'str', scheme)
294 if not err: line = new_line
294 if not err: line = new_line
295
295
296 if i == lnum:
296 if i == lnum:
297 # This is the line with the error
297 # This is the line with the error
298 pad = numbers_width - len(str(i))
298 pad = numbers_width - len(str(i))
299 if pad >= 3:
299 if pad >= 3:
300 marker = '-'*(pad-3) + '-> '
300 marker = '-'*(pad-3) + '-> '
301 elif pad == 2:
301 elif pad == 2:
302 marker = '> '
302 marker = '> '
303 elif pad == 1:
303 elif pad == 1:
304 marker = '>'
304 marker = '>'
305 else:
305 else:
306 marker = ''
306 marker = ''
307 num = marker + str(i)
307 num = marker + str(i)
308 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
308 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
309 Colors.line, line, Colors.Normal)
309 Colors.line, line, Colors.Normal)
310 else:
310 else:
311 num = '%*s' % (numbers_width,i)
311 num = '%*s' % (numbers_width,i)
312 line = '%s%s%s %s' %(Colors.lineno, num,
312 line = '%s%s%s %s' %(Colors.lineno, num,
313 Colors.Normal, line)
313 Colors.Normal, line)
314
314
315 res.append(line)
315 res.append(line)
316 if lvals and i == lnum:
316 if lvals and i == lnum:
317 res.append(lvals + '\n')
317 res.append(lvals + '\n')
318 i = i + 1
318 i = i + 1
319 return res
319 return res
320
320
321
321
322 #---------------------------------------------------------------------------
322 #---------------------------------------------------------------------------
323 # Module classes
323 # Module classes
324 class TBTools(object):
324 class TBTools(object):
325 """Basic tools used by all traceback printer classes."""
325 """Basic tools used by all traceback printer classes."""
326
326
327 # Number of frames to skip when reporting tracebacks
327 # Number of frames to skip when reporting tracebacks
328 tb_offset = 0
328 tb_offset = 0
329
329
330 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
330 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
331 # Whether to call the interactive pdb debugger after printing
331 # Whether to call the interactive pdb debugger after printing
332 # tracebacks or not
332 # tracebacks or not
333 self.call_pdb = call_pdb
333 self.call_pdb = call_pdb
334
334
335 # Output stream to write to. Note that we store the original value in
335 # Output stream to write to. Note that we store the original value in
336 # a private attribute and then make the public ostream a property, so
336 # a private attribute and then make the public ostream a property, so
337 # that we can delay accessing io.stdout until runtime. The way
337 # that we can delay accessing io.stdout until runtime. The way
338 # things are written now, the io.stdout object is dynamically managed
338 # things are written now, the io.stdout object is dynamically managed
339 # so a reference to it should NEVER be stored statically. This
339 # so a reference to it should NEVER be stored statically. This
340 # property approach confines this detail to a single location, and all
340 # property approach confines this detail to a single location, and all
341 # subclasses can simply access self.ostream for writing.
341 # subclasses can simply access self.ostream for writing.
342 self._ostream = ostream
342 self._ostream = ostream
343
343
344 # Create color table
344 # Create color table
345 self.color_scheme_table = exception_colors()
345 self.color_scheme_table = exception_colors()
346
346
347 self.set_colors(color_scheme)
347 self.set_colors(color_scheme)
348 self.old_scheme = color_scheme # save initial value for toggles
348 self.old_scheme = color_scheme # save initial value for toggles
349
349
350 if call_pdb:
350 if call_pdb:
351 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
351 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
352 else:
352 else:
353 self.pdb = None
353 self.pdb = None
354
354
355 def _get_ostream(self):
355 def _get_ostream(self):
356 """Output stream that exceptions are written to.
356 """Output stream that exceptions are written to.
357
357
358 Valid values are:
358 Valid values are:
359
359
360 - None: the default, which means that IPython will dynamically resolve
360 - None: the default, which means that IPython will dynamically resolve
361 to io.stdout. This ensures compatibility with most tools, including
361 to io.stdout. This ensures compatibility with most tools, including
362 Windows (where plain stdout doesn't recognize ANSI escapes).
362 Windows (where plain stdout doesn't recognize ANSI escapes).
363
363
364 - Any object with 'write' and 'flush' attributes.
364 - Any object with 'write' and 'flush' attributes.
365 """
365 """
366 return io.stdout if self._ostream is None else self._ostream
366 return io.stdout if self._ostream is None else self._ostream
367
367
368 def _set_ostream(self, val):
368 def _set_ostream(self, val):
369 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
369 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
370 self._ostream = val
370 self._ostream = val
371
371
372 ostream = property(_get_ostream, _set_ostream)
372 ostream = property(_get_ostream, _set_ostream)
373
373
374 def set_colors(self,*args,**kw):
374 def set_colors(self,*args,**kw):
375 """Shorthand access to the color table scheme selector method."""
375 """Shorthand access to the color table scheme selector method."""
376
376
377 # Set own color table
377 # Set own color table
378 self.color_scheme_table.set_active_scheme(*args,**kw)
378 self.color_scheme_table.set_active_scheme(*args,**kw)
379 # for convenience, set Colors to the active scheme
379 # for convenience, set Colors to the active scheme
380 self.Colors = self.color_scheme_table.active_colors
380 self.Colors = self.color_scheme_table.active_colors
381 # Also set colors of debugger
381 # Also set colors of debugger
382 if hasattr(self,'pdb') and self.pdb is not None:
382 if hasattr(self,'pdb') and self.pdb is not None:
383 self.pdb.set_colors(*args,**kw)
383 self.pdb.set_colors(*args,**kw)
384
384
385 def color_toggle(self):
385 def color_toggle(self):
386 """Toggle between the currently active color scheme and NoColor."""
386 """Toggle between the currently active color scheme and NoColor."""
387
387
388 if self.color_scheme_table.active_scheme_name == 'NoColor':
388 if self.color_scheme_table.active_scheme_name == 'NoColor':
389 self.color_scheme_table.set_active_scheme(self.old_scheme)
389 self.color_scheme_table.set_active_scheme(self.old_scheme)
390 self.Colors = self.color_scheme_table.active_colors
390 self.Colors = self.color_scheme_table.active_colors
391 else:
391 else:
392 self.old_scheme = self.color_scheme_table.active_scheme_name
392 self.old_scheme = self.color_scheme_table.active_scheme_name
393 self.color_scheme_table.set_active_scheme('NoColor')
393 self.color_scheme_table.set_active_scheme('NoColor')
394 self.Colors = self.color_scheme_table.active_colors
394 self.Colors = self.color_scheme_table.active_colors
395
395
396 def stb2text(self, stb):
396 def stb2text(self, stb):
397 """Convert a structured traceback (a list) to a string."""
397 """Convert a structured traceback (a list) to a string."""
398 return '\n'.join(stb)
398 return '\n'.join(stb)
399
399
400 def text(self, etype, value, tb, tb_offset=None, context=5):
400 def text(self, etype, value, tb, tb_offset=None, context=5):
401 """Return formatted traceback.
401 """Return formatted traceback.
402
402
403 Subclasses may override this if they add extra arguments.
403 Subclasses may override this if they add extra arguments.
404 """
404 """
405 tb_list = self.structured_traceback(etype, value, tb,
405 tb_list = self.structured_traceback(etype, value, tb,
406 tb_offset, context)
406 tb_offset, context)
407 return self.stb2text(tb_list)
407 return self.stb2text(tb_list)
408
408
409 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
409 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
410 context=5, mode=None):
410 context=5, mode=None):
411 """Return a list of traceback frames.
411 """Return a list of traceback frames.
412
412
413 Must be implemented by each class.
413 Must be implemented by each class.
414 """
414 """
415 raise NotImplementedError()
415 raise NotImplementedError()
416
416
417
417
418 #---------------------------------------------------------------------------
418 #---------------------------------------------------------------------------
419 class ListTB(TBTools):
419 class ListTB(TBTools):
420 """Print traceback information from a traceback list, with optional color.
420 """Print traceback information from a traceback list, with optional color.
421
421
422 Calling requires 3 arguments: (etype, evalue, elist)
422 Calling requires 3 arguments: (etype, evalue, elist)
423 as would be obtained by::
423 as would be obtained by::
424
424
425 etype, evalue, tb = sys.exc_info()
425 etype, evalue, tb = sys.exc_info()
426 if tb:
426 if tb:
427 elist = traceback.extract_tb(tb)
427 elist = traceback.extract_tb(tb)
428 else:
428 else:
429 elist = None
429 elist = None
430
430
431 It can thus be used by programs which need to process the traceback before
431 It can thus be used by programs which need to process the traceback before
432 printing (such as console replacements based on the code module from the
432 printing (such as console replacements based on the code module from the
433 standard library).
433 standard library).
434
434
435 Because they are meant to be called without a full traceback (only a
435 Because they are meant to be called without a full traceback (only a
436 list), instances of this class can't call the interactive pdb debugger."""
436 list), instances of this class can't call the interactive pdb debugger."""
437
437
438 def __init__(self,color_scheme = 'NoColor', call_pdb=False, ostream=None):
438 def __init__(self,color_scheme = 'NoColor', call_pdb=False, ostream=None):
439 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
439 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
440 ostream=ostream)
440 ostream=ostream)
441
441
442 def __call__(self, etype, value, elist):
442 def __call__(self, etype, value, elist):
443 self.ostream.flush()
443 self.ostream.flush()
444 self.ostream.write(self.text(etype, value, elist))
444 self.ostream.write(self.text(etype, value, elist))
445 self.ostream.write('\n')
445 self.ostream.write('\n')
446
446
447 def structured_traceback(self, etype, value, elist, tb_offset=None,
447 def structured_traceback(self, etype, value, elist, tb_offset=None,
448 context=5):
448 context=5):
449 """Return a color formatted string with the traceback info.
449 """Return a color formatted string with the traceback info.
450
450
451 Parameters
451 Parameters
452 ----------
452 ----------
453 etype : exception type
453 etype : exception type
454 Type of the exception raised.
454 Type of the exception raised.
455
455
456 value : object
456 value : object
457 Data stored in the exception
457 Data stored in the exception
458
458
459 elist : list
459 elist : list
460 List of frames, see class docstring for details.
460 List of frames, see class docstring for details.
461
461
462 tb_offset : int, optional
462 tb_offset : int, optional
463 Number of frames in the traceback to skip. If not given, the
463 Number of frames in the traceback to skip. If not given, the
464 instance value is used (set in constructor).
464 instance value is used (set in constructor).
465
465
466 context : int, optional
466 context : int, optional
467 Number of lines of context information to print.
467 Number of lines of context information to print.
468
468
469 Returns
469 Returns
470 -------
470 -------
471 String with formatted exception.
471 String with formatted exception.
472 """
472 """
473 tb_offset = self.tb_offset if tb_offset is None else tb_offset
473 tb_offset = self.tb_offset if tb_offset is None else tb_offset
474 Colors = self.Colors
474 Colors = self.Colors
475 out_list = []
475 out_list = []
476 if elist:
476 if elist:
477
477
478 if tb_offset and len(elist) > tb_offset:
478 if tb_offset and len(elist) > tb_offset:
479 elist = elist[tb_offset:]
479 elist = elist[tb_offset:]
480
480
481 out_list.append('Traceback %s(most recent call last)%s:' %
481 out_list.append('Traceback %s(most recent call last)%s:' %
482 (Colors.normalEm, Colors.Normal) + '\n')
482 (Colors.normalEm, Colors.Normal) + '\n')
483 out_list.extend(self._format_list(elist))
483 out_list.extend(self._format_list(elist))
484 # The exception info should be a single entry in the list.
484 # The exception info should be a single entry in the list.
485 lines = ''.join(self._format_exception_only(etype, value))
485 lines = ''.join(self._format_exception_only(etype, value))
486 out_list.append(lines)
486 out_list.append(lines)
487
487
488 # Note: this code originally read:
488 # Note: this code originally read:
489
489
490 ## for line in lines[:-1]:
490 ## for line in lines[:-1]:
491 ## out_list.append(" "+line)
491 ## out_list.append(" "+line)
492 ## out_list.append(lines[-1])
492 ## out_list.append(lines[-1])
493
493
494 # This means it was indenting everything but the last line by a little
494 # This means it was indenting everything but the last line by a little
495 # bit. I've disabled this for now, but if we see ugliness somewhre we
495 # bit. I've disabled this for now, but if we see ugliness somewhre we
496 # can restore it.
496 # can restore it.
497
497
498 return out_list
498 return out_list
499
499
500 def _format_list(self, extracted_list):
500 def _format_list(self, extracted_list):
501 """Format a list of traceback entry tuples for printing.
501 """Format a list of traceback entry tuples for printing.
502
502
503 Given a list of tuples as returned by extract_tb() or
503 Given a list of tuples as returned by extract_tb() or
504 extract_stack(), return a list of strings ready for printing.
504 extract_stack(), return a list of strings ready for printing.
505 Each string in the resulting list corresponds to the item with the
505 Each string in the resulting list corresponds to the item with the
506 same index in the argument list. Each string ends in a newline;
506 same index in the argument list. Each string ends in a newline;
507 the strings may contain internal newlines as well, for those items
507 the strings may contain internal newlines as well, for those items
508 whose source text line is not None.
508 whose source text line is not None.
509
509
510 Lifted almost verbatim from traceback.py
510 Lifted almost verbatim from traceback.py
511 """
511 """
512
512
513 Colors = self.Colors
513 Colors = self.Colors
514 list = []
514 list = []
515 for filename, lineno, name, line in extracted_list[:-1]:
515 for filename, lineno, name, line in extracted_list[:-1]:
516 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
516 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
517 (Colors.filename, filename, Colors.Normal,
517 (Colors.filename, filename, Colors.Normal,
518 Colors.lineno, lineno, Colors.Normal,
518 Colors.lineno, lineno, Colors.Normal,
519 Colors.name, name, Colors.Normal)
519 Colors.name, name, Colors.Normal)
520 if line:
520 if line:
521 item += ' %s\n' % line.strip()
521 item += ' %s\n' % line.strip()
522 list.append(item)
522 list.append(item)
523 # Emphasize the last entry
523 # Emphasize the last entry
524 filename, lineno, name, line = extracted_list[-1]
524 filename, lineno, name, line = extracted_list[-1]
525 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
525 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
526 (Colors.normalEm,
526 (Colors.normalEm,
527 Colors.filenameEm, filename, Colors.normalEm,
527 Colors.filenameEm, filename, Colors.normalEm,
528 Colors.linenoEm, lineno, Colors.normalEm,
528 Colors.linenoEm, lineno, Colors.normalEm,
529 Colors.nameEm, name, Colors.normalEm,
529 Colors.nameEm, name, Colors.normalEm,
530 Colors.Normal)
530 Colors.Normal)
531 if line:
531 if line:
532 item += '%s %s%s\n' % (Colors.line, line.strip(),
532 item += '%s %s%s\n' % (Colors.line, line.strip(),
533 Colors.Normal)
533 Colors.Normal)
534 list.append(item)
534 list.append(item)
535 #from pprint import pformat; print 'LISTTB', pformat(list) # dbg
535 #from pprint import pformat; print 'LISTTB', pformat(list) # dbg
536 return list
536 return list
537
537
538 def _format_exception_only(self, etype, value):
538 def _format_exception_only(self, etype, value):
539 """Format the exception part of a traceback.
539 """Format the exception part of a traceback.
540
540
541 The arguments are the exception type and value such as given by
541 The arguments are the exception type and value such as given by
542 sys.exc_info()[:2]. The return value is a list of strings, each ending
542 sys.exc_info()[:2]. The return value is a list of strings, each ending
543 in a newline. Normally, the list contains a single string; however,
543 in a newline. Normally, the list contains a single string; however,
544 for SyntaxError exceptions, it contains several lines that (when
544 for SyntaxError exceptions, it contains several lines that (when
545 printed) display detailed information about where the syntax error
545 printed) display detailed information about where the syntax error
546 occurred. The message indicating which exception occurred is the
546 occurred. The message indicating which exception occurred is the
547 always last string in the list.
547 always last string in the list.
548
548
549 Also lifted nearly verbatim from traceback.py
549 Also lifted nearly verbatim from traceback.py
550 """
550 """
551 have_filedata = False
551 have_filedata = False
552 Colors = self.Colors
552 Colors = self.Colors
553 list = []
553 list = []
554 stype = Colors.excName + etype.__name__ + Colors.Normal
554 stype = Colors.excName + etype.__name__ + Colors.Normal
555 if value is None:
555 if value is None:
556 # Not sure if this can still happen in Python 2.6 and above
556 # Not sure if this can still happen in Python 2.6 and above
557 list.append( py3compat.cast_unicode(stype) + '\n')
557 list.append( py3compat.cast_unicode(stype) + '\n')
558 else:
558 else:
559 if issubclass(etype, SyntaxError):
559 if issubclass(etype, SyntaxError):
560 have_filedata = True
560 have_filedata = True
561 #print 'filename is',filename # dbg
561 #print 'filename is',filename # dbg
562 if not value.filename: value.filename = "<string>"
562 if not value.filename: value.filename = "<string>"
563 if value.lineno:
563 if value.lineno:
564 lineno = value.lineno
564 lineno = value.lineno
565 textline = ulinecache.getline(value.filename, value.lineno)
565 textline = ulinecache.getline(value.filename, value.lineno)
566 else:
566 else:
567 lineno = 'unknown'
567 lineno = 'unknown'
568 textline = ''
568 textline = ''
569 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
569 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
570 (Colors.normalEm,
570 (Colors.normalEm,
571 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
571 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
572 Colors.linenoEm, lineno, Colors.Normal ))
572 Colors.linenoEm, lineno, Colors.Normal ))
573 if textline == '':
573 if textline == '':
574 textline = py3compat.cast_unicode(value.text, "utf-8")
574 textline = py3compat.cast_unicode(value.text, "utf-8")
575
575
576 if textline is not None:
576 if textline is not None:
577 i = 0
577 i = 0
578 while i < len(textline) and textline[i].isspace():
578 while i < len(textline) and textline[i].isspace():
579 i += 1
579 i += 1
580 list.append('%s %s%s\n' % (Colors.line,
580 list.append('%s %s%s\n' % (Colors.line,
581 textline.strip(),
581 textline.strip(),
582 Colors.Normal))
582 Colors.Normal))
583 if value.offset is not None:
583 if value.offset is not None:
584 s = ' '
584 s = ' '
585 for c in textline[i:value.offset-1]:
585 for c in textline[i:value.offset-1]:
586 if c.isspace():
586 if c.isspace():
587 s += c
587 s += c
588 else:
588 else:
589 s += ' '
589 s += ' '
590 list.append('%s%s^%s\n' % (Colors.caret, s,
590 list.append('%s%s^%s\n' % (Colors.caret, s,
591 Colors.Normal) )
591 Colors.Normal) )
592
592
593 try:
593 try:
594 s = value.msg
594 s = value.msg
595 except Exception:
595 except Exception:
596 s = self._some_str(value)
596 s = self._some_str(value)
597 if s:
597 if s:
598 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
598 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
599 Colors.Normal, s))
599 Colors.Normal, s))
600 else:
600 else:
601 list.append('%s\n' % str(stype))
601 list.append('%s\n' % str(stype))
602
602
603 # sync with user hooks
603 # sync with user hooks
604 if have_filedata:
604 if have_filedata:
605 ipinst = ipapi.get()
605 ipinst = ipapi.get()
606 if ipinst is not None:
606 if ipinst is not None:
607 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
607 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
608
608
609 return list
609 return list
610
610
611 def get_exception_only(self, etype, value):
611 def get_exception_only(self, etype, value):
612 """Only print the exception type and message, without a traceback.
612 """Only print the exception type and message, without a traceback.
613
613
614 Parameters
614 Parameters
615 ----------
615 ----------
616 etype : exception type
616 etype : exception type
617 value : exception value
617 value : exception value
618 """
618 """
619 return ListTB.structured_traceback(self, etype, value, [])
619 return ListTB.structured_traceback(self, etype, value, [])
620
620
621
621
622 def show_exception_only(self, etype, evalue):
622 def show_exception_only(self, etype, evalue):
623 """Only print the exception type and message, without a traceback.
623 """Only print the exception type and message, without a traceback.
624
624
625 Parameters
625 Parameters
626 ----------
626 ----------
627 etype : exception type
627 etype : exception type
628 value : exception value
628 value : exception value
629 """
629 """
630 # This method needs to use __call__ from *this* class, not the one from
630 # This method needs to use __call__ from *this* class, not the one from
631 # a subclass whose signature or behavior may be different
631 # a subclass whose signature or behavior may be different
632 ostream = self.ostream
632 ostream = self.ostream
633 ostream.flush()
633 ostream.flush()
634 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
634 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
635 ostream.flush()
635 ostream.flush()
636
636
637 def _some_str(self, value):
637 def _some_str(self, value):
638 # Lifted from traceback.py
638 # Lifted from traceback.py
639 try:
639 try:
640 return str(value)
640 return str(value)
641 except:
641 except:
642 return '<unprintable %s object>' % type(value).__name__
642 return '<unprintable %s object>' % type(value).__name__
643
643
644 #----------------------------------------------------------------------------
644 #----------------------------------------------------------------------------
645 class VerboseTB(TBTools):
645 class VerboseTB(TBTools):
646 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
646 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
647 of HTML. Requires inspect and pydoc. Crazy, man.
647 of HTML. Requires inspect and pydoc. Crazy, man.
648
648
649 Modified version which optionally strips the topmost entries from the
649 Modified version which optionally strips the topmost entries from the
650 traceback, to be used with alternate interpreters (because their own code
650 traceback, to be used with alternate interpreters (because their own code
651 would appear in the traceback)."""
651 would appear in the traceback)."""
652
652
653 def __init__(self,color_scheme = 'Linux', call_pdb=False, ostream=None,
653 def __init__(self,color_scheme = 'Linux', call_pdb=False, ostream=None,
654 tb_offset=0, long_header=False, include_vars=True,
654 tb_offset=0, long_header=False, include_vars=True,
655 check_cache=None):
655 check_cache=None):
656 """Specify traceback offset, headers and color scheme.
656 """Specify traceback offset, headers and color scheme.
657
657
658 Define how many frames to drop from the tracebacks. Calling it with
658 Define how many frames to drop from the tracebacks. Calling it with
659 tb_offset=1 allows use of this handler in interpreters which will have
659 tb_offset=1 allows use of this handler in interpreters which will have
660 their own code at the top of the traceback (VerboseTB will first
660 their own code at the top of the traceback (VerboseTB will first
661 remove that frame before printing the traceback info)."""
661 remove that frame before printing the traceback info)."""
662 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
662 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
663 ostream=ostream)
663 ostream=ostream)
664 self.tb_offset = tb_offset
664 self.tb_offset = tb_offset
665 self.long_header = long_header
665 self.long_header = long_header
666 self.include_vars = include_vars
666 self.include_vars = include_vars
667 # By default we use linecache.checkcache, but the user can provide a
667 # By default we use linecache.checkcache, but the user can provide a
668 # different check_cache implementation. This is used by the IPython
668 # different check_cache implementation. This is used by the IPython
669 # kernel to provide tracebacks for interactive code that is cached,
669 # kernel to provide tracebacks for interactive code that is cached,
670 # by a compiler instance that flushes the linecache but preserves its
670 # by a compiler instance that flushes the linecache but preserves its
671 # own code cache.
671 # own code cache.
672 if check_cache is None:
672 if check_cache is None:
673 check_cache = linecache.checkcache
673 check_cache = linecache.checkcache
674 self.check_cache = check_cache
674 self.check_cache = check_cache
675
675
676 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
676 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
677 context=5):
677 context=5):
678 """Return a nice text document describing the traceback."""
678 """Return a nice text document describing the traceback."""
679
679
680 tb_offset = self.tb_offset if tb_offset is None else tb_offset
680 tb_offset = self.tb_offset if tb_offset is None else tb_offset
681
681
682 # some locals
682 # some locals
683 try:
683 try:
684 etype = etype.__name__
684 etype = etype.__name__
685 except AttributeError:
685 except AttributeError:
686 pass
686 pass
687 Colors = self.Colors # just a shorthand + quicker name lookup
687 Colors = self.Colors # just a shorthand + quicker name lookup
688 ColorsNormal = Colors.Normal # used a lot
688 ColorsNormal = Colors.Normal # used a lot
689 col_scheme = self.color_scheme_table.active_scheme_name
689 col_scheme = self.color_scheme_table.active_scheme_name
690 indent = ' '*INDENT_SIZE
690 indent = ' '*INDENT_SIZE
691 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
691 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
692 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
692 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
693 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
693 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
694
694
695 # some internal-use functions
695 # some internal-use functions
696 def text_repr(value):
696 def text_repr(value):
697 """Hopefully pretty robust repr equivalent."""
697 """Hopefully pretty robust repr equivalent."""
698 # this is pretty horrible but should always return *something*
698 # this is pretty horrible but should always return *something*
699 try:
699 try:
700 return pydoc.text.repr(value)
700 return pydoc.text.repr(value)
701 except KeyboardInterrupt:
701 except KeyboardInterrupt:
702 raise
702 raise
703 except:
703 except:
704 try:
704 try:
705 return repr(value)
705 return repr(value)
706 except KeyboardInterrupt:
706 except KeyboardInterrupt:
707 raise
707 raise
708 except:
708 except:
709 try:
709 try:
710 # all still in an except block so we catch
710 # all still in an except block so we catch
711 # getattr raising
711 # getattr raising
712 name = getattr(value, '__name__', None)
712 name = getattr(value, '__name__', None)
713 if name:
713 if name:
714 # ick, recursion
714 # ick, recursion
715 return text_repr(name)
715 return text_repr(name)
716 klass = getattr(value, '__class__', None)
716 klass = getattr(value, '__class__', None)
717 if klass:
717 if klass:
718 return '%s instance' % text_repr(klass)
718 return '%s instance' % text_repr(klass)
719 except KeyboardInterrupt:
719 except KeyboardInterrupt:
720 raise
720 raise
721 except:
721 except:
722 return 'UNRECOVERABLE REPR FAILURE'
722 return 'UNRECOVERABLE REPR FAILURE'
723 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
723 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
724 def nullrepr(value, repr=text_repr): return ''
724 def nullrepr(value, repr=text_repr): return ''
725
725
726 # meat of the code begins
726 # meat of the code begins
727 try:
727 try:
728 etype = etype.__name__
728 etype = etype.__name__
729 except AttributeError:
729 except AttributeError:
730 pass
730 pass
731
731
732 if self.long_header:
732 if self.long_header:
733 # Header with the exception type, python version, and date
733 # Header with the exception type, python version, and date
734 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
734 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
735 date = time.ctime(time.time())
735 date = time.ctime(time.time())
736
736
737 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
737 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
738 exc, ' '*(75-len(str(etype))-len(pyver)),
738 exc, ' '*(75-len(str(etype))-len(pyver)),
739 pyver, date.rjust(75) )
739 pyver, date.rjust(75) )
740 head += "\nA problem occured executing Python code. Here is the sequence of function"\
740 head += "\nA problem occured executing Python code. Here is the sequence of function"\
741 "\ncalls leading up to the error, with the most recent (innermost) call last."
741 "\ncalls leading up to the error, with the most recent (innermost) call last."
742 else:
742 else:
743 # Simplified header
743 # Simplified header
744 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
744 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
745 'Traceback (most recent call last)'.\
745 'Traceback (most recent call last)'.\
746 rjust(75 - len(str(etype)) ) )
746 rjust(75 - len(str(etype)) ) )
747 frames = []
747 frames = []
748 # Flush cache before calling inspect. This helps alleviate some of the
748 # Flush cache before calling inspect. This helps alleviate some of the
749 # problems with python 2.3's inspect.py.
749 # problems with python 2.3's inspect.py.
750 ##self.check_cache()
750 ##self.check_cache()
751 # Drop topmost frames if requested
751 # Drop topmost frames if requested
752 try:
752 try:
753 # Try the default getinnerframes and Alex's: Alex's fixes some
753 # Try the default getinnerframes and Alex's: Alex's fixes some
754 # problems, but it generates empty tracebacks for console errors
754 # problems, but it generates empty tracebacks for console errors
755 # (5 blanks lines) where none should be returned.
755 # (5 blanks lines) where none should be returned.
756 #records = inspect.getinnerframes(etb, context)[tb_offset:]
756 #records = inspect.getinnerframes(etb, context)[tb_offset:]
757 #print 'python records:', records # dbg
757 #print 'python records:', records # dbg
758 records = _fixed_getinnerframes(etb, context, tb_offset)
758 records = _fixed_getinnerframes(etb, context, tb_offset)
759 #print 'alex records:', records # dbg
759 #print 'alex records:', records # dbg
760 except:
760 except:
761
761
762 # FIXME: I've been getting many crash reports from python 2.3
762 # FIXME: I've been getting many crash reports from python 2.3
763 # users, traceable to inspect.py. If I can find a small test-case
763 # users, traceable to inspect.py. If I can find a small test-case
764 # to reproduce this, I should either write a better workaround or
764 # to reproduce this, I should either write a better workaround or
765 # file a bug report against inspect (if that's the real problem).
765 # file a bug report against inspect (if that's the real problem).
766 # So far, I haven't been able to find an isolated example to
766 # So far, I haven't been able to find an isolated example to
767 # reproduce the problem.
767 # reproduce the problem.
768 inspect_error()
768 inspect_error()
769 traceback.print_exc(file=self.ostream)
769 traceback.print_exc(file=self.ostream)
770 info('\nUnfortunately, your original traceback can not be constructed.\n')
770 info('\nUnfortunately, your original traceback can not be constructed.\n')
771 return ''
771 return ''
772
772
773 # build some color string templates outside these nested loops
773 # build some color string templates outside these nested loops
774 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
774 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
775 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
775 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
776 ColorsNormal)
776 ColorsNormal)
777 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
777 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
778 (Colors.vName, Colors.valEm, ColorsNormal)
778 (Colors.vName, Colors.valEm, ColorsNormal)
779 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
779 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
780 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
780 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
781 Colors.vName, ColorsNormal)
781 Colors.vName, ColorsNormal)
782 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
782 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
783 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
783 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
784 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
784 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
785 ColorsNormal)
785 ColorsNormal)
786
786
787 # now, loop over all records printing context and info
787 # now, loop over all records printing context and info
788 abspath = os.path.abspath
788 abspath = os.path.abspath
789 for frame, file, lnum, func, lines, index in records:
789 for frame, file, lnum, func, lines, index in records:
790 #print '*** record:',file,lnum,func,lines,index # dbg
790 #print '*** record:',file,lnum,func,lines,index # dbg
791 if not file:
791 if not file:
792 file = '?'
792 file = '?'
793 elif not(file.startswith(str("<")) and file.endswith(str(">"))):
793 elif not(file.startswith(str("<")) and file.endswith(str(">"))):
794 # Guess that filenames like <string> aren't real filenames, so
794 # Guess that filenames like <string> aren't real filenames, so
795 # don't call abspath on them.
795 # don't call abspath on them.
796 try:
796 try:
797 file = abspath(file)
797 file = abspath(file)
798 except OSError:
798 except OSError:
799 # Not sure if this can still happen: abspath now works with
799 # Not sure if this can still happen: abspath now works with
800 # file names like <string>
800 # file names like <string>
801 pass
801 pass
802 file = py3compat.cast_unicode(file, util_path.fs_encoding)
802 file = py3compat.cast_unicode(file, util_path.fs_encoding)
803 link = tpl_link % file
803 link = tpl_link % file
804 args, varargs, varkw, locals = inspect.getargvalues(frame)
804 args, varargs, varkw, locals = inspect.getargvalues(frame)
805
805
806 if func == '?':
806 if func == '?':
807 call = ''
807 call = ''
808 else:
808 else:
809 # Decide whether to include variable details or not
809 # Decide whether to include variable details or not
810 var_repr = self.include_vars and eqrepr or nullrepr
810 var_repr = self.include_vars and eqrepr or nullrepr
811 try:
811 try:
812 call = tpl_call % (func,inspect.formatargvalues(args,
812 call = tpl_call % (func,inspect.formatargvalues(args,
813 varargs, varkw,
813 varargs, varkw,
814 locals,formatvalue=var_repr))
814 locals,formatvalue=var_repr))
815 except KeyError:
815 except KeyError:
816 # This happens in situations like errors inside generator
816 # This happens in situations like errors inside generator
817 # expressions, where local variables are listed in the
817 # expressions, where local variables are listed in the
818 # line, but can't be extracted from the frame. I'm not
818 # line, but can't be extracted from the frame. I'm not
819 # 100% sure this isn't actually a bug in inspect itself,
819 # 100% sure this isn't actually a bug in inspect itself,
820 # but since there's no info for us to compute with, the
820 # but since there's no info for us to compute with, the
821 # best we can do is report the failure and move on. Here
821 # best we can do is report the failure and move on. Here
822 # we must *not* call any traceback construction again,
822 # we must *not* call any traceback construction again,
823 # because that would mess up use of %debug later on. So we
823 # because that would mess up use of %debug later on. So we
824 # simply report the failure and move on. The only
824 # simply report the failure and move on. The only
825 # limitation will be that this frame won't have locals
825 # limitation will be that this frame won't have locals
826 # listed in the call signature. Quite subtle problem...
826 # listed in the call signature. Quite subtle problem...
827 # I can't think of a good way to validate this in a unit
827 # I can't think of a good way to validate this in a unit
828 # test, but running a script consisting of:
828 # test, but running a script consisting of:
829 # dict( (k,v.strip()) for (k,v) in range(10) )
829 # dict( (k,v.strip()) for (k,v) in range(10) )
830 # will illustrate the error, if this exception catch is
830 # will illustrate the error, if this exception catch is
831 # disabled.
831 # disabled.
832 call = tpl_call_fail % func
832 call = tpl_call_fail % func
833
833
834 # Don't attempt to tokenize binary files.
834 # Don't attempt to tokenize binary files.
835 if file.endswith(('.so', '.pyd', '.dll')):
835 if file.endswith(('.so', '.pyd', '.dll')):
836 frames.append('%s %s\n' % (link,call))
836 frames.append('%s %s\n' % (link,call))
837 continue
837 continue
838 elif file.endswith(('.pyc','.pyo')):
838 elif file.endswith(('.pyc','.pyo')):
839 # Look up the corresponding source file.
839 # Look up the corresponding source file.
840 file = pyfile.source_from_cache(file)
840 file = openpy.source_from_cache(file)
841
841
842 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
842 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
843 line = getline(file, lnum[0])
843 line = getline(file, lnum[0])
844 lnum[0] += 1
844 lnum[0] += 1
845 return line
845 return line
846
846
847 # Build the list of names on this line of code where the exception
847 # Build the list of names on this line of code where the exception
848 # occurred.
848 # occurred.
849 try:
849 try:
850 names = []
850 names = []
851 name_cont = False
851 name_cont = False
852
852
853 for token_type, token, start, end, line in generate_tokens(linereader):
853 for token_type, token, start, end, line in generate_tokens(linereader):
854 # build composite names
854 # build composite names
855 if token_type == tokenize.NAME and token not in keyword.kwlist:
855 if token_type == tokenize.NAME and token not in keyword.kwlist:
856 if name_cont:
856 if name_cont:
857 # Continuation of a dotted name
857 # Continuation of a dotted name
858 try:
858 try:
859 names[-1].append(token)
859 names[-1].append(token)
860 except IndexError:
860 except IndexError:
861 names.append([token])
861 names.append([token])
862 name_cont = False
862 name_cont = False
863 else:
863 else:
864 # Regular new names. We append everything, the caller
864 # Regular new names. We append everything, the caller
865 # will be responsible for pruning the list later. It's
865 # will be responsible for pruning the list later. It's
866 # very tricky to try to prune as we go, b/c composite
866 # very tricky to try to prune as we go, b/c composite
867 # names can fool us. The pruning at the end is easy
867 # names can fool us. The pruning at the end is easy
868 # to do (or the caller can print a list with repeated
868 # to do (or the caller can print a list with repeated
869 # names if so desired.
869 # names if so desired.
870 names.append([token])
870 names.append([token])
871 elif token == '.':
871 elif token == '.':
872 name_cont = True
872 name_cont = True
873 elif token_type == tokenize.NEWLINE:
873 elif token_type == tokenize.NEWLINE:
874 break
874 break
875
875
876 except (IndexError, UnicodeDecodeError):
876 except (IndexError, UnicodeDecodeError):
877 # signals exit of tokenizer
877 # signals exit of tokenizer
878 pass
878 pass
879 except tokenize.TokenError as msg:
879 except tokenize.TokenError as msg:
880 _m = ("An unexpected error occurred while tokenizing input\n"
880 _m = ("An unexpected error occurred while tokenizing input\n"
881 "The following traceback may be corrupted or invalid\n"
881 "The following traceback may be corrupted or invalid\n"
882 "The error message is: %s\n" % msg)
882 "The error message is: %s\n" % msg)
883 error(_m)
883 error(_m)
884
884
885 # Join composite names (e.g. "dict.fromkeys")
885 # Join composite names (e.g. "dict.fromkeys")
886 names = ['.'.join(n) for n in names]
886 names = ['.'.join(n) for n in names]
887 # prune names list of duplicates, but keep the right order
887 # prune names list of duplicates, but keep the right order
888 unique_names = uniq_stable(names)
888 unique_names = uniq_stable(names)
889
889
890 # Start loop over vars
890 # Start loop over vars
891 lvals = []
891 lvals = []
892 if self.include_vars:
892 if self.include_vars:
893 for name_full in unique_names:
893 for name_full in unique_names:
894 name_base = name_full.split('.',1)[0]
894 name_base = name_full.split('.',1)[0]
895 if name_base in frame.f_code.co_varnames:
895 if name_base in frame.f_code.co_varnames:
896 if name_base in locals:
896 if name_base in locals:
897 try:
897 try:
898 value = repr(eval(name_full,locals))
898 value = repr(eval(name_full,locals))
899 except:
899 except:
900 value = undefined
900 value = undefined
901 else:
901 else:
902 value = undefined
902 value = undefined
903 name = tpl_local_var % name_full
903 name = tpl_local_var % name_full
904 else:
904 else:
905 if name_base in frame.f_globals:
905 if name_base in frame.f_globals:
906 try:
906 try:
907 value = repr(eval(name_full,frame.f_globals))
907 value = repr(eval(name_full,frame.f_globals))
908 except:
908 except:
909 value = undefined
909 value = undefined
910 else:
910 else:
911 value = undefined
911 value = undefined
912 name = tpl_global_var % name_full
912 name = tpl_global_var % name_full
913 lvals.append(tpl_name_val % (name,value))
913 lvals.append(tpl_name_val % (name,value))
914 if lvals:
914 if lvals:
915 lvals = '%s%s' % (indent,em_normal.join(lvals))
915 lvals = '%s%s' % (indent,em_normal.join(lvals))
916 else:
916 else:
917 lvals = ''
917 lvals = ''
918
918
919 level = '%s %s\n' % (link,call)
919 level = '%s %s\n' % (link,call)
920
920
921 if index is None:
921 if index is None:
922 frames.append(level)
922 frames.append(level)
923 else:
923 else:
924 frames.append('%s%s' % (level,''.join(
924 frames.append('%s%s' % (level,''.join(
925 _format_traceback_lines(lnum,index,lines,Colors,lvals,
925 _format_traceback_lines(lnum,index,lines,Colors,lvals,
926 col_scheme))))
926 col_scheme))))
927
927
928 # Get (safely) a string form of the exception info
928 # Get (safely) a string form of the exception info
929 try:
929 try:
930 etype_str,evalue_str = map(str,(etype,evalue))
930 etype_str,evalue_str = map(str,(etype,evalue))
931 except:
931 except:
932 # User exception is improperly defined.
932 # User exception is improperly defined.
933 etype,evalue = str,sys.exc_info()[:2]
933 etype,evalue = str,sys.exc_info()[:2]
934 etype_str,evalue_str = map(str,(etype,evalue))
934 etype_str,evalue_str = map(str,(etype,evalue))
935 # ... and format it
935 # ... and format it
936 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
936 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
937 ColorsNormal, py3compat.cast_unicode(evalue_str))]
937 ColorsNormal, py3compat.cast_unicode(evalue_str))]
938 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
938 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
939 try:
939 try:
940 names = [w for w in dir(evalue) if isinstance(w, basestring)]
940 names = [w for w in dir(evalue) if isinstance(w, basestring)]
941 except:
941 except:
942 # Every now and then, an object with funny inernals blows up
942 # Every now and then, an object with funny inernals blows up
943 # when dir() is called on it. We do the best we can to report
943 # when dir() is called on it. We do the best we can to report
944 # the problem and continue
944 # the problem and continue
945 _m = '%sException reporting error (object with broken dir())%s:'
945 _m = '%sException reporting error (object with broken dir())%s:'
946 exception.append(_m % (Colors.excName,ColorsNormal))
946 exception.append(_m % (Colors.excName,ColorsNormal))
947 etype_str,evalue_str = map(str,sys.exc_info()[:2])
947 etype_str,evalue_str = map(str,sys.exc_info()[:2])
948 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
948 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
949 ColorsNormal, py3compat.cast_unicode(evalue_str)))
949 ColorsNormal, py3compat.cast_unicode(evalue_str)))
950 names = []
950 names = []
951 for name in names:
951 for name in names:
952 value = text_repr(getattr(evalue, name))
952 value = text_repr(getattr(evalue, name))
953 exception.append('\n%s%s = %s' % (indent, name, value))
953 exception.append('\n%s%s = %s' % (indent, name, value))
954
954
955 # vds: >>
955 # vds: >>
956 if records:
956 if records:
957 filepath, lnum = records[-1][1:3]
957 filepath, lnum = records[-1][1:3]
958 #print "file:", str(file), "linenb", str(lnum) # dbg
958 #print "file:", str(file), "linenb", str(lnum) # dbg
959 filepath = os.path.abspath(filepath)
959 filepath = os.path.abspath(filepath)
960 ipinst = ipapi.get()
960 ipinst = ipapi.get()
961 if ipinst is not None:
961 if ipinst is not None:
962 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
962 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
963 # vds: <<
963 # vds: <<
964
964
965 # return all our info assembled as a single string
965 # return all our info assembled as a single string
966 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
966 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
967 return [head] + frames + [''.join(exception[0])]
967 return [head] + frames + [''.join(exception[0])]
968
968
969 def debugger(self,force=False):
969 def debugger(self,force=False):
970 """Call up the pdb debugger if desired, always clean up the tb
970 """Call up the pdb debugger if desired, always clean up the tb
971 reference.
971 reference.
972
972
973 Keywords:
973 Keywords:
974
974
975 - force(False): by default, this routine checks the instance call_pdb
975 - force(False): by default, this routine checks the instance call_pdb
976 flag and does not actually invoke the debugger if the flag is false.
976 flag and does not actually invoke the debugger if the flag is false.
977 The 'force' option forces the debugger to activate even if the flag
977 The 'force' option forces the debugger to activate even if the flag
978 is false.
978 is false.
979
979
980 If the call_pdb flag is set, the pdb interactive debugger is
980 If the call_pdb flag is set, the pdb interactive debugger is
981 invoked. In all cases, the self.tb reference to the current traceback
981 invoked. In all cases, the self.tb reference to the current traceback
982 is deleted to prevent lingering references which hamper memory
982 is deleted to prevent lingering references which hamper memory
983 management.
983 management.
984
984
985 Note that each call to pdb() does an 'import readline', so if your app
985 Note that each call to pdb() does an 'import readline', so if your app
986 requires a special setup for the readline completers, you'll have to
986 requires a special setup for the readline completers, you'll have to
987 fix that by hand after invoking the exception handler."""
987 fix that by hand after invoking the exception handler."""
988
988
989 if force or self.call_pdb:
989 if force or self.call_pdb:
990 if self.pdb is None:
990 if self.pdb is None:
991 self.pdb = debugger.Pdb(
991 self.pdb = debugger.Pdb(
992 self.color_scheme_table.active_scheme_name)
992 self.color_scheme_table.active_scheme_name)
993 # the system displayhook may have changed, restore the original
993 # the system displayhook may have changed, restore the original
994 # for pdb
994 # for pdb
995 display_trap = DisplayTrap(hook=sys.__displayhook__)
995 display_trap = DisplayTrap(hook=sys.__displayhook__)
996 with display_trap:
996 with display_trap:
997 self.pdb.reset()
997 self.pdb.reset()
998 # Find the right frame so we don't pop up inside ipython itself
998 # Find the right frame so we don't pop up inside ipython itself
999 if hasattr(self,'tb') and self.tb is not None:
999 if hasattr(self,'tb') and self.tb is not None:
1000 etb = self.tb
1000 etb = self.tb
1001 else:
1001 else:
1002 etb = self.tb = sys.last_traceback
1002 etb = self.tb = sys.last_traceback
1003 while self.tb is not None and self.tb.tb_next is not None:
1003 while self.tb is not None and self.tb.tb_next is not None:
1004 self.tb = self.tb.tb_next
1004 self.tb = self.tb.tb_next
1005 if etb and etb.tb_next:
1005 if etb and etb.tb_next:
1006 etb = etb.tb_next
1006 etb = etb.tb_next
1007 self.pdb.botframe = etb.tb_frame
1007 self.pdb.botframe = etb.tb_frame
1008 self.pdb.interaction(self.tb.tb_frame, self.tb)
1008 self.pdb.interaction(self.tb.tb_frame, self.tb)
1009
1009
1010 if hasattr(self,'tb'):
1010 if hasattr(self,'tb'):
1011 del self.tb
1011 del self.tb
1012
1012
1013 def handler(self, info=None):
1013 def handler(self, info=None):
1014 (etype, evalue, etb) = info or sys.exc_info()
1014 (etype, evalue, etb) = info or sys.exc_info()
1015 self.tb = etb
1015 self.tb = etb
1016 ostream = self.ostream
1016 ostream = self.ostream
1017 ostream.flush()
1017 ostream.flush()
1018 ostream.write(self.text(etype, evalue, etb))
1018 ostream.write(self.text(etype, evalue, etb))
1019 ostream.write('\n')
1019 ostream.write('\n')
1020 ostream.flush()
1020 ostream.flush()
1021
1021
1022 # Changed so an instance can just be called as VerboseTB_inst() and print
1022 # Changed so an instance can just be called as VerboseTB_inst() and print
1023 # out the right info on its own.
1023 # out the right info on its own.
1024 def __call__(self, etype=None, evalue=None, etb=None):
1024 def __call__(self, etype=None, evalue=None, etb=None):
1025 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1025 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1026 if etb is None:
1026 if etb is None:
1027 self.handler()
1027 self.handler()
1028 else:
1028 else:
1029 self.handler((etype, evalue, etb))
1029 self.handler((etype, evalue, etb))
1030 try:
1030 try:
1031 self.debugger()
1031 self.debugger()
1032 except KeyboardInterrupt:
1032 except KeyboardInterrupt:
1033 print "\nKeyboardInterrupt"
1033 print "\nKeyboardInterrupt"
1034
1034
1035 #----------------------------------------------------------------------------
1035 #----------------------------------------------------------------------------
1036 class FormattedTB(VerboseTB, ListTB):
1036 class FormattedTB(VerboseTB, ListTB):
1037 """Subclass ListTB but allow calling with a traceback.
1037 """Subclass ListTB but allow calling with a traceback.
1038
1038
1039 It can thus be used as a sys.excepthook for Python > 2.1.
1039 It can thus be used as a sys.excepthook for Python > 2.1.
1040
1040
1041 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1041 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1042
1042
1043 Allows a tb_offset to be specified. This is useful for situations where
1043 Allows a tb_offset to be specified. This is useful for situations where
1044 one needs to remove a number of topmost frames from the traceback (such as
1044 one needs to remove a number of topmost frames from the traceback (such as
1045 occurs with python programs that themselves execute other python code,
1045 occurs with python programs that themselves execute other python code,
1046 like Python shells). """
1046 like Python shells). """
1047
1047
1048 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1048 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1049 ostream=None,
1049 ostream=None,
1050 tb_offset=0, long_header=False, include_vars=False,
1050 tb_offset=0, long_header=False, include_vars=False,
1051 check_cache=None):
1051 check_cache=None):
1052
1052
1053 # NEVER change the order of this list. Put new modes at the end:
1053 # NEVER change the order of this list. Put new modes at the end:
1054 self.valid_modes = ['Plain','Context','Verbose']
1054 self.valid_modes = ['Plain','Context','Verbose']
1055 self.verbose_modes = self.valid_modes[1:3]
1055 self.verbose_modes = self.valid_modes[1:3]
1056
1056
1057 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1057 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1058 ostream=ostream, tb_offset=tb_offset,
1058 ostream=ostream, tb_offset=tb_offset,
1059 long_header=long_header, include_vars=include_vars,
1059 long_header=long_header, include_vars=include_vars,
1060 check_cache=check_cache)
1060 check_cache=check_cache)
1061
1061
1062 # Different types of tracebacks are joined with different separators to
1062 # Different types of tracebacks are joined with different separators to
1063 # form a single string. They are taken from this dict
1063 # form a single string. They are taken from this dict
1064 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1064 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1065 # set_mode also sets the tb_join_char attribute
1065 # set_mode also sets the tb_join_char attribute
1066 self.set_mode(mode)
1066 self.set_mode(mode)
1067
1067
1068 def _extract_tb(self,tb):
1068 def _extract_tb(self,tb):
1069 if tb:
1069 if tb:
1070 return traceback.extract_tb(tb)
1070 return traceback.extract_tb(tb)
1071 else:
1071 else:
1072 return None
1072 return None
1073
1073
1074 def structured_traceback(self, etype, value, tb, tb_offset=None, context=5):
1074 def structured_traceback(self, etype, value, tb, tb_offset=None, context=5):
1075 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1075 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1076 mode = self.mode
1076 mode = self.mode
1077 if mode in self.verbose_modes:
1077 if mode in self.verbose_modes:
1078 # Verbose modes need a full traceback
1078 # Verbose modes need a full traceback
1079 return VerboseTB.structured_traceback(
1079 return VerboseTB.structured_traceback(
1080 self, etype, value, tb, tb_offset, context
1080 self, etype, value, tb, tb_offset, context
1081 )
1081 )
1082 else:
1082 else:
1083 # We must check the source cache because otherwise we can print
1083 # We must check the source cache because otherwise we can print
1084 # out-of-date source code.
1084 # out-of-date source code.
1085 self.check_cache()
1085 self.check_cache()
1086 # Now we can extract and format the exception
1086 # Now we can extract and format the exception
1087 elist = self._extract_tb(tb)
1087 elist = self._extract_tb(tb)
1088 return ListTB.structured_traceback(
1088 return ListTB.structured_traceback(
1089 self, etype, value, elist, tb_offset, context
1089 self, etype, value, elist, tb_offset, context
1090 )
1090 )
1091
1091
1092 def stb2text(self, stb):
1092 def stb2text(self, stb):
1093 """Convert a structured traceback (a list) to a string."""
1093 """Convert a structured traceback (a list) to a string."""
1094 return self.tb_join_char.join(stb)
1094 return self.tb_join_char.join(stb)
1095
1095
1096
1096
1097 def set_mode(self,mode=None):
1097 def set_mode(self,mode=None):
1098 """Switch to the desired mode.
1098 """Switch to the desired mode.
1099
1099
1100 If mode is not specified, cycles through the available modes."""
1100 If mode is not specified, cycles through the available modes."""
1101
1101
1102 if not mode:
1102 if not mode:
1103 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
1103 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
1104 len(self.valid_modes)
1104 len(self.valid_modes)
1105 self.mode = self.valid_modes[new_idx]
1105 self.mode = self.valid_modes[new_idx]
1106 elif mode not in self.valid_modes:
1106 elif mode not in self.valid_modes:
1107 raise ValueError('Unrecognized mode in FormattedTB: <'+mode+'>\n'
1107 raise ValueError('Unrecognized mode in FormattedTB: <'+mode+'>\n'
1108 'Valid modes: '+str(self.valid_modes))
1108 'Valid modes: '+str(self.valid_modes))
1109 else:
1109 else:
1110 self.mode = mode
1110 self.mode = mode
1111 # include variable details only in 'Verbose' mode
1111 # include variable details only in 'Verbose' mode
1112 self.include_vars = (self.mode == self.valid_modes[2])
1112 self.include_vars = (self.mode == self.valid_modes[2])
1113 # Set the join character for generating text tracebacks
1113 # Set the join character for generating text tracebacks
1114 self.tb_join_char = self._join_chars[self.mode]
1114 self.tb_join_char = self._join_chars[self.mode]
1115
1115
1116 # some convenient shorcuts
1116 # some convenient shorcuts
1117 def plain(self):
1117 def plain(self):
1118 self.set_mode(self.valid_modes[0])
1118 self.set_mode(self.valid_modes[0])
1119
1119
1120 def context(self):
1120 def context(self):
1121 self.set_mode(self.valid_modes[1])
1121 self.set_mode(self.valid_modes[1])
1122
1122
1123 def verbose(self):
1123 def verbose(self):
1124 self.set_mode(self.valid_modes[2])
1124 self.set_mode(self.valid_modes[2])
1125
1125
1126 #----------------------------------------------------------------------------
1126 #----------------------------------------------------------------------------
1127 class AutoFormattedTB(FormattedTB):
1127 class AutoFormattedTB(FormattedTB):
1128 """A traceback printer which can be called on the fly.
1128 """A traceback printer which can be called on the fly.
1129
1129
1130 It will find out about exceptions by itself.
1130 It will find out about exceptions by itself.
1131
1131
1132 A brief example::
1132 A brief example::
1133
1133
1134 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1134 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1135 try:
1135 try:
1136 ...
1136 ...
1137 except:
1137 except:
1138 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1138 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1139 """
1139 """
1140
1140
1141 def __call__(self,etype=None,evalue=None,etb=None,
1141 def __call__(self,etype=None,evalue=None,etb=None,
1142 out=None,tb_offset=None):
1142 out=None,tb_offset=None):
1143 """Print out a formatted exception traceback.
1143 """Print out a formatted exception traceback.
1144
1144
1145 Optional arguments:
1145 Optional arguments:
1146 - out: an open file-like object to direct output to.
1146 - out: an open file-like object to direct output to.
1147
1147
1148 - tb_offset: the number of frames to skip over in the stack, on a
1148 - tb_offset: the number of frames to skip over in the stack, on a
1149 per-call basis (this overrides temporarily the instance's tb_offset
1149 per-call basis (this overrides temporarily the instance's tb_offset
1150 given at initialization time. """
1150 given at initialization time. """
1151
1151
1152
1152
1153 if out is None:
1153 if out is None:
1154 out = self.ostream
1154 out = self.ostream
1155 out.flush()
1155 out.flush()
1156 out.write(self.text(etype, evalue, etb, tb_offset))
1156 out.write(self.text(etype, evalue, etb, tb_offset))
1157 out.write('\n')
1157 out.write('\n')
1158 out.flush()
1158 out.flush()
1159 # FIXME: we should remove the auto pdb behavior from here and leave
1159 # FIXME: we should remove the auto pdb behavior from here and leave
1160 # that to the clients.
1160 # that to the clients.
1161 try:
1161 try:
1162 self.debugger()
1162 self.debugger()
1163 except KeyboardInterrupt:
1163 except KeyboardInterrupt:
1164 print "\nKeyboardInterrupt"
1164 print "\nKeyboardInterrupt"
1165
1165
1166 def structured_traceback(self, etype=None, value=None, tb=None,
1166 def structured_traceback(self, etype=None, value=None, tb=None,
1167 tb_offset=None, context=5):
1167 tb_offset=None, context=5):
1168 if etype is None:
1168 if etype is None:
1169 etype,value,tb = sys.exc_info()
1169 etype,value,tb = sys.exc_info()
1170 self.tb = tb
1170 self.tb = tb
1171 return FormattedTB.structured_traceback(
1171 return FormattedTB.structured_traceback(
1172 self, etype, value, tb, tb_offset, context)
1172 self, etype, value, tb, tb_offset, context)
1173
1173
1174 #---------------------------------------------------------------------------
1174 #---------------------------------------------------------------------------
1175
1175
1176 # A simple class to preserve Nathan's original functionality.
1176 # A simple class to preserve Nathan's original functionality.
1177 class ColorTB(FormattedTB):
1177 class ColorTB(FormattedTB):
1178 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1178 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1179 def __init__(self,color_scheme='Linux',call_pdb=0):
1179 def __init__(self,color_scheme='Linux',call_pdb=0):
1180 FormattedTB.__init__(self,color_scheme=color_scheme,
1180 FormattedTB.__init__(self,color_scheme=color_scheme,
1181 call_pdb=call_pdb)
1181 call_pdb=call_pdb)
1182
1182
1183
1183
1184 class SyntaxTB(ListTB):
1184 class SyntaxTB(ListTB):
1185 """Extension which holds some state: the last exception value"""
1185 """Extension which holds some state: the last exception value"""
1186
1186
1187 def __init__(self,color_scheme = 'NoColor'):
1187 def __init__(self,color_scheme = 'NoColor'):
1188 ListTB.__init__(self,color_scheme)
1188 ListTB.__init__(self,color_scheme)
1189 self.last_syntax_error = None
1189 self.last_syntax_error = None
1190
1190
1191 def __call__(self, etype, value, elist):
1191 def __call__(self, etype, value, elist):
1192 self.last_syntax_error = value
1192 self.last_syntax_error = value
1193 ListTB.__call__(self,etype,value,elist)
1193 ListTB.__call__(self,etype,value,elist)
1194
1194
1195 def clear_err_state(self):
1195 def clear_err_state(self):
1196 """Return the current error state and clear it"""
1196 """Return the current error state and clear it"""
1197 e = self.last_syntax_error
1197 e = self.last_syntax_error
1198 self.last_syntax_error = None
1198 self.last_syntax_error = None
1199 return e
1199 return e
1200
1200
1201 def stb2text(self, stb):
1201 def stb2text(self, stb):
1202 """Convert a structured traceback (a list) to a string."""
1202 """Convert a structured traceback (a list) to a string."""
1203 return ''.join(stb)
1203 return ''.join(stb)
1204
1204
1205
1205
1206 #----------------------------------------------------------------------------
1206 #----------------------------------------------------------------------------
1207 # module testing (minimal)
1207 # module testing (minimal)
1208 if __name__ == "__main__":
1208 if __name__ == "__main__":
1209 def spam(c, d_e):
1209 def spam(c, d_e):
1210 (d, e) = d_e
1210 (d, e) = d_e
1211 x = c + d
1211 x = c + d
1212 y = c * d
1212 y = c * d
1213 foo(x, y)
1213 foo(x, y)
1214
1214
1215 def foo(a, b, bar=1):
1215 def foo(a, b, bar=1):
1216 eggs(a, b + bar)
1216 eggs(a, b + bar)
1217
1217
1218 def eggs(f, g, z=globals()):
1218 def eggs(f, g, z=globals()):
1219 h = f + g
1219 h = f + g
1220 i = f - g
1220 i = f - g
1221 return h / i
1221 return h / i
1222
1222
1223 print ''
1223 print ''
1224 print '*** Before ***'
1224 print '*** Before ***'
1225 try:
1225 try:
1226 print spam(1, (2, 3))
1226 print spam(1, (2, 3))
1227 except:
1227 except:
1228 traceback.print_exc()
1228 traceback.print_exc()
1229 print ''
1229 print ''
1230
1230
1231 handler = ColorTB()
1231 handler = ColorTB()
1232 print '*** ColorTB ***'
1232 print '*** ColorTB ***'
1233 try:
1233 try:
1234 print spam(1, (2, 3))
1234 print spam(1, (2, 3))
1235 except:
1235 except:
1236 handler(*sys.exc_info())
1236 handler(*sys.exc_info())
1237 print ''
1237 print ''
1238
1238
1239 handler = VerboseTB()
1239 handler = VerboseTB()
1240 print '*** VerboseTB ***'
1240 print '*** VerboseTB ***'
1241 try:
1241 try:
1242 print spam(1, (2, 3))
1242 print spam(1, (2, 3))
1243 except:
1243 except:
1244 handler(*sys.exc_info())
1244 handler(*sys.exc_info())
1245 print ''
1245 print ''
1246
1246
@@ -1,509 +1,509 b''
1 """IPython extension to reload modules before executing user code.
1 """IPython extension to reload modules before executing user code.
2
2
3 ``autoreload`` reloads modules automatically before entering the execution of
3 ``autoreload`` reloads modules automatically before entering the execution of
4 code typed at the IPython prompt.
4 code typed at the IPython prompt.
5
5
6 This makes for example the following workflow possible:
6 This makes for example the following workflow possible:
7
7
8 .. sourcecode:: ipython
8 .. sourcecode:: ipython
9
9
10 In [1]: %load_ext autoreload
10 In [1]: %load_ext autoreload
11
11
12 In [2]: %autoreload 2
12 In [2]: %autoreload 2
13
13
14 In [3]: from foo import some_function
14 In [3]: from foo import some_function
15
15
16 In [4]: some_function()
16 In [4]: some_function()
17 Out[4]: 42
17 Out[4]: 42
18
18
19 In [5]: # open foo.py in an editor and change some_function to return 43
19 In [5]: # open foo.py in an editor and change some_function to return 43
20
20
21 In [6]: some_function()
21 In [6]: some_function()
22 Out[6]: 43
22 Out[6]: 43
23
23
24 The module was reloaded without reloading it explicitly, and the object
24 The module was reloaded without reloading it explicitly, and the object
25 imported with ``from foo import ...`` was also updated.
25 imported with ``from foo import ...`` was also updated.
26
26
27 Usage
27 Usage
28 =====
28 =====
29
29
30 The following magic commands are provided:
30 The following magic commands are provided:
31
31
32 ``%autoreload``
32 ``%autoreload``
33
33
34 Reload all modules (except those excluded by ``%aimport``)
34 Reload all modules (except those excluded by ``%aimport``)
35 automatically now.
35 automatically now.
36
36
37 ``%autoreload 0``
37 ``%autoreload 0``
38
38
39 Disable automatic reloading.
39 Disable automatic reloading.
40
40
41 ``%autoreload 1``
41 ``%autoreload 1``
42
42
43 Reload all modules imported with ``%aimport`` every time before
43 Reload all modules imported with ``%aimport`` every time before
44 executing the Python code typed.
44 executing the Python code typed.
45
45
46 ``%autoreload 2``
46 ``%autoreload 2``
47
47
48 Reload all modules (except those excluded by ``%aimport``) every
48 Reload all modules (except those excluded by ``%aimport``) every
49 time before executing the Python code typed.
49 time before executing the Python code typed.
50
50
51 ``%aimport``
51 ``%aimport``
52
52
53 List modules which are to be automatically imported or not to be imported.
53 List modules which are to be automatically imported or not to be imported.
54
54
55 ``%aimport foo``
55 ``%aimport foo``
56
56
57 Import module 'foo' and mark it to be autoreloaded for ``%autoreload 1``
57 Import module 'foo' and mark it to be autoreloaded for ``%autoreload 1``
58
58
59 ``%aimport -foo``
59 ``%aimport -foo``
60
60
61 Mark module 'foo' to not be autoreloaded.
61 Mark module 'foo' to not be autoreloaded.
62
62
63 Caveats
63 Caveats
64 =======
64 =======
65
65
66 Reloading Python modules in a reliable way is in general difficult,
66 Reloading Python modules in a reliable way is in general difficult,
67 and unexpected things may occur. ``%autoreload`` tries to work around
67 and unexpected things may occur. ``%autoreload`` tries to work around
68 common pitfalls by replacing function code objects and parts of
68 common pitfalls by replacing function code objects and parts of
69 classes previously in the module with new versions. This makes the
69 classes previously in the module with new versions. This makes the
70 following things to work:
70 following things to work:
71
71
72 - Functions and classes imported via 'from xxx import foo' are upgraded
72 - Functions and classes imported via 'from xxx import foo' are upgraded
73 to new versions when 'xxx' is reloaded.
73 to new versions when 'xxx' is reloaded.
74
74
75 - Methods and properties of classes are upgraded on reload, so that
75 - Methods and properties of classes are upgraded on reload, so that
76 calling 'c.foo()' on an object 'c' created before the reload causes
76 calling 'c.foo()' on an object 'c' created before the reload causes
77 the new code for 'foo' to be executed.
77 the new code for 'foo' to be executed.
78
78
79 Some of the known remaining caveats are:
79 Some of the known remaining caveats are:
80
80
81 - Replacing code objects does not always succeed: changing a @property
81 - Replacing code objects does not always succeed: changing a @property
82 in a class to an ordinary method or a method to a member variable
82 in a class to an ordinary method or a method to a member variable
83 can cause problems (but in old objects only).
83 can cause problems (but in old objects only).
84
84
85 - Functions that are removed (eg. via monkey-patching) from a module
85 - Functions that are removed (eg. via monkey-patching) from a module
86 before it is reloaded are not upgraded.
86 before it is reloaded are not upgraded.
87
87
88 - C extension modules cannot be reloaded, and so cannot be autoreloaded.
88 - C extension modules cannot be reloaded, and so cannot be autoreloaded.
89 """
89 """
90 from __future__ import print_function
90 from __future__ import print_function
91
91
92 skip_doctest = True
92 skip_doctest = True
93
93
94 #-----------------------------------------------------------------------------
94 #-----------------------------------------------------------------------------
95 # Copyright (C) 2000 Thomas Heller
95 # Copyright (C) 2000 Thomas Heller
96 # Copyright (C) 2008 Pauli Virtanen <pav@iki.fi>
96 # Copyright (C) 2008 Pauli Virtanen <pav@iki.fi>
97 # Copyright (C) 2012 The IPython Development Team
97 # Copyright (C) 2012 The IPython Development Team
98 #
98 #
99 # Distributed under the terms of the BSD License. The full license is in
99 # Distributed under the terms of the BSD License. The full license is in
100 # the file COPYING, distributed as part of this software.
100 # the file COPYING, distributed as part of this software.
101 #-----------------------------------------------------------------------------
101 #-----------------------------------------------------------------------------
102 #
102 #
103 # This IPython module is written by Pauli Virtanen, based on the autoreload
103 # This IPython module is written by Pauli Virtanen, based on the autoreload
104 # code by Thomas Heller.
104 # code by Thomas Heller.
105
105
106 #-----------------------------------------------------------------------------
106 #-----------------------------------------------------------------------------
107 # Imports
107 # Imports
108 #-----------------------------------------------------------------------------
108 #-----------------------------------------------------------------------------
109
109
110 import os
110 import os
111 import sys
111 import sys
112 import traceback
112 import traceback
113 import types
113 import types
114 import weakref
114 import weakref
115
115
116 try:
116 try:
117 # Reload is not defined by default in Python3.
117 # Reload is not defined by default in Python3.
118 reload
118 reload
119 except NameError:
119 except NameError:
120 from imp import reload
120 from imp import reload
121
121
122 from IPython.utils import pyfile
122 from IPython.utils import openpy
123 from IPython.utils.py3compat import PY3
123 from IPython.utils.py3compat import PY3
124
124
125 #------------------------------------------------------------------------------
125 #------------------------------------------------------------------------------
126 # Autoreload functionality
126 # Autoreload functionality
127 #------------------------------------------------------------------------------
127 #------------------------------------------------------------------------------
128
128
129 class ModuleReloader(object):
129 class ModuleReloader(object):
130 enabled = False
130 enabled = False
131 """Whether this reloader is enabled"""
131 """Whether this reloader is enabled"""
132
132
133 failed = {}
133 failed = {}
134 """Modules that failed to reload: {module: mtime-on-failed-reload, ...}"""
134 """Modules that failed to reload: {module: mtime-on-failed-reload, ...}"""
135
135
136 modules = {}
136 modules = {}
137 """Modules specially marked as autoreloadable."""
137 """Modules specially marked as autoreloadable."""
138
138
139 skip_modules = {}
139 skip_modules = {}
140 """Modules specially marked as not autoreloadable."""
140 """Modules specially marked as not autoreloadable."""
141
141
142 check_all = True
142 check_all = True
143 """Autoreload all modules, not just those listed in 'modules'"""
143 """Autoreload all modules, not just those listed in 'modules'"""
144
144
145 old_objects = {}
145 old_objects = {}
146 """(module-name, name) -> weakref, for replacing old code objects"""
146 """(module-name, name) -> weakref, for replacing old code objects"""
147
147
148 def mark_module_skipped(self, module_name):
148 def mark_module_skipped(self, module_name):
149 """Skip reloading the named module in the future"""
149 """Skip reloading the named module in the future"""
150 try:
150 try:
151 del self.modules[module_name]
151 del self.modules[module_name]
152 except KeyError:
152 except KeyError:
153 pass
153 pass
154 self.skip_modules[module_name] = True
154 self.skip_modules[module_name] = True
155
155
156 def mark_module_reloadable(self, module_name):
156 def mark_module_reloadable(self, module_name):
157 """Reload the named module in the future (if it is imported)"""
157 """Reload the named module in the future (if it is imported)"""
158 try:
158 try:
159 del self.skip_modules[module_name]
159 del self.skip_modules[module_name]
160 except KeyError:
160 except KeyError:
161 pass
161 pass
162 self.modules[module_name] = True
162 self.modules[module_name] = True
163
163
164 def aimport_module(self, module_name):
164 def aimport_module(self, module_name):
165 """Import a module, and mark it reloadable
165 """Import a module, and mark it reloadable
166
166
167 Returns
167 Returns
168 -------
168 -------
169 top_module : module
169 top_module : module
170 The imported module if it is top-level, or the top-level
170 The imported module if it is top-level, or the top-level
171 top_name : module
171 top_name : module
172 Name of top_module
172 Name of top_module
173
173
174 """
174 """
175 self.mark_module_reloadable(module_name)
175 self.mark_module_reloadable(module_name)
176
176
177 __import__(module_name)
177 __import__(module_name)
178 top_name = module_name.split('.')[0]
178 top_name = module_name.split('.')[0]
179 top_module = sys.modules[top_name]
179 top_module = sys.modules[top_name]
180 return top_module, top_name
180 return top_module, top_name
181
181
182 def check(self, check_all=False):
182 def check(self, check_all=False):
183 """Check whether some modules need to be reloaded."""
183 """Check whether some modules need to be reloaded."""
184
184
185 if not self.enabled and not check_all:
185 if not self.enabled and not check_all:
186 return
186 return
187
187
188 if check_all or self.check_all:
188 if check_all or self.check_all:
189 modules = sys.modules.keys()
189 modules = sys.modules.keys()
190 else:
190 else:
191 modules = self.modules.keys()
191 modules = self.modules.keys()
192
192
193 for modname in modules:
193 for modname in modules:
194 m = sys.modules.get(modname, None)
194 m = sys.modules.get(modname, None)
195
195
196 if modname in self.skip_modules:
196 if modname in self.skip_modules:
197 continue
197 continue
198
198
199 if not hasattr(m, '__file__'):
199 if not hasattr(m, '__file__'):
200 continue
200 continue
201
201
202 if m.__name__ == '__main__':
202 if m.__name__ == '__main__':
203 # we cannot reload(__main__)
203 # we cannot reload(__main__)
204 continue
204 continue
205
205
206 filename = m.__file__
206 filename = m.__file__
207 path, ext = os.path.splitext(filename)
207 path, ext = os.path.splitext(filename)
208
208
209 if ext.lower() == '.py':
209 if ext.lower() == '.py':
210 pyc_filename = pyfile.cache_from_source(filename)
210 pyc_filename = openpy.cache_from_source(filename)
211 py_filename = filename
211 py_filename = filename
212 else:
212 else:
213 pyc_filename = filename
213 pyc_filename = filename
214 try:
214 try:
215 py_filename = pyfile.source_from_cache(filename)
215 py_filename = openpy.source_from_cache(filename)
216 except ValueError:
216 except ValueError:
217 continue
217 continue
218
218
219 try:
219 try:
220 pymtime = os.stat(py_filename).st_mtime
220 pymtime = os.stat(py_filename).st_mtime
221 if pymtime <= os.stat(pyc_filename).st_mtime:
221 if pymtime <= os.stat(pyc_filename).st_mtime:
222 continue
222 continue
223 if self.failed.get(py_filename, None) == pymtime:
223 if self.failed.get(py_filename, None) == pymtime:
224 continue
224 continue
225 except OSError:
225 except OSError:
226 continue
226 continue
227
227
228 try:
228 try:
229 superreload(m, reload, self.old_objects)
229 superreload(m, reload, self.old_objects)
230 if py_filename in self.failed:
230 if py_filename in self.failed:
231 del self.failed[py_filename]
231 del self.failed[py_filename]
232 except:
232 except:
233 print("[autoreload of %s failed: %s]" % (
233 print("[autoreload of %s failed: %s]" % (
234 modname, traceback.format_exc(1)), file=sys.stderr)
234 modname, traceback.format_exc(1)), file=sys.stderr)
235 self.failed[py_filename] = pymtime
235 self.failed[py_filename] = pymtime
236
236
237 #------------------------------------------------------------------------------
237 #------------------------------------------------------------------------------
238 # superreload
238 # superreload
239 #------------------------------------------------------------------------------
239 #------------------------------------------------------------------------------
240
240
241 if PY3:
241 if PY3:
242 func_attrs = ['__code__', '__defaults__', '__doc__',
242 func_attrs = ['__code__', '__defaults__', '__doc__',
243 '__closure__', '__globals__', '__dict__']
243 '__closure__', '__globals__', '__dict__']
244 else:
244 else:
245 func_attrs = ['func_code', 'func_defaults', 'func_doc',
245 func_attrs = ['func_code', 'func_defaults', 'func_doc',
246 'func_closure', 'func_globals', 'func_dict']
246 'func_closure', 'func_globals', 'func_dict']
247
247
248
248
249 def update_function(old, new):
249 def update_function(old, new):
250 """Upgrade the code object of a function"""
250 """Upgrade the code object of a function"""
251 for name in func_attrs:
251 for name in func_attrs:
252 try:
252 try:
253 setattr(old, name, getattr(new, name))
253 setattr(old, name, getattr(new, name))
254 except (AttributeError, TypeError):
254 except (AttributeError, TypeError):
255 pass
255 pass
256
256
257
257
258 def update_class(old, new):
258 def update_class(old, new):
259 """Replace stuff in the __dict__ of a class, and upgrade
259 """Replace stuff in the __dict__ of a class, and upgrade
260 method code objects"""
260 method code objects"""
261 for key in old.__dict__.keys():
261 for key in old.__dict__.keys():
262 old_obj = getattr(old, key)
262 old_obj = getattr(old, key)
263
263
264 try:
264 try:
265 new_obj = getattr(new, key)
265 new_obj = getattr(new, key)
266 except AttributeError:
266 except AttributeError:
267 # obsolete attribute: remove it
267 # obsolete attribute: remove it
268 try:
268 try:
269 delattr(old, key)
269 delattr(old, key)
270 except (AttributeError, TypeError):
270 except (AttributeError, TypeError):
271 pass
271 pass
272 continue
272 continue
273
273
274 if update_generic(old_obj, new_obj): continue
274 if update_generic(old_obj, new_obj): continue
275
275
276 try:
276 try:
277 setattr(old, key, getattr(new, key))
277 setattr(old, key, getattr(new, key))
278 except (AttributeError, TypeError):
278 except (AttributeError, TypeError):
279 pass # skip non-writable attributes
279 pass # skip non-writable attributes
280
280
281
281
282 def update_property(old, new):
282 def update_property(old, new):
283 """Replace get/set/del functions of a property"""
283 """Replace get/set/del functions of a property"""
284 update_generic(old.fdel, new.fdel)
284 update_generic(old.fdel, new.fdel)
285 update_generic(old.fget, new.fget)
285 update_generic(old.fget, new.fget)
286 update_generic(old.fset, new.fset)
286 update_generic(old.fset, new.fset)
287
287
288
288
289 def isinstance2(a, b, typ):
289 def isinstance2(a, b, typ):
290 return isinstance(a, typ) and isinstance(b, typ)
290 return isinstance(a, typ) and isinstance(b, typ)
291
291
292
292
293 UPDATE_RULES = [
293 UPDATE_RULES = [
294 (lambda a, b: isinstance2(a, b, type),
294 (lambda a, b: isinstance2(a, b, type),
295 update_class),
295 update_class),
296 (lambda a, b: isinstance2(a, b, types.FunctionType),
296 (lambda a, b: isinstance2(a, b, types.FunctionType),
297 update_function),
297 update_function),
298 (lambda a, b: isinstance2(a, b, property),
298 (lambda a, b: isinstance2(a, b, property),
299 update_property),
299 update_property),
300 ]
300 ]
301
301
302
302
303 if PY3:
303 if PY3:
304 UPDATE_RULES.extend([(lambda a, b: isinstance2(a, b, types.MethodType),
304 UPDATE_RULES.extend([(lambda a, b: isinstance2(a, b, types.MethodType),
305 lambda a, b: update_function(a.__func__, b.__func__)),
305 lambda a, b: update_function(a.__func__, b.__func__)),
306 ])
306 ])
307 else:
307 else:
308 UPDATE_RULES.extend([(lambda a, b: isinstance2(a, b, types.ClassType),
308 UPDATE_RULES.extend([(lambda a, b: isinstance2(a, b, types.ClassType),
309 update_class),
309 update_class),
310 (lambda a, b: isinstance2(a, b, types.MethodType),
310 (lambda a, b: isinstance2(a, b, types.MethodType),
311 lambda a, b: update_function(a.im_func, b.im_func)),
311 lambda a, b: update_function(a.im_func, b.im_func)),
312 ])
312 ])
313
313
314
314
315 def update_generic(a, b):
315 def update_generic(a, b):
316 for type_check, update in UPDATE_RULES:
316 for type_check, update in UPDATE_RULES:
317 if type_check(a, b):
317 if type_check(a, b):
318 update(a, b)
318 update(a, b)
319 return True
319 return True
320 return False
320 return False
321
321
322
322
323 class StrongRef(object):
323 class StrongRef(object):
324 def __init__(self, obj):
324 def __init__(self, obj):
325 self.obj = obj
325 self.obj = obj
326 def __call__(self):
326 def __call__(self):
327 return self.obj
327 return self.obj
328
328
329
329
330 def superreload(module, reload=reload, old_objects={}):
330 def superreload(module, reload=reload, old_objects={}):
331 """Enhanced version of the builtin reload function.
331 """Enhanced version of the builtin reload function.
332
332
333 superreload remembers objects previously in the module, and
333 superreload remembers objects previously in the module, and
334
334
335 - upgrades the class dictionary of every old class in the module
335 - upgrades the class dictionary of every old class in the module
336 - upgrades the code object of every old function and method
336 - upgrades the code object of every old function and method
337 - clears the module's namespace before reloading
337 - clears the module's namespace before reloading
338
338
339 """
339 """
340
340
341 # collect old objects in the module
341 # collect old objects in the module
342 for name, obj in module.__dict__.items():
342 for name, obj in module.__dict__.items():
343 if not hasattr(obj, '__module__') or obj.__module__ != module.__name__:
343 if not hasattr(obj, '__module__') or obj.__module__ != module.__name__:
344 continue
344 continue
345 key = (module.__name__, name)
345 key = (module.__name__, name)
346 try:
346 try:
347 old_objects.setdefault(key, []).append(weakref.ref(obj))
347 old_objects.setdefault(key, []).append(weakref.ref(obj))
348 except TypeError:
348 except TypeError:
349 # weakref doesn't work for all types;
349 # weakref doesn't work for all types;
350 # create strong references for 'important' cases
350 # create strong references for 'important' cases
351 if not PY3 and isinstance(obj, types.ClassType):
351 if not PY3 and isinstance(obj, types.ClassType):
352 old_objects.setdefault(key, []).append(StrongRef(obj))
352 old_objects.setdefault(key, []).append(StrongRef(obj))
353
353
354 # reload module
354 # reload module
355 try:
355 try:
356 # clear namespace first from old cruft
356 # clear namespace first from old cruft
357 old_dict = module.__dict__.copy()
357 old_dict = module.__dict__.copy()
358 old_name = module.__name__
358 old_name = module.__name__
359 module.__dict__.clear()
359 module.__dict__.clear()
360 module.__dict__['__name__'] = old_name
360 module.__dict__['__name__'] = old_name
361 module.__dict__['__loader__'] = old_dict['__loader__']
361 module.__dict__['__loader__'] = old_dict['__loader__']
362 except (TypeError, AttributeError, KeyError):
362 except (TypeError, AttributeError, KeyError):
363 pass
363 pass
364
364
365 try:
365 try:
366 module = reload(module)
366 module = reload(module)
367 except:
367 except:
368 # restore module dictionary on failed reload
368 # restore module dictionary on failed reload
369 module.__dict__.update(old_dict)
369 module.__dict__.update(old_dict)
370 raise
370 raise
371
371
372 # iterate over all objects and update functions & classes
372 # iterate over all objects and update functions & classes
373 for name, new_obj in module.__dict__.items():
373 for name, new_obj in module.__dict__.items():
374 key = (module.__name__, name)
374 key = (module.__name__, name)
375 if key not in old_objects: continue
375 if key not in old_objects: continue
376
376
377 new_refs = []
377 new_refs = []
378 for old_ref in old_objects[key]:
378 for old_ref in old_objects[key]:
379 old_obj = old_ref()
379 old_obj = old_ref()
380 if old_obj is None: continue
380 if old_obj is None: continue
381 new_refs.append(old_ref)
381 new_refs.append(old_ref)
382 update_generic(old_obj, new_obj)
382 update_generic(old_obj, new_obj)
383
383
384 if new_refs:
384 if new_refs:
385 old_objects[key] = new_refs
385 old_objects[key] = new_refs
386 else:
386 else:
387 del old_objects[key]
387 del old_objects[key]
388
388
389 return module
389 return module
390
390
391 #------------------------------------------------------------------------------
391 #------------------------------------------------------------------------------
392 # IPython connectivity
392 # IPython connectivity
393 #------------------------------------------------------------------------------
393 #------------------------------------------------------------------------------
394
394
395 from IPython.core.hooks import TryNext
395 from IPython.core.hooks import TryNext
396 from IPython.core.magic import Magics, magics_class, line_magic
396 from IPython.core.magic import Magics, magics_class, line_magic
397
397
398 @magics_class
398 @magics_class
399 class AutoreloadMagics(Magics):
399 class AutoreloadMagics(Magics):
400 def __init__(self, *a, **kw):
400 def __init__(self, *a, **kw):
401 super(AutoreloadMagics, self).__init__(*a, **kw)
401 super(AutoreloadMagics, self).__init__(*a, **kw)
402 self._reloader = ModuleReloader()
402 self._reloader = ModuleReloader()
403 self._reloader.check_all = False
403 self._reloader.check_all = False
404
404
405 @line_magic
405 @line_magic
406 def autoreload(self, parameter_s=''):
406 def autoreload(self, parameter_s=''):
407 r"""%autoreload => Reload modules automatically
407 r"""%autoreload => Reload modules automatically
408
408
409 %autoreload
409 %autoreload
410 Reload all modules (except those excluded by %aimport) automatically
410 Reload all modules (except those excluded by %aimport) automatically
411 now.
411 now.
412
412
413 %autoreload 0
413 %autoreload 0
414 Disable automatic reloading.
414 Disable automatic reloading.
415
415
416 %autoreload 1
416 %autoreload 1
417 Reload all modules imported with %aimport every time before executing
417 Reload all modules imported with %aimport every time before executing
418 the Python code typed.
418 the Python code typed.
419
419
420 %autoreload 2
420 %autoreload 2
421 Reload all modules (except those excluded by %aimport) every time
421 Reload all modules (except those excluded by %aimport) every time
422 before executing the Python code typed.
422 before executing the Python code typed.
423
423
424 Reloading Python modules in a reliable way is in general
424 Reloading Python modules in a reliable way is in general
425 difficult, and unexpected things may occur. %autoreload tries to
425 difficult, and unexpected things may occur. %autoreload tries to
426 work around common pitfalls by replacing function code objects and
426 work around common pitfalls by replacing function code objects and
427 parts of classes previously in the module with new versions. This
427 parts of classes previously in the module with new versions. This
428 makes the following things to work:
428 makes the following things to work:
429
429
430 - Functions and classes imported via 'from xxx import foo' are upgraded
430 - Functions and classes imported via 'from xxx import foo' are upgraded
431 to new versions when 'xxx' is reloaded.
431 to new versions when 'xxx' is reloaded.
432
432
433 - Methods and properties of classes are upgraded on reload, so that
433 - Methods and properties of classes are upgraded on reload, so that
434 calling 'c.foo()' on an object 'c' created before the reload causes
434 calling 'c.foo()' on an object 'c' created before the reload causes
435 the new code for 'foo' to be executed.
435 the new code for 'foo' to be executed.
436
436
437 Some of the known remaining caveats are:
437 Some of the known remaining caveats are:
438
438
439 - Replacing code objects does not always succeed: changing a @property
439 - Replacing code objects does not always succeed: changing a @property
440 in a class to an ordinary method or a method to a member variable
440 in a class to an ordinary method or a method to a member variable
441 can cause problems (but in old objects only).
441 can cause problems (but in old objects only).
442
442
443 - Functions that are removed (eg. via monkey-patching) from a module
443 - Functions that are removed (eg. via monkey-patching) from a module
444 before it is reloaded are not upgraded.
444 before it is reloaded are not upgraded.
445
445
446 - C extension modules cannot be reloaded, and so cannot be
446 - C extension modules cannot be reloaded, and so cannot be
447 autoreloaded.
447 autoreloaded.
448
448
449 """
449 """
450 if parameter_s == '':
450 if parameter_s == '':
451 self._reloader.check(True)
451 self._reloader.check(True)
452 elif parameter_s == '0':
452 elif parameter_s == '0':
453 self._reloader.enabled = False
453 self._reloader.enabled = False
454 elif parameter_s == '1':
454 elif parameter_s == '1':
455 self._reloader.check_all = False
455 self._reloader.check_all = False
456 self._reloader.enabled = True
456 self._reloader.enabled = True
457 elif parameter_s == '2':
457 elif parameter_s == '2':
458 self._reloader.check_all = True
458 self._reloader.check_all = True
459 self._reloader.enabled = True
459 self._reloader.enabled = True
460
460
461 @line_magic
461 @line_magic
462 def aimport(self, parameter_s='', stream=None):
462 def aimport(self, parameter_s='', stream=None):
463 """%aimport => Import modules for automatic reloading.
463 """%aimport => Import modules for automatic reloading.
464
464
465 %aimport
465 %aimport
466 List modules to automatically import and not to import.
466 List modules to automatically import and not to import.
467
467
468 %aimport foo
468 %aimport foo
469 Import module 'foo' and mark it to be autoreloaded for %autoreload 1
469 Import module 'foo' and mark it to be autoreloaded for %autoreload 1
470
470
471 %aimport -foo
471 %aimport -foo
472 Mark module 'foo' to not be autoreloaded for %autoreload 1
472 Mark module 'foo' to not be autoreloaded for %autoreload 1
473 """
473 """
474 modname = parameter_s
474 modname = parameter_s
475 if not modname:
475 if not modname:
476 to_reload = self._reloader.modules.keys()
476 to_reload = self._reloader.modules.keys()
477 to_reload.sort()
477 to_reload.sort()
478 to_skip = self._reloader.skip_modules.keys()
478 to_skip = self._reloader.skip_modules.keys()
479 to_skip.sort()
479 to_skip.sort()
480 if stream is None:
480 if stream is None:
481 stream = sys.stdout
481 stream = sys.stdout
482 if self._reloader.check_all:
482 if self._reloader.check_all:
483 stream.write("Modules to reload:\nall-except-skipped\n")
483 stream.write("Modules to reload:\nall-except-skipped\n")
484 else:
484 else:
485 stream.write("Modules to reload:\n%s\n" % ' '.join(to_reload))
485 stream.write("Modules to reload:\n%s\n" % ' '.join(to_reload))
486 stream.write("\nModules to skip:\n%s\n" % ' '.join(to_skip))
486 stream.write("\nModules to skip:\n%s\n" % ' '.join(to_skip))
487 elif modname.startswith('-'):
487 elif modname.startswith('-'):
488 modname = modname[1:]
488 modname = modname[1:]
489 self._reloader.mark_module_skipped(modname)
489 self._reloader.mark_module_skipped(modname)
490 else:
490 else:
491 top_module, top_name = self._reloader.aimport_module(modname)
491 top_module, top_name = self._reloader.aimport_module(modname)
492
492
493 # Inject module to user namespace
493 # Inject module to user namespace
494 self.shell.push({top_name: top_module})
494 self.shell.push({top_name: top_module})
495
495
496 def pre_run_code_hook(self, ip):
496 def pre_run_code_hook(self, ip):
497 if not self._reloader.enabled:
497 if not self._reloader.enabled:
498 raise TryNext
498 raise TryNext
499 try:
499 try:
500 self._reloader.check()
500 self._reloader.check()
501 except:
501 except:
502 pass
502 pass
503
503
504
504
505 def load_ipython_extension(ip):
505 def load_ipython_extension(ip):
506 """Load the extension in IPython."""
506 """Load the extension in IPython."""
507 auto_reload = AutoreloadMagics(ip)
507 auto_reload = AutoreloadMagics(ip)
508 ip.register_magics(auto_reload)
508 ip.register_magics(auto_reload)
509 ip.set_hook('pre_run_code_hook', auto_reload.pre_run_code_hook)
509 ip.set_hook('pre_run_code_hook', auto_reload.pre_run_code_hook)
@@ -1,219 +1,239 b''
1 """
1 """
2 Tools to open .py files as Unicode, using the encoding specified within the file,
2 Tools to open .py files as Unicode, using the encoding specified within the file,
3 as per PEP 263.
3 as per PEP 263.
4
4
5 Much of the code is taken from the tokenize module in Python 3.2.
5 Much of the code is taken from the tokenize module in Python 3.2.
6 """
6 """
7 from __future__ import absolute_import
7 from __future__ import absolute_import
8
8
9 import io
9 import io
10 from io import TextIOWrapper, BytesIO
10 from io import TextIOWrapper, BytesIO
11 import os.path
11 import re
12 import re
12
13
13 cookie_re = re.compile(ur"coding[:=]\s*([-\w.]+)", re.UNICODE)
14 cookie_re = re.compile(ur"coding[:=]\s*([-\w.]+)", re.UNICODE)
14 cookie_comment_re = re.compile(ur"^\s*#.*coding[:=]\s*([-\w.]+)", re.UNICODE)
15 cookie_comment_re = re.compile(ur"^\s*#.*coding[:=]\s*([-\w.]+)", re.UNICODE)
15
16
16 try:
17 try:
17 # Available in Python 3
18 # Available in Python 3
18 from tokenize import detect_encoding
19 from tokenize import detect_encoding
19 except ImportError:
20 except ImportError:
20 from codecs import lookup, BOM_UTF8
21 from codecs import lookup, BOM_UTF8
21
22
22 # Copied from Python 3.2 tokenize
23 # Copied from Python 3.2 tokenize
23 def _get_normal_name(orig_enc):
24 def _get_normal_name(orig_enc):
24 """Imitates get_normal_name in tokenizer.c."""
25 """Imitates get_normal_name in tokenizer.c."""
25 # Only care about the first 12 characters.
26 # Only care about the first 12 characters.
26 enc = orig_enc[:12].lower().replace("_", "-")
27 enc = orig_enc[:12].lower().replace("_", "-")
27 if enc == "utf-8" or enc.startswith("utf-8-"):
28 if enc == "utf-8" or enc.startswith("utf-8-"):
28 return "utf-8"
29 return "utf-8"
29 if enc in ("latin-1", "iso-8859-1", "iso-latin-1") or \
30 if enc in ("latin-1", "iso-8859-1", "iso-latin-1") or \
30 enc.startswith(("latin-1-", "iso-8859-1-", "iso-latin-1-")):
31 enc.startswith(("latin-1-", "iso-8859-1-", "iso-latin-1-")):
31 return "iso-8859-1"
32 return "iso-8859-1"
32 return orig_enc
33 return orig_enc
33
34
34 # Copied from Python 3.2 tokenize
35 # Copied from Python 3.2 tokenize
35 def detect_encoding(readline):
36 def detect_encoding(readline):
36 """
37 """
37 The detect_encoding() function is used to detect the encoding that should
38 The detect_encoding() function is used to detect the encoding that should
38 be used to decode a Python source file. It requires one argment, readline,
39 be used to decode a Python source file. It requires one argment, readline,
39 in the same way as the tokenize() generator.
40 in the same way as the tokenize() generator.
40
41
41 It will call readline a maximum of twice, and return the encoding used
42 It will call readline a maximum of twice, and return the encoding used
42 (as a string) and a list of any lines (left as bytes) it has read in.
43 (as a string) and a list of any lines (left as bytes) it has read in.
43
44
44 It detects the encoding from the presence of a utf-8 bom or an encoding
45 It detects the encoding from the presence of a utf-8 bom or an encoding
45 cookie as specified in pep-0263. If both a bom and a cookie are present,
46 cookie as specified in pep-0263. If both a bom and a cookie are present,
46 but disagree, a SyntaxError will be raised. If the encoding cookie is an
47 but disagree, a SyntaxError will be raised. If the encoding cookie is an
47 invalid charset, raise a SyntaxError. Note that if a utf-8 bom is found,
48 invalid charset, raise a SyntaxError. Note that if a utf-8 bom is found,
48 'utf-8-sig' is returned.
49 'utf-8-sig' is returned.
49
50
50 If no encoding is specified, then the default of 'utf-8' will be returned.
51 If no encoding is specified, then the default of 'utf-8' will be returned.
51 """
52 """
52 bom_found = False
53 bom_found = False
53 encoding = None
54 encoding = None
54 default = 'utf-8'
55 default = 'utf-8'
55 def read_or_stop():
56 def read_or_stop():
56 try:
57 try:
57 return readline()
58 return readline()
58 except StopIteration:
59 except StopIteration:
59 return b''
60 return b''
60
61
61 def find_cookie(line):
62 def find_cookie(line):
62 try:
63 try:
63 line_string = line.decode('ascii')
64 line_string = line.decode('ascii')
64 except UnicodeDecodeError:
65 except UnicodeDecodeError:
65 return None
66 return None
66
67
67 matches = cookie_re.findall(line_string)
68 matches = cookie_re.findall(line_string)
68 if not matches:
69 if not matches:
69 return None
70 return None
70 encoding = _get_normal_name(matches[0])
71 encoding = _get_normal_name(matches[0])
71 try:
72 try:
72 codec = lookup(encoding)
73 codec = lookup(encoding)
73 except LookupError:
74 except LookupError:
74 # This behaviour mimics the Python interpreter
75 # This behaviour mimics the Python interpreter
75 raise SyntaxError("unknown encoding: " + encoding)
76 raise SyntaxError("unknown encoding: " + encoding)
76
77
77 if bom_found:
78 if bom_found:
78 if codec.name != 'utf-8':
79 if codec.name != 'utf-8':
79 # This behaviour mimics the Python interpreter
80 # This behaviour mimics the Python interpreter
80 raise SyntaxError('encoding problem: utf-8')
81 raise SyntaxError('encoding problem: utf-8')
81 encoding += '-sig'
82 encoding += '-sig'
82 return encoding
83 return encoding
83
84
84 first = read_or_stop()
85 first = read_or_stop()
85 if first.startswith(BOM_UTF8):
86 if first.startswith(BOM_UTF8):
86 bom_found = True
87 bom_found = True
87 first = first[3:]
88 first = first[3:]
88 default = 'utf-8-sig'
89 default = 'utf-8-sig'
89 if not first:
90 if not first:
90 return default, []
91 return default, []
91
92
92 encoding = find_cookie(first)
93 encoding = find_cookie(first)
93 if encoding:
94 if encoding:
94 return encoding, [first]
95 return encoding, [first]
95
96
96 second = read_or_stop()
97 second = read_or_stop()
97 if not second:
98 if not second:
98 return default, [first]
99 return default, [first]
99
100
100 encoding = find_cookie(second)
101 encoding = find_cookie(second)
101 if encoding:
102 if encoding:
102 return encoding, [first, second]
103 return encoding, [first, second]
103
104
104 return default, [first, second]
105 return default, [first, second]
105
106
106 try:
107 try:
107 # Available in Python 3.2 and above.
108 # Available in Python 3.2 and above.
108 from tokenize import open
109 from tokenize import open
109 except ImportError:
110 except ImportError:
110 # Copied from Python 3.2 tokenize
111 # Copied from Python 3.2 tokenize
111 def open(filename):
112 def open(filename):
112 """Open a file in read only mode using the encoding detected by
113 """Open a file in read only mode using the encoding detected by
113 detect_encoding().
114 detect_encoding().
114 """
115 """
115 buffer = io.open(filename, 'rb') # Tweaked to use io.open for Python 2
116 buffer = io.open(filename, 'rb') # Tweaked to use io.open for Python 2
116 encoding, lines = detect_encoding(buffer.readline)
117 encoding, lines = detect_encoding(buffer.readline)
117 buffer.seek(0)
118 buffer.seek(0)
118 text = TextIOWrapper(buffer, encoding, line_buffering=True)
119 text = TextIOWrapper(buffer, encoding, line_buffering=True)
119 text.mode = 'r'
120 text.mode = 'r'
120 return text
121 return text
121
122
122 def source_to_unicode(txt, errors='replace', skip_encoding_cookie=True):
123 def source_to_unicode(txt, errors='replace', skip_encoding_cookie=True):
123 """Converts a bytes string with python source code to unicode.
124 """Converts a bytes string with python source code to unicode.
124
125
125 Unicode strings are passed through unchanged. Byte strings are checked
126 Unicode strings are passed through unchanged. Byte strings are checked
126 for the python source file encoding cookie to determine encoding.
127 for the python source file encoding cookie to determine encoding.
127 txt can be either a bytes buffer or a string containing the source
128 txt can be either a bytes buffer or a string containing the source
128 code.
129 code.
129 """
130 """
130 if isinstance(txt, unicode):
131 if isinstance(txt, unicode):
131 return txt
132 return txt
132 if isinstance(txt, bytes):
133 if isinstance(txt, bytes):
133 buffer = BytesIO(txt)
134 buffer = BytesIO(txt)
134 else:
135 else:
135 buffer = txt
136 buffer = txt
136 try:
137 try:
137 encoding, _ = detect_encoding(buffer.readline)
138 encoding, _ = detect_encoding(buffer.readline)
138 except SyntaxError:
139 except SyntaxError:
139 encoding = "ascii"
140 encoding = "ascii"
140 buffer.seek(0)
141 buffer.seek(0)
141 text = TextIOWrapper(buffer, encoding, errors=errors, line_buffering=True)
142 text = TextIOWrapper(buffer, encoding, errors=errors, line_buffering=True)
142 text.mode = 'r'
143 text.mode = 'r'
143 if skip_encoding_cookie:
144 if skip_encoding_cookie:
144 return u"".join(strip_encoding_cookie(text))
145 return u"".join(strip_encoding_cookie(text))
145 else:
146 else:
146 return text.read()
147 return text.read()
147
148
148 def strip_encoding_cookie(filelike):
149 def strip_encoding_cookie(filelike):
149 """Generator to pull lines from a text-mode file, skipping the encoding
150 """Generator to pull lines from a text-mode file, skipping the encoding
150 cookie if it is found in the first two lines.
151 cookie if it is found in the first two lines.
151 """
152 """
152 it = iter(filelike)
153 it = iter(filelike)
153 try:
154 try:
154 first = next(it)
155 first = next(it)
155 if not cookie_comment_re.match(first):
156 if not cookie_comment_re.match(first):
156 yield first
157 yield first
157 second = next(it)
158 second = next(it)
158 if not cookie_comment_re.match(second):
159 if not cookie_comment_re.match(second):
159 yield second
160 yield second
160 except StopIteration:
161 except StopIteration:
161 return
162 return
162
163
163 for line in it:
164 for line in it:
164 yield line
165 yield line
165
166
166 def read_py_file(filename, skip_encoding_cookie=True):
167 def read_py_file(filename, skip_encoding_cookie=True):
167 """Read a Python file, using the encoding declared inside the file.
168 """Read a Python file, using the encoding declared inside the file.
168
169
169 Parameters
170 Parameters
170 ----------
171 ----------
171 filename : str
172 filename : str
172 The path to the file to read.
173 The path to the file to read.
173 skip_encoding_cookie : bool
174 skip_encoding_cookie : bool
174 If True (the default), and the encoding declaration is found in the first
175 If True (the default), and the encoding declaration is found in the first
175 two lines, that line will be excluded from the output - compiling a
176 two lines, that line will be excluded from the output - compiling a
176 unicode string with an encoding declaration is a SyntaxError in Python 2.
177 unicode string with an encoding declaration is a SyntaxError in Python 2.
177
178
178 Returns
179 Returns
179 -------
180 -------
180 A unicode string containing the contents of the file.
181 A unicode string containing the contents of the file.
181 """
182 """
182 with open(filename) as f: # the open function defined in this module.
183 with open(filename) as f: # the open function defined in this module.
183 if skip_encoding_cookie:
184 if skip_encoding_cookie:
184 return "".join(strip_encoding_cookie(f))
185 return "".join(strip_encoding_cookie(f))
185 else:
186 else:
186 return f.read()
187 return f.read()
187
188
188 def read_py_url(url, errors='replace', skip_encoding_cookie=True):
189 def read_py_url(url, errors='replace', skip_encoding_cookie=True):
189 """Read a Python file from a URL, using the encoding declared inside the file.
190 """Read a Python file from a URL, using the encoding declared inside the file.
190
191
191 Parameters
192 Parameters
192 ----------
193 ----------
193 url : str
194 url : str
194 The URL from which to fetch the file.
195 The URL from which to fetch the file.
195 errors : str
196 errors : str
196 How to handle decoding errors in the file. Options are the same as for
197 How to handle decoding errors in the file. Options are the same as for
197 bytes.decode(), but here 'replace' is the default.
198 bytes.decode(), but here 'replace' is the default.
198 skip_encoding_cookie : bool
199 skip_encoding_cookie : bool
199 If True (the default), and the encoding declaration is found in the first
200 If True (the default), and the encoding declaration is found in the first
200 two lines, that line will be excluded from the output - compiling a
201 two lines, that line will be excluded from the output - compiling a
201 unicode string with an encoding declaration is a SyntaxError in Python 2.
202 unicode string with an encoding declaration is a SyntaxError in Python 2.
202
203
203 Returns
204 Returns
204 -------
205 -------
205 A unicode string containing the contents of the file.
206 A unicode string containing the contents of the file.
206 """
207 """
207 from urllib import urlopen # Deferred import for faster start
208 from urllib import urlopen # Deferred import for faster start
208 response = urlopen(url)
209 response = urlopen(url)
209 buffer = io.BytesIO(response.read())
210 buffer = io.BytesIO(response.read())
210 return source_to_unicode(buffer, errors, skip_encoding_cookie)
211 return source_to_unicode(buffer, errors, skip_encoding_cookie)
211
212
212 def _list_readline(x):
213 def _list_readline(x):
213 """Given a list, returns a readline() function that returns the next element
214 """Given a list, returns a readline() function that returns the next element
214 with each call.
215 with each call.
215 """
216 """
216 x = iter(x)
217 x = iter(x)
217 def readline():
218 def readline():
218 return next(x)
219 return next(x)
219 return readline
220 return readline
221
222 # Code for going between .py files and cached .pyc files ----------------------
223
224 try: # Python 3.2, see PEP 3147
225 from imp import source_from_cache, cache_from_source
226 except ImportError:
227 # Python <= 3.1: .pyc files go next to .py
228 def source_from_cache(path):
229 basename, ext = os.path.splitext(path)
230 if ext not in ('.pyc', '.pyo'):
231 raise ValueError('Not a cached Python file extension', ext)
232 # Should we look for .pyw files?
233 return basename + '.py'
234
235 def cache_from_source(path, debug_override=None):
236 if debug_override is None:
237 debug_override = __debug__
238 basename, ext = os.path.splitext(path)
239 return basename + '.pyc' if debug_override else '.pyo'
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now