##// END OF EJS Templates
Small fixes after Brian's review....
Fernando Perez -
Show More
@@ -1,261 +1,254 b''
1 """Tests for various magic functions.
1 """Tests for various magic functions.
2
2
3 Needs to be run by nose (to make ipython session available).
3 Needs to be run by nose (to make ipython session available).
4 """
4 """
5
5
6 import os
6 import os
7 import sys
7 import sys
8 import tempfile
8 import tempfile
9 import types
9 import types
10
10
11 import nose.tools as nt
11 import nose.tools as nt
12
12
13 from IPython.platutils import find_cmd, get_long_path_name
13 from IPython.platutils import find_cmd, get_long_path_name
14 from IPython.testing import decorators as dec
14 from IPython.testing import decorators as dec
15 from IPython.testing import tools as tt
15 from IPython.testing import tools as tt
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Test functions begin
18 # Test functions begin
19
19
20 def test_rehashx():
20 def test_rehashx():
21 # clear up everything
21 # clear up everything
22 _ip.IP.alias_table.clear()
22 _ip.IP.alias_table.clear()
23 del _ip.db['syscmdlist']
23 del _ip.db['syscmdlist']
24
24
25 _ip.magic('rehashx')
25 _ip.magic('rehashx')
26 # Practically ALL ipython development systems will have more than 10 aliases
26 # Practically ALL ipython development systems will have more than 10 aliases
27
27
28 yield (nt.assert_true, len(_ip.IP.alias_table) > 10)
28 yield (nt.assert_true, len(_ip.IP.alias_table) > 10)
29 for key, val in _ip.IP.alias_table.items():
29 for key, val in _ip.IP.alias_table.items():
30 # we must strip dots from alias names
30 # we must strip dots from alias names
31 nt.assert_true('.' not in key)
31 nt.assert_true('.' not in key)
32
32
33 # rehashx must fill up syscmdlist
33 # rehashx must fill up syscmdlist
34 scoms = _ip.db['syscmdlist']
34 scoms = _ip.db['syscmdlist']
35 yield (nt.assert_true, len(scoms) > 10)
35 yield (nt.assert_true, len(scoms) > 10)
36
36
37
37
38 ## def doctest_lsmagic():
39 ## """
40 ## In [15]: %lsmagic
41 ## Available magic functions:
42 ## %Exit
43 ## """
44
45 def doctest_hist_f():
38 def doctest_hist_f():
46 """Test %hist -f with temporary filename.
39 """Test %hist -f with temporary filename.
47
40
48 In [9]: import tempfile
41 In [9]: import tempfile
49
42
50 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
43 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
51
44
52 In [11]: %hist -n -f $tfile 3
45 In [11]: %hist -n -f $tfile 3
53
46
54 """
47 """
55
48
56
49
57 def doctest_hist_r():
50 def doctest_hist_r():
58 """Test %hist -r
51 """Test %hist -r
59
52
60 XXX - This test is not recording the output correctly. Not sure why...
53 XXX - This test is not recording the output correctly. Not sure why...
61
54
62 In [20]: 'hist' in _ip.IP.lsmagic()
55 In [20]: 'hist' in _ip.IP.lsmagic()
63 Out[20]: True
56 Out[20]: True
64
57
65 In [6]: x=1
58 In [6]: x=1
66
59
67 In [7]: %hist -n -r 2
60 In [7]: %hist -n -r 2
68 x=1 # random
61 x=1 # random
69 hist -n -r 2 # random
62 hist -n -r 2 # random
70 """
63 """
71
64
72 # This test is known to fail on win32.
65 # This test is known to fail on win32.
73 # See ticket https://bugs.launchpad.net/bugs/366334
66 # See ticket https://bugs.launchpad.net/bugs/366334
74 def test_obj_del():
67 def test_obj_del():
75 """Test that object's __del__ methods are called on exit."""
68 """Test that object's __del__ methods are called on exit."""
76 test_dir = os.path.dirname(__file__)
69 test_dir = os.path.dirname(__file__)
77 del_file = os.path.join(test_dir,'obj_del.py')
70 del_file = os.path.join(test_dir,'obj_del.py')
78 ipython_cmd = find_cmd('ipython')
71 ipython_cmd = find_cmd('ipython')
79 out = _ip.IP.getoutput('%s %s' % (ipython_cmd, del_file))
72 out = _ip.IP.getoutput('%s %s' % (ipython_cmd, del_file))
80 nt.assert_equals(out,'obj_del.py: object A deleted')
73 nt.assert_equals(out,'obj_del.py: object A deleted')
81
74
82
75
83 def test_shist():
76 def test_shist():
84 # Simple tests of ShadowHist class - test generator.
77 # Simple tests of ShadowHist class - test generator.
85 import os, shutil, tempfile
78 import os, shutil, tempfile
86
79
87 from IPython.Extensions import pickleshare
80 from IPython.Extensions import pickleshare
88 from IPython.history import ShadowHist
81 from IPython.history import ShadowHist
89
82
90 tfile = tempfile.mktemp('','tmp-ipython-')
83 tfile = tempfile.mktemp('','tmp-ipython-')
91
84
92 db = pickleshare.PickleShareDB(tfile)
85 db = pickleshare.PickleShareDB(tfile)
93 s = ShadowHist(db)
86 s = ShadowHist(db)
94 s.add('hello')
87 s.add('hello')
95 s.add('world')
88 s.add('world')
96 s.add('hello')
89 s.add('hello')
97 s.add('hello')
90 s.add('hello')
98 s.add('karhu')
91 s.add('karhu')
99
92
100 yield nt.assert_equals,s.all(),[(1, 'hello'), (2, 'world'), (3, 'karhu')]
93 yield nt.assert_equals,s.all(),[(1, 'hello'), (2, 'world'), (3, 'karhu')]
101
94
102 yield nt.assert_equal,s.get(2),'world'
95 yield nt.assert_equal,s.get(2),'world'
103
96
104 shutil.rmtree(tfile)
97 shutil.rmtree(tfile)
105
98
106 @dec.skipif_not_numpy
99 @dec.skipif_not_numpy
107 def test_numpy_clear_array_undec():
100 def test_numpy_clear_array_undec():
108 from IPython.Extensions import clearcmd
101 from IPython.Extensions import clearcmd
109
102
110 _ip.ex('import numpy as np')
103 _ip.ex('import numpy as np')
111 _ip.ex('a = np.empty(2)')
104 _ip.ex('a = np.empty(2)')
112 yield (nt.assert_true, 'a' in _ip.user_ns)
105 yield (nt.assert_true, 'a' in _ip.user_ns)
113 _ip.magic('clear array')
106 _ip.magic('clear array')
114 yield (nt.assert_false, 'a' in _ip.user_ns)
107 yield (nt.assert_false, 'a' in _ip.user_ns)
115
108
116
109
117 @dec.skip()
110 @dec.skip()
118 def test_fail_dec(*a,**k):
111 def test_fail_dec(*a,**k):
119 yield nt.assert_true, False
112 yield nt.assert_true, False
120
113
121 @dec.skip('This one shouldn not run')
114 @dec.skip('This one shouldn not run')
122 def test_fail_dec2(*a,**k):
115 def test_fail_dec2(*a,**k):
123 yield nt.assert_true, False
116 yield nt.assert_true, False
124
117
125 @dec.skipknownfailure
118 @dec.skipknownfailure
126 def test_fail_dec3(*a,**k):
119 def test_fail_dec3(*a,**k):
127 yield nt.assert_true, False
120 yield nt.assert_true, False
128
121
129
122
130 def doctest_refbug():
123 def doctest_refbug():
131 """Very nasty problem with references held by multiple runs of a script.
124 """Very nasty problem with references held by multiple runs of a script.
132 See: https://bugs.launchpad.net/ipython/+bug/269966
125 See: https://bugs.launchpad.net/ipython/+bug/269966
133
126
134 In [1]: _ip.IP.clear_main_mod_cache()
127 In [1]: _ip.IP.clear_main_mod_cache()
135
128
136 In [2]: run refbug
129 In [2]: run refbug
137
130
138 In [3]: call_f()
131 In [3]: call_f()
139 lowercased: hello
132 lowercased: hello
140
133
141 In [4]: run refbug
134 In [4]: run refbug
142
135
143 In [5]: call_f()
136 In [5]: call_f()
144 lowercased: hello
137 lowercased: hello
145 lowercased: hello
138 lowercased: hello
146 """
139 """
147
140
148 #-----------------------------------------------------------------------------
141 #-----------------------------------------------------------------------------
149 # Tests for %run
142 # Tests for %run
150 #-----------------------------------------------------------------------------
143 #-----------------------------------------------------------------------------
151
144
152 # %run is critical enough that it's a good idea to have a solid collection of
145 # %run is critical enough that it's a good idea to have a solid collection of
153 # tests for it, some as doctests and some as normal tests.
146 # tests for it, some as doctests and some as normal tests.
154
147
155 def doctest_run_ns():
148 def doctest_run_ns():
156 """Classes declared %run scripts must be instantiable afterwards.
149 """Classes declared %run scripts must be instantiable afterwards.
157
150
158 In [11]: run tclass foo
151 In [11]: run tclass foo
159
152
160 In [12]: isinstance(f(),foo)
153 In [12]: isinstance(f(),foo)
161 Out[12]: True
154 Out[12]: True
162 """
155 """
163
156
164
157
165 def doctest_run_ns2():
158 def doctest_run_ns2():
166 """Classes declared %run scripts must be instantiable afterwards.
159 """Classes declared %run scripts must be instantiable afterwards.
167
160
168 In [4]: run tclass C-first_pass
161 In [4]: run tclass C-first_pass
169
162
170 In [5]: run tclass C-second_pass
163 In [5]: run tclass C-second_pass
171 tclass.py: deleting object: C-first_pass
164 tclass.py: deleting object: C-first_pass
172 """
165 """
173
166
174 @dec.skip_win32
167 @dec.skip_win32
175 def doctest_run_builtins():
168 def doctest_run_builtins():
176 """Check that %run doesn't damage __builtins__ via a doctest.
169 """Check that %run doesn't damage __builtins__ via a doctest.
177
170
178 This is similar to the test_run_builtins, but I want *both* forms of the
171 This is similar to the test_run_builtins, but I want *both* forms of the
179 test to catch any possible glitches in our testing machinery, since that
172 test to catch any possible glitches in our testing machinery, since that
180 modifies %run somewhat. So for this, we have both a normal test (below)
173 modifies %run somewhat. So for this, we have both a normal test (below)
181 and a doctest (this one).
174 and a doctest (this one).
182
175
183 In [1]: import tempfile
176 In [1]: import tempfile
184
177
185 In [2]: bid1 = id(__builtins__)
178 In [2]: bid1 = id(__builtins__)
186
179
187 In [3]: f = tempfile.NamedTemporaryFile()
180 In [3]: f = tempfile.NamedTemporaryFile()
188
181
189 In [4]: f.write('pass\\n')
182 In [4]: f.write('pass\\n')
190
183
191 In [5]: f.flush()
184 In [5]: f.flush()
192
185
193 In [6]: print 'B1:',type(__builtins__)
186 In [6]: print 'B1:',type(__builtins__)
194 B1: <type 'module'>
187 B1: <type 'module'>
195
188
196 In [7]: %run $f.name
189 In [7]: %run $f.name
197
190
198 In [8]: bid2 = id(__builtins__)
191 In [8]: bid2 = id(__builtins__)
199
192
200 In [9]: print 'B2:',type(__builtins__)
193 In [9]: print 'B2:',type(__builtins__)
201 B2: <type 'module'>
194 B2: <type 'module'>
202
195
203 In [10]: bid1 == bid2
196 In [10]: bid1 == bid2
204 Out[10]: True
197 Out[10]: True
205 """
198 """
206
199
207 # For some tests, it will be handy to organize them in a class with a common
200 # For some tests, it will be handy to organize them in a class with a common
208 # setup that makes a temp file
201 # setup that makes a temp file
209
202
210 class TestMagicRun(object):
203 class TestMagicRun(object):
211
204
212 def setup(self):
205 def setup(self):
213 """Make a valid python temp file."""
206 """Make a valid python temp file."""
214 f = tempfile.NamedTemporaryFile()
207 f = tempfile.NamedTemporaryFile()
215 f.write('pass\n')
208 f.write('pass\n')
216 f.flush()
209 f.flush()
217 self.tmpfile = f
210 self.tmpfile = f
218
211
219 def run_tmpfile(self):
212 def run_tmpfile(self):
220 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
213 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
221 # See below and ticket https://bugs.launchpad.net/bugs/366353
214 # See below and ticket https://bugs.launchpad.net/bugs/366353
222 _ip.magic('run %s' % self.tmpfile.name)
215 _ip.magic('run %s' % self.tmpfile.name)
223
216
224 # See https://bugs.launchpad.net/bugs/366353
217 # See https://bugs.launchpad.net/bugs/366353
225 @dec.skip_if_not_win32
218 @dec.skip_if_not_win32
226 def test_run_tempfile_path(self):
219 def test_run_tempfile_path(self):
227 tt.assert_equals(True,False,"%run doesn't work with tempfile paths on win32.")
220 tt.assert_equals(True,False,"%run doesn't work with tempfile paths on win32.")
228
221
229 # See https://bugs.launchpad.net/bugs/366353
222 # See https://bugs.launchpad.net/bugs/366353
230 @dec.skip_win32
223 @dec.skip_win32
231 def test_builtins_id(self):
224 def test_builtins_id(self):
232 """Check that %run doesn't damage __builtins__ """
225 """Check that %run doesn't damage __builtins__ """
233
226
234 # Test that the id of __builtins__ is not modified by %run
227 # Test that the id of __builtins__ is not modified by %run
235 bid1 = id(_ip.user_ns['__builtins__'])
228 bid1 = id(_ip.user_ns['__builtins__'])
236 self.run_tmpfile()
229 self.run_tmpfile()
237 bid2 = id(_ip.user_ns['__builtins__'])
230 bid2 = id(_ip.user_ns['__builtins__'])
238 tt.assert_equals(bid1, bid2)
231 tt.assert_equals(bid1, bid2)
239
232
240 # See https://bugs.launchpad.net/bugs/366353
233 # See https://bugs.launchpad.net/bugs/366353
241 @dec.skip_win32
234 @dec.skip_win32
242 def test_builtins_type(self):
235 def test_builtins_type(self):
243 """Check that the type of __builtins__ doesn't change with %run.
236 """Check that the type of __builtins__ doesn't change with %run.
244
237
245 However, the above could pass if __builtins__ was already modified to
238 However, the above could pass if __builtins__ was already modified to
246 be a dict (it should be a module) by a previous use of %run. So we
239 be a dict (it should be a module) by a previous use of %run. So we
247 also check explicitly that it really is a module:
240 also check explicitly that it really is a module:
248 """
241 """
249 self.run_tmpfile()
242 self.run_tmpfile()
250 tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys))
243 tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys))
251
244
252 # See https://bugs.launchpad.net/bugs/366353
245 # See https://bugs.launchpad.net/bugs/366353
253 @dec.skip_win32
246 @dec.skip_win32
254 def test_prompts(self):
247 def test_prompts(self):
255 """Test that prompts correctly generate after %run"""
248 """Test that prompts correctly generate after %run"""
256 self.run_tmpfile()
249 self.run_tmpfile()
257 p2 = str(_ip.IP.outputcache.prompt2).strip()
250 p2 = str(_ip.IP.outputcache.prompt2).strip()
258 nt.assert_equals(p2[:3], '...')
251 nt.assert_equals(p2[:3], '...')
259
252
260 def teardown(self):
253 def teardown(self):
261 self.tmpfile.close()
254 self.tmpfile.close()
@@ -1,1056 +1,1056 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 ultraTB.py -- Spice up your tracebacks!
3 ultraTB.py -- Spice up your tracebacks!
4
4
5 * ColorTB
5 * ColorTB
6 I've always found it a bit hard to visually parse tracebacks in Python. The
6 I've always found it a bit hard to visually parse tracebacks in Python. The
7 ColorTB class is a solution to that problem. It colors the different parts of a
7 ColorTB class is a solution to that problem. It colors the different parts of a
8 traceback in a manner similar to what you would expect from a syntax-highlighting
8 traceback in a manner similar to what you would expect from a syntax-highlighting
9 text editor.
9 text editor.
10
10
11 Installation instructions for ColorTB:
11 Installation instructions for ColorTB:
12 import sys,ultraTB
12 import sys,ultraTB
13 sys.excepthook = ultraTB.ColorTB()
13 sys.excepthook = ultraTB.ColorTB()
14
14
15 * VerboseTB
15 * VerboseTB
16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
17 of useful info when a traceback occurs. Ping originally had it spit out HTML
17 of useful info when a traceback occurs. Ping originally had it spit out HTML
18 and intended it for CGI programmers, but why should they have all the fun? I
18 and intended it for CGI programmers, but why should they have all the fun? I
19 altered it to spit out colored text to the terminal. It's a bit overwhelming,
19 altered it to spit out colored text to the terminal. It's a bit overwhelming,
20 but kind of neat, and maybe useful for long-running programs that you believe
20 but kind of neat, and maybe useful for long-running programs that you believe
21 are bug-free. If a crash *does* occur in that type of program you want details.
21 are bug-free. If a crash *does* occur in that type of program you want details.
22 Give it a shot--you'll love it or you'll hate it.
22 Give it a shot--you'll love it or you'll hate it.
23
23
24 Note:
24 Note:
25
25
26 The Verbose mode prints the variables currently visible where the exception
26 The Verbose mode prints the variables currently visible where the exception
27 happened (shortening their strings if too long). This can potentially be
27 happened (shortening their strings if too long). This can potentially be
28 very slow, if you happen to have a huge data structure whose string
28 very slow, if you happen to have a huge data structure whose string
29 representation is complex to compute. Your computer may appear to freeze for
29 representation is complex to compute. Your computer may appear to freeze for
30 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
30 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
31 with Ctrl-C (maybe hitting it more than once).
31 with Ctrl-C (maybe hitting it more than once).
32
32
33 If you encounter this kind of situation often, you may want to use the
33 If you encounter this kind of situation often, you may want to use the
34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
35 variables (but otherwise includes the information and context given by
35 variables (but otherwise includes the information and context given by
36 Verbose).
36 Verbose).
37
37
38
38
39 Installation instructions for ColorTB:
39 Installation instructions for ColorTB:
40 import sys,ultraTB
40 import sys,ultraTB
41 sys.excepthook = ultraTB.VerboseTB()
41 sys.excepthook = ultraTB.VerboseTB()
42
42
43 Note: Much of the code in this module was lifted verbatim from the standard
43 Note: Much of the code in this module was lifted verbatim from the standard
44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
44 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
45
45
46 * Color schemes
46 * Color schemes
47 The colors are defined in the class TBTools through the use of the
47 The colors are defined in the class TBTools through the use of the
48 ColorSchemeTable class. Currently the following exist:
48 ColorSchemeTable class. Currently the following exist:
49
49
50 - NoColor: allows all of this module to be used in any terminal (the color
50 - NoColor: allows all of this module to be used in any terminal (the color
51 escapes are just dummy blank strings).
51 escapes are just dummy blank strings).
52
52
53 - Linux: is meant to look good in a terminal like the Linux console (black
53 - Linux: is meant to look good in a terminal like the Linux console (black
54 or very dark background).
54 or very dark background).
55
55
56 - LightBG: similar to Linux but swaps dark/light colors to be more readable
56 - LightBG: similar to Linux but swaps dark/light colors to be more readable
57 in light background terminals.
57 in light background terminals.
58
58
59 You can implement other color schemes easily, the syntax is fairly
59 You can implement other color schemes easily, the syntax is fairly
60 self-explanatory. Please send back new schemes you develop to the author for
60 self-explanatory. Please send back new schemes you develop to the author for
61 possible inclusion in future releases.
61 possible inclusion in future releases.
62 """
62 """
63
63
64 #*****************************************************************************
64 #*****************************************************************************
65 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
65 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
66 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
66 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
67 #
67 #
68 # Distributed under the terms of the BSD License. The full license is in
68 # Distributed under the terms of the BSD License. The full license is in
69 # the file COPYING, distributed as part of this software.
69 # the file COPYING, distributed as part of this software.
70 #*****************************************************************************
70 #*****************************************************************************
71
71
72 # Required modules
72 # Required modules
73 import inspect
73 import inspect
74 import keyword
74 import keyword
75 import linecache
75 import linecache
76 import os
76 import os
77 import pydoc
77 import pydoc
78 import re
78 import re
79 import string
79 import string
80 import sys
80 import sys
81 import time
81 import time
82 import tokenize
82 import tokenize
83 import traceback
83 import traceback
84 import types
84 import types
85
85
86 # For purposes of monkeypatching inspect to fix a bug in it.
86 # For purposes of monkeypatching inspect to fix a bug in it.
87 from inspect import getsourcefile, getfile, getmodule,\
87 from inspect import getsourcefile, getfile, getmodule,\
88 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
88 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
89
89
90
90
91 # IPython's own modules
91 # IPython's own modules
92 # Modified pdb which doesn't damage IPython's readline handling
92 # Modified pdb which doesn't damage IPython's readline handling
93 from IPython import Debugger, PyColorize
93 from IPython import Debugger, PyColorize, ipapi
94 from IPython.ipstruct import Struct
94 from IPython.ipstruct import Struct
95 from IPython.excolors import exception_colors
95 from IPython.excolors import exception_colors
96 from IPython.genutils import Term,uniq_stable,error,info
96 from IPython.genutils import Term,uniq_stable,error,info
97
97
98 # Globals
98 # Globals
99 # amount of space to put line numbers before verbose tracebacks
99 # amount of space to put line numbers before verbose tracebacks
100 INDENT_SIZE = 8
100 INDENT_SIZE = 8
101
101
102 # Default color scheme. This is used, for example, by the traceback
102 # Default color scheme. This is used, for example, by the traceback
103 # formatter. When running in an actual IPython instance, the user's rc.colors
103 # formatter. When running in an actual IPython instance, the user's rc.colors
104 # value is used, but havinga module global makes this functionality available
104 # value is used, but havinga module global makes this functionality available
105 # to users of ultraTB who are NOT running inside ipython.
105 # to users of ultraTB who are NOT running inside ipython.
106 DEFAULT_SCHEME = 'NoColor'
106 DEFAULT_SCHEME = 'NoColor'
107
107
108 #---------------------------------------------------------------------------
108 #---------------------------------------------------------------------------
109 # Code begins
109 # Code begins
110
110
111 # Utility functions
111 # Utility functions
112 def inspect_error():
112 def inspect_error():
113 """Print a message about internal inspect errors.
113 """Print a message about internal inspect errors.
114
114
115 These are unfortunately quite common."""
115 These are unfortunately quite common."""
116
116
117 error('Internal Python error in the inspect module.\n'
117 error('Internal Python error in the inspect module.\n'
118 'Below is the traceback from this internal error.\n')
118 'Below is the traceback from this internal error.\n')
119
119
120
120
121 def findsource(object):
121 def findsource(object):
122 """Return the entire source file and starting line number for an object.
122 """Return the entire source file and starting line number for an object.
123
123
124 The argument may be a module, class, method, function, traceback, frame,
124 The argument may be a module, class, method, function, traceback, frame,
125 or code object. The source code is returned as a list of all the lines
125 or code object. The source code is returned as a list of all the lines
126 in the file and the line number indexes a line in that list. An IOError
126 in the file and the line number indexes a line in that list. An IOError
127 is raised if the source code cannot be retrieved.
127 is raised if the source code cannot be retrieved.
128
128
129 FIXED version with which we monkeypatch the stdlib to work around a bug."""
129 FIXED version with which we monkeypatch the stdlib to work around a bug."""
130
130
131 file = getsourcefile(object) or getfile(object)
131 file = getsourcefile(object) or getfile(object)
132 # If the object is a frame, then trying to get the globals dict from its
132 # If the object is a frame, then trying to get the globals dict from its
133 # module won't work. Instead, the frame object itself has the globals
133 # module won't work. Instead, the frame object itself has the globals
134 # dictionary.
134 # dictionary.
135 globals_dict = None
135 globals_dict = None
136 if inspect.isframe(object):
136 if inspect.isframe(object):
137 # XXX: can this ever be false?
137 # XXX: can this ever be false?
138 globals_dict = object.f_globals
138 globals_dict = object.f_globals
139 else:
139 else:
140 module = getmodule(object, file)
140 module = getmodule(object, file)
141 if module:
141 if module:
142 globals_dict = module.__dict__
142 globals_dict = module.__dict__
143 lines = linecache.getlines(file, globals_dict)
143 lines = linecache.getlines(file, globals_dict)
144 if not lines:
144 if not lines:
145 raise IOError('could not get source code')
145 raise IOError('could not get source code')
146
146
147 if ismodule(object):
147 if ismodule(object):
148 return lines, 0
148 return lines, 0
149
149
150 if isclass(object):
150 if isclass(object):
151 name = object.__name__
151 name = object.__name__
152 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
152 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
153 # make some effort to find the best matching class definition:
153 # make some effort to find the best matching class definition:
154 # use the one with the least indentation, which is the one
154 # use the one with the least indentation, which is the one
155 # that's most probably not inside a function definition.
155 # that's most probably not inside a function definition.
156 candidates = []
156 candidates = []
157 for i in range(len(lines)):
157 for i in range(len(lines)):
158 match = pat.match(lines[i])
158 match = pat.match(lines[i])
159 if match:
159 if match:
160 # if it's at toplevel, it's already the best one
160 # if it's at toplevel, it's already the best one
161 if lines[i][0] == 'c':
161 if lines[i][0] == 'c':
162 return lines, i
162 return lines, i
163 # else add whitespace to candidate list
163 # else add whitespace to candidate list
164 candidates.append((match.group(1), i))
164 candidates.append((match.group(1), i))
165 if candidates:
165 if candidates:
166 # this will sort by whitespace, and by line number,
166 # this will sort by whitespace, and by line number,
167 # less whitespace first
167 # less whitespace first
168 candidates.sort()
168 candidates.sort()
169 return lines, candidates[0][1]
169 return lines, candidates[0][1]
170 else:
170 else:
171 raise IOError('could not find class definition')
171 raise IOError('could not find class definition')
172
172
173 if ismethod(object):
173 if ismethod(object):
174 object = object.im_func
174 object = object.im_func
175 if isfunction(object):
175 if isfunction(object):
176 object = object.func_code
176 object = object.func_code
177 if istraceback(object):
177 if istraceback(object):
178 object = object.tb_frame
178 object = object.tb_frame
179 if isframe(object):
179 if isframe(object):
180 object = object.f_code
180 object = object.f_code
181 if iscode(object):
181 if iscode(object):
182 if not hasattr(object, 'co_firstlineno'):
182 if not hasattr(object, 'co_firstlineno'):
183 raise IOError('could not find function definition')
183 raise IOError('could not find function definition')
184 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
184 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
185 pmatch = pat.match
185 pmatch = pat.match
186 # fperez - fix: sometimes, co_firstlineno can give a number larger than
186 # fperez - fix: sometimes, co_firstlineno can give a number larger than
187 # the length of lines, which causes an error. Safeguard against that.
187 # the length of lines, which causes an error. Safeguard against that.
188 lnum = min(object.co_firstlineno,len(lines))-1
188 lnum = min(object.co_firstlineno,len(lines))-1
189 while lnum > 0:
189 while lnum > 0:
190 if pmatch(lines[lnum]): break
190 if pmatch(lines[lnum]): break
191 lnum -= 1
191 lnum -= 1
192
192
193 return lines, lnum
193 return lines, lnum
194 raise IOError('could not find code object')
194 raise IOError('could not find code object')
195
195
196 # Monkeypatch inspect to apply our bugfix. This code only works with py25
196 # Monkeypatch inspect to apply our bugfix. This code only works with py25
197 if sys.version_info[:2] >= (2,5):
197 if sys.version_info[:2] >= (2,5):
198 inspect.findsource = findsource
198 inspect.findsource = findsource
199
199
200 def fix_frame_records_filenames(records):
200 def fix_frame_records_filenames(records):
201 """Try to fix the filenames in each record from inspect.getinnerframes().
201 """Try to fix the filenames in each record from inspect.getinnerframes().
202
202
203 Particularly, modules loaded from within zip files have useless filenames
203 Particularly, modules loaded from within zip files have useless filenames
204 attached to their code object, and inspect.getinnerframes() just uses it.
204 attached to their code object, and inspect.getinnerframes() just uses it.
205 """
205 """
206 fixed_records = []
206 fixed_records = []
207 for frame, filename, line_no, func_name, lines, index in records:
207 for frame, filename, line_no, func_name, lines, index in records:
208 # Look inside the frame's globals dictionary for __file__, which should
208 # Look inside the frame's globals dictionary for __file__, which should
209 # be better.
209 # be better.
210 better_fn = frame.f_globals.get('__file__', None)
210 better_fn = frame.f_globals.get('__file__', None)
211 if isinstance(better_fn, str):
211 if isinstance(better_fn, str):
212 # Check the type just in case someone did something weird with
212 # Check the type just in case someone did something weird with
213 # __file__. It might also be None if the error occurred during
213 # __file__. It might also be None if the error occurred during
214 # import.
214 # import.
215 filename = better_fn
215 filename = better_fn
216 fixed_records.append((frame, filename, line_no, func_name, lines, index))
216 fixed_records.append((frame, filename, line_no, func_name, lines, index))
217 return fixed_records
217 return fixed_records
218
218
219
219
220 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
220 def _fixed_getinnerframes(etb, context=1,tb_offset=0):
221 import linecache
221 import linecache
222 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
222 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
223
223
224 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
224 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
225
225
226 # If the error is at the console, don't build any context, since it would
226 # If the error is at the console, don't build any context, since it would
227 # otherwise produce 5 blank lines printed out (there is no file at the
227 # otherwise produce 5 blank lines printed out (there is no file at the
228 # console)
228 # console)
229 rec_check = records[tb_offset:]
229 rec_check = records[tb_offset:]
230 try:
230 try:
231 rname = rec_check[0][1]
231 rname = rec_check[0][1]
232 if rname == '<ipython console>' or rname.endswith('<string>'):
232 if rname == '<ipython console>' or rname.endswith('<string>'):
233 return rec_check
233 return rec_check
234 except IndexError:
234 except IndexError:
235 pass
235 pass
236
236
237 aux = traceback.extract_tb(etb)
237 aux = traceback.extract_tb(etb)
238 assert len(records) == len(aux)
238 assert len(records) == len(aux)
239 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
239 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
240 maybeStart = lnum-1 - context//2
240 maybeStart = lnum-1 - context//2
241 start = max(maybeStart, 0)
241 start = max(maybeStart, 0)
242 end = start + context
242 end = start + context
243 lines = linecache.getlines(file)[start:end]
243 lines = linecache.getlines(file)[start:end]
244 # pad with empty lines if necessary
244 # pad with empty lines if necessary
245 if maybeStart < 0:
245 if maybeStart < 0:
246 lines = (['\n'] * -maybeStart) + lines
246 lines = (['\n'] * -maybeStart) + lines
247 if len(lines) < context:
247 if len(lines) < context:
248 lines += ['\n'] * (context - len(lines))
248 lines += ['\n'] * (context - len(lines))
249 buf = list(records[i])
249 buf = list(records[i])
250 buf[LNUM_POS] = lnum
250 buf[LNUM_POS] = lnum
251 buf[INDEX_POS] = lnum - 1 - start
251 buf[INDEX_POS] = lnum - 1 - start
252 buf[LINES_POS] = lines
252 buf[LINES_POS] = lines
253 records[i] = tuple(buf)
253 records[i] = tuple(buf)
254 return records[tb_offset:]
254 return records[tb_offset:]
255
255
256 # Helper function -- largely belongs to VerboseTB, but we need the same
256 # Helper function -- largely belongs to VerboseTB, but we need the same
257 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
257 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
258 # can be recognized properly by ipython.el's py-traceback-line-re
258 # can be recognized properly by ipython.el's py-traceback-line-re
259 # (SyntaxErrors have to be treated specially because they have no traceback)
259 # (SyntaxErrors have to be treated specially because they have no traceback)
260
260
261 _parser = PyColorize.Parser()
261 _parser = PyColorize.Parser()
262
262
263 def _formatTracebackLines(lnum, index, lines, Colors, lvals=None,scheme=None):
263 def _formatTracebackLines(lnum, index, lines, Colors, lvals=None,scheme=None):
264 numbers_width = INDENT_SIZE - 1
264 numbers_width = INDENT_SIZE - 1
265 res = []
265 res = []
266 i = lnum - index
266 i = lnum - index
267
267
268 # This lets us get fully syntax-highlighted tracebacks.
268 # This lets us get fully syntax-highlighted tracebacks.
269 if scheme is None:
269 if scheme is None:
270 try:
270 try:
271 scheme = __IPYTHON__.rc.colors
271 scheme = ipapi.get().IP.rc.colors
272 except:
272 except:
273 scheme = DEFAULT_SCHEME
273 scheme = DEFAULT_SCHEME
274 _line_format = _parser.format2
274 _line_format = _parser.format2
275
275
276 for line in lines:
276 for line in lines:
277 new_line, err = _line_format(line,'str',scheme)
277 new_line, err = _line_format(line,'str',scheme)
278 if not err: line = new_line
278 if not err: line = new_line
279
279
280 if i == lnum:
280 if i == lnum:
281 # This is the line with the error
281 # This is the line with the error
282 pad = numbers_width - len(str(i))
282 pad = numbers_width - len(str(i))
283 if pad >= 3:
283 if pad >= 3:
284 marker = '-'*(pad-3) + '-> '
284 marker = '-'*(pad-3) + '-> '
285 elif pad == 2:
285 elif pad == 2:
286 marker = '> '
286 marker = '> '
287 elif pad == 1:
287 elif pad == 1:
288 marker = '>'
288 marker = '>'
289 else:
289 else:
290 marker = ''
290 marker = ''
291 num = marker + str(i)
291 num = marker + str(i)
292 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
292 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
293 Colors.line, line, Colors.Normal)
293 Colors.line, line, Colors.Normal)
294 else:
294 else:
295 num = '%*s' % (numbers_width,i)
295 num = '%*s' % (numbers_width,i)
296 line = '%s%s%s %s' %(Colors.lineno, num,
296 line = '%s%s%s %s' %(Colors.lineno, num,
297 Colors.Normal, line)
297 Colors.Normal, line)
298
298
299 res.append(line)
299 res.append(line)
300 if lvals and i == lnum:
300 if lvals and i == lnum:
301 res.append(lvals + '\n')
301 res.append(lvals + '\n')
302 i = i + 1
302 i = i + 1
303 return res
303 return res
304
304
305
305
306 #---------------------------------------------------------------------------
306 #---------------------------------------------------------------------------
307 # Module classes
307 # Module classes
308 class TBTools:
308 class TBTools:
309 """Basic tools used by all traceback printer classes."""
309 """Basic tools used by all traceback printer classes."""
310
310
311 def __init__(self,color_scheme = 'NoColor',call_pdb=False):
311 def __init__(self,color_scheme = 'NoColor',call_pdb=False):
312 # Whether to call the interactive pdb debugger after printing
312 # Whether to call the interactive pdb debugger after printing
313 # tracebacks or not
313 # tracebacks or not
314 self.call_pdb = call_pdb
314 self.call_pdb = call_pdb
315
315
316 # Create color table
316 # Create color table
317 self.color_scheme_table = exception_colors()
317 self.color_scheme_table = exception_colors()
318
318
319 self.set_colors(color_scheme)
319 self.set_colors(color_scheme)
320 self.old_scheme = color_scheme # save initial value for toggles
320 self.old_scheme = color_scheme # save initial value for toggles
321
321
322 if call_pdb:
322 if call_pdb:
323 self.pdb = Debugger.Pdb(self.color_scheme_table.active_scheme_name)
323 self.pdb = Debugger.Pdb(self.color_scheme_table.active_scheme_name)
324 else:
324 else:
325 self.pdb = None
325 self.pdb = None
326
326
327 def set_colors(self,*args,**kw):
327 def set_colors(self,*args,**kw):
328 """Shorthand access to the color table scheme selector method."""
328 """Shorthand access to the color table scheme selector method."""
329
329
330 # Set own color table
330 # Set own color table
331 self.color_scheme_table.set_active_scheme(*args,**kw)
331 self.color_scheme_table.set_active_scheme(*args,**kw)
332 # for convenience, set Colors to the active scheme
332 # for convenience, set Colors to the active scheme
333 self.Colors = self.color_scheme_table.active_colors
333 self.Colors = self.color_scheme_table.active_colors
334 # Also set colors of debugger
334 # Also set colors of debugger
335 if hasattr(self,'pdb') and self.pdb is not None:
335 if hasattr(self,'pdb') and self.pdb is not None:
336 self.pdb.set_colors(*args,**kw)
336 self.pdb.set_colors(*args,**kw)
337
337
338 def color_toggle(self):
338 def color_toggle(self):
339 """Toggle between the currently active color scheme and NoColor."""
339 """Toggle between the currently active color scheme and NoColor."""
340
340
341 if self.color_scheme_table.active_scheme_name == 'NoColor':
341 if self.color_scheme_table.active_scheme_name == 'NoColor':
342 self.color_scheme_table.set_active_scheme(self.old_scheme)
342 self.color_scheme_table.set_active_scheme(self.old_scheme)
343 self.Colors = self.color_scheme_table.active_colors
343 self.Colors = self.color_scheme_table.active_colors
344 else:
344 else:
345 self.old_scheme = self.color_scheme_table.active_scheme_name
345 self.old_scheme = self.color_scheme_table.active_scheme_name
346 self.color_scheme_table.set_active_scheme('NoColor')
346 self.color_scheme_table.set_active_scheme('NoColor')
347 self.Colors = self.color_scheme_table.active_colors
347 self.Colors = self.color_scheme_table.active_colors
348
348
349 #---------------------------------------------------------------------------
349 #---------------------------------------------------------------------------
350 class ListTB(TBTools):
350 class ListTB(TBTools):
351 """Print traceback information from a traceback list, with optional color.
351 """Print traceback information from a traceback list, with optional color.
352
352
353 Calling: requires 3 arguments:
353 Calling: requires 3 arguments:
354 (etype, evalue, elist)
354 (etype, evalue, elist)
355 as would be obtained by:
355 as would be obtained by:
356 etype, evalue, tb = sys.exc_info()
356 etype, evalue, tb = sys.exc_info()
357 if tb:
357 if tb:
358 elist = traceback.extract_tb(tb)
358 elist = traceback.extract_tb(tb)
359 else:
359 else:
360 elist = None
360 elist = None
361
361
362 It can thus be used by programs which need to process the traceback before
362 It can thus be used by programs which need to process the traceback before
363 printing (such as console replacements based on the code module from the
363 printing (such as console replacements based on the code module from the
364 standard library).
364 standard library).
365
365
366 Because they are meant to be called without a full traceback (only a
366 Because they are meant to be called without a full traceback (only a
367 list), instances of this class can't call the interactive pdb debugger."""
367 list), instances of this class can't call the interactive pdb debugger."""
368
368
369 def __init__(self,color_scheme = 'NoColor'):
369 def __init__(self,color_scheme = 'NoColor'):
370 TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0)
370 TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0)
371
371
372 def __call__(self, etype, value, elist):
372 def __call__(self, etype, value, elist):
373 Term.cout.flush()
373 Term.cout.flush()
374 print >> Term.cerr, self.text(etype,value,elist)
374 print >> Term.cerr, self.text(etype,value,elist)
375 Term.cerr.flush()
375 Term.cerr.flush()
376
376
377 def text(self,etype, value, elist,context=5):
377 def text(self,etype, value, elist,context=5):
378 """Return a color formatted string with the traceback info."""
378 """Return a color formatted string with the traceback info."""
379
379
380 Colors = self.Colors
380 Colors = self.Colors
381 out_string = ['%s%s%s\n' % (Colors.topline,'-'*60,Colors.Normal)]
381 out_string = ['%s%s%s\n' % (Colors.topline,'-'*60,Colors.Normal)]
382 if elist:
382 if elist:
383 out_string.append('Traceback %s(most recent call last)%s:' % \
383 out_string.append('Traceback %s(most recent call last)%s:' % \
384 (Colors.normalEm, Colors.Normal) + '\n')
384 (Colors.normalEm, Colors.Normal) + '\n')
385 out_string.extend(self._format_list(elist))
385 out_string.extend(self._format_list(elist))
386 lines = self._format_exception_only(etype, value)
386 lines = self._format_exception_only(etype, value)
387 for line in lines[:-1]:
387 for line in lines[:-1]:
388 out_string.append(" "+line)
388 out_string.append(" "+line)
389 out_string.append(lines[-1])
389 out_string.append(lines[-1])
390 return ''.join(out_string)
390 return ''.join(out_string)
391
391
392 def _format_list(self, extracted_list):
392 def _format_list(self, extracted_list):
393 """Format a list of traceback entry tuples for printing.
393 """Format a list of traceback entry tuples for printing.
394
394
395 Given a list of tuples as returned by extract_tb() or
395 Given a list of tuples as returned by extract_tb() or
396 extract_stack(), return a list of strings ready for printing.
396 extract_stack(), return a list of strings ready for printing.
397 Each string in the resulting list corresponds to the item with the
397 Each string in the resulting list corresponds to the item with the
398 same index in the argument list. Each string ends in a newline;
398 same index in the argument list. Each string ends in a newline;
399 the strings may contain internal newlines as well, for those items
399 the strings may contain internal newlines as well, for those items
400 whose source text line is not None.
400 whose source text line is not None.
401
401
402 Lifted almost verbatim from traceback.py
402 Lifted almost verbatim from traceback.py
403 """
403 """
404
404
405 Colors = self.Colors
405 Colors = self.Colors
406 list = []
406 list = []
407 for filename, lineno, name, line in extracted_list[:-1]:
407 for filename, lineno, name, line in extracted_list[:-1]:
408 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
408 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
409 (Colors.filename, filename, Colors.Normal,
409 (Colors.filename, filename, Colors.Normal,
410 Colors.lineno, lineno, Colors.Normal,
410 Colors.lineno, lineno, Colors.Normal,
411 Colors.name, name, Colors.Normal)
411 Colors.name, name, Colors.Normal)
412 if line:
412 if line:
413 item = item + ' %s\n' % line.strip()
413 item = item + ' %s\n' % line.strip()
414 list.append(item)
414 list.append(item)
415 # Emphasize the last entry
415 # Emphasize the last entry
416 filename, lineno, name, line = extracted_list[-1]
416 filename, lineno, name, line = extracted_list[-1]
417 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
417 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
418 (Colors.normalEm,
418 (Colors.normalEm,
419 Colors.filenameEm, filename, Colors.normalEm,
419 Colors.filenameEm, filename, Colors.normalEm,
420 Colors.linenoEm, lineno, Colors.normalEm,
420 Colors.linenoEm, lineno, Colors.normalEm,
421 Colors.nameEm, name, Colors.normalEm,
421 Colors.nameEm, name, Colors.normalEm,
422 Colors.Normal)
422 Colors.Normal)
423 if line:
423 if line:
424 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
424 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
425 Colors.Normal)
425 Colors.Normal)
426 list.append(item)
426 list.append(item)
427 return list
427 return list
428
428
429 def _format_exception_only(self, etype, value):
429 def _format_exception_only(self, etype, value):
430 """Format the exception part of a traceback.
430 """Format the exception part of a traceback.
431
431
432 The arguments are the exception type and value such as given by
432 The arguments are the exception type and value such as given by
433 sys.exc_info()[:2]. The return value is a list of strings, each ending
433 sys.exc_info()[:2]. The return value is a list of strings, each ending
434 in a newline. Normally, the list contains a single string; however,
434 in a newline. Normally, the list contains a single string; however,
435 for SyntaxError exceptions, it contains several lines that (when
435 for SyntaxError exceptions, it contains several lines that (when
436 printed) display detailed information about where the syntax error
436 printed) display detailed information about where the syntax error
437 occurred. The message indicating which exception occurred is the
437 occurred. The message indicating which exception occurred is the
438 always last string in the list.
438 always last string in the list.
439
439
440 Also lifted nearly verbatim from traceback.py
440 Also lifted nearly verbatim from traceback.py
441 """
441 """
442
442
443 have_filedata = False
443 have_filedata = False
444 Colors = self.Colors
444 Colors = self.Colors
445 list = []
445 list = []
446 try:
446 try:
447 stype = Colors.excName + etype.__name__ + Colors.Normal
447 stype = Colors.excName + etype.__name__ + Colors.Normal
448 except AttributeError:
448 except AttributeError:
449 stype = etype # String exceptions don't get special coloring
449 stype = etype # String exceptions don't get special coloring
450 if value is None:
450 if value is None:
451 list.append( str(stype) + '\n')
451 list.append( str(stype) + '\n')
452 else:
452 else:
453 if etype is SyntaxError:
453 if etype is SyntaxError:
454 try:
454 try:
455 msg, (filename, lineno, offset, line) = value
455 msg, (filename, lineno, offset, line) = value
456 except:
456 except:
457 have_filedata = False
457 have_filedata = False
458 else:
458 else:
459 have_filedata = True
459 have_filedata = True
460 #print 'filename is',filename # dbg
460 #print 'filename is',filename # dbg
461 if not filename: filename = "<string>"
461 if not filename: filename = "<string>"
462 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
462 list.append('%s File %s"%s"%s, line %s%d%s\n' % \
463 (Colors.normalEm,
463 (Colors.normalEm,
464 Colors.filenameEm, filename, Colors.normalEm,
464 Colors.filenameEm, filename, Colors.normalEm,
465 Colors.linenoEm, lineno, Colors.Normal ))
465 Colors.linenoEm, lineno, Colors.Normal ))
466 if line is not None:
466 if line is not None:
467 i = 0
467 i = 0
468 while i < len(line) and line[i].isspace():
468 while i < len(line) and line[i].isspace():
469 i = i+1
469 i = i+1
470 list.append('%s %s%s\n' % (Colors.line,
470 list.append('%s %s%s\n' % (Colors.line,
471 line.strip(),
471 line.strip(),
472 Colors.Normal))
472 Colors.Normal))
473 if offset is not None:
473 if offset is not None:
474 s = ' '
474 s = ' '
475 for c in line[i:offset-1]:
475 for c in line[i:offset-1]:
476 if c.isspace():
476 if c.isspace():
477 s = s + c
477 s = s + c
478 else:
478 else:
479 s = s + ' '
479 s = s + ' '
480 list.append('%s%s^%s\n' % (Colors.caret, s,
480 list.append('%s%s^%s\n' % (Colors.caret, s,
481 Colors.Normal) )
481 Colors.Normal) )
482 value = msg
482 value = msg
483 s = self._some_str(value)
483 s = self._some_str(value)
484 if s:
484 if s:
485 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
485 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
486 Colors.Normal, s))
486 Colors.Normal, s))
487 else:
487 else:
488 list.append('%s\n' % str(stype))
488 list.append('%s\n' % str(stype))
489
489
490 # vds:>>
490 # vds:>>
491 if have_filedata:
491 if have_filedata:
492 __IPYTHON__.hooks.synchronize_with_editor(filename, lineno, 0)
492 ipapi.get().IP.hooks.synchronize_with_editor(filename, lineno, 0)
493 # vds:<<
493 # vds:<<
494
494
495 return list
495 return list
496
496
497 def _some_str(self, value):
497 def _some_str(self, value):
498 # Lifted from traceback.py
498 # Lifted from traceback.py
499 try:
499 try:
500 return str(value)
500 return str(value)
501 except:
501 except:
502 return '<unprintable %s object>' % type(value).__name__
502 return '<unprintable %s object>' % type(value).__name__
503
503
504 #----------------------------------------------------------------------------
504 #----------------------------------------------------------------------------
505 class VerboseTB(TBTools):
505 class VerboseTB(TBTools):
506 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
506 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
507 of HTML. Requires inspect and pydoc. Crazy, man.
507 of HTML. Requires inspect and pydoc. Crazy, man.
508
508
509 Modified version which optionally strips the topmost entries from the
509 Modified version which optionally strips the topmost entries from the
510 traceback, to be used with alternate interpreters (because their own code
510 traceback, to be used with alternate interpreters (because their own code
511 would appear in the traceback)."""
511 would appear in the traceback)."""
512
512
513 def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0,
513 def __init__(self,color_scheme = 'Linux',tb_offset=0,long_header=0,
514 call_pdb = 0, include_vars=1):
514 call_pdb = 0, include_vars=1):
515 """Specify traceback offset, headers and color scheme.
515 """Specify traceback offset, headers and color scheme.
516
516
517 Define how many frames to drop from the tracebacks. Calling it with
517 Define how many frames to drop from the tracebacks. Calling it with
518 tb_offset=1 allows use of this handler in interpreters which will have
518 tb_offset=1 allows use of this handler in interpreters which will have
519 their own code at the top of the traceback (VerboseTB will first
519 their own code at the top of the traceback (VerboseTB will first
520 remove that frame before printing the traceback info)."""
520 remove that frame before printing the traceback info)."""
521 TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb)
521 TBTools.__init__(self,color_scheme=color_scheme,call_pdb=call_pdb)
522 self.tb_offset = tb_offset
522 self.tb_offset = tb_offset
523 self.long_header = long_header
523 self.long_header = long_header
524 self.include_vars = include_vars
524 self.include_vars = include_vars
525
525
526 def text(self, etype, evalue, etb, context=5):
526 def text(self, etype, evalue, etb, context=5):
527 """Return a nice text document describing the traceback."""
527 """Return a nice text document describing the traceback."""
528
528
529 # some locals
529 # some locals
530 try:
530 try:
531 etype = etype.__name__
531 etype = etype.__name__
532 except AttributeError:
532 except AttributeError:
533 pass
533 pass
534 Colors = self.Colors # just a shorthand + quicker name lookup
534 Colors = self.Colors # just a shorthand + quicker name lookup
535 ColorsNormal = Colors.Normal # used a lot
535 ColorsNormal = Colors.Normal # used a lot
536 col_scheme = self.color_scheme_table.active_scheme_name
536 col_scheme = self.color_scheme_table.active_scheme_name
537 indent = ' '*INDENT_SIZE
537 indent = ' '*INDENT_SIZE
538 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
538 em_normal = '%s\n%s%s' % (Colors.valEm, indent,ColorsNormal)
539 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
539 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
540 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
540 exc = '%s%s%s' % (Colors.excName,etype,ColorsNormal)
541
541
542 # some internal-use functions
542 # some internal-use functions
543 def text_repr(value):
543 def text_repr(value):
544 """Hopefully pretty robust repr equivalent."""
544 """Hopefully pretty robust repr equivalent."""
545 # this is pretty horrible but should always return *something*
545 # this is pretty horrible but should always return *something*
546 try:
546 try:
547 return pydoc.text.repr(value)
547 return pydoc.text.repr(value)
548 except KeyboardInterrupt:
548 except KeyboardInterrupt:
549 raise
549 raise
550 except:
550 except:
551 try:
551 try:
552 return repr(value)
552 return repr(value)
553 except KeyboardInterrupt:
553 except KeyboardInterrupt:
554 raise
554 raise
555 except:
555 except:
556 try:
556 try:
557 # all still in an except block so we catch
557 # all still in an except block so we catch
558 # getattr raising
558 # getattr raising
559 name = getattr(value, '__name__', None)
559 name = getattr(value, '__name__', None)
560 if name:
560 if name:
561 # ick, recursion
561 # ick, recursion
562 return text_repr(name)
562 return text_repr(name)
563 klass = getattr(value, '__class__', None)
563 klass = getattr(value, '__class__', None)
564 if klass:
564 if klass:
565 return '%s instance' % text_repr(klass)
565 return '%s instance' % text_repr(klass)
566 except KeyboardInterrupt:
566 except KeyboardInterrupt:
567 raise
567 raise
568 except:
568 except:
569 return 'UNRECOVERABLE REPR FAILURE'
569 return 'UNRECOVERABLE REPR FAILURE'
570 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
570 def eqrepr(value, repr=text_repr): return '=%s' % repr(value)
571 def nullrepr(value, repr=text_repr): return ''
571 def nullrepr(value, repr=text_repr): return ''
572
572
573 # meat of the code begins
573 # meat of the code begins
574 try:
574 try:
575 etype = etype.__name__
575 etype = etype.__name__
576 except AttributeError:
576 except AttributeError:
577 pass
577 pass
578
578
579 if self.long_header:
579 if self.long_header:
580 # Header with the exception type, python version, and date
580 # Header with the exception type, python version, and date
581 pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable
581 pyver = 'Python ' + string.split(sys.version)[0] + ': ' + sys.executable
582 date = time.ctime(time.time())
582 date = time.ctime(time.time())
583
583
584 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
584 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
585 exc, ' '*(75-len(str(etype))-len(pyver)),
585 exc, ' '*(75-len(str(etype))-len(pyver)),
586 pyver, string.rjust(date, 75) )
586 pyver, string.rjust(date, 75) )
587 head += "\nA problem occured executing Python code. Here is the sequence of function"\
587 head += "\nA problem occured executing Python code. Here is the sequence of function"\
588 "\ncalls leading up to the error, with the most recent (innermost) call last."
588 "\ncalls leading up to the error, with the most recent (innermost) call last."
589 else:
589 else:
590 # Simplified header
590 # Simplified header
591 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
591 head = '%s%s%s\n%s%s' % (Colors.topline, '-'*75, ColorsNormal,exc,
592 string.rjust('Traceback (most recent call last)',
592 string.rjust('Traceback (most recent call last)',
593 75 - len(str(etype)) ) )
593 75 - len(str(etype)) ) )
594 frames = []
594 frames = []
595 # Flush cache before calling inspect. This helps alleviate some of the
595 # Flush cache before calling inspect. This helps alleviate some of the
596 # problems with python 2.3's inspect.py.
596 # problems with python 2.3's inspect.py.
597 linecache.checkcache()
597 linecache.checkcache()
598 # Drop topmost frames if requested
598 # Drop topmost frames if requested
599 try:
599 try:
600 # Try the default getinnerframes and Alex's: Alex's fixes some
600 # Try the default getinnerframes and Alex's: Alex's fixes some
601 # problems, but it generates empty tracebacks for console errors
601 # problems, but it generates empty tracebacks for console errors
602 # (5 blanks lines) where none should be returned.
602 # (5 blanks lines) where none should be returned.
603 #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
603 #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
604 #print 'python records:', records # dbg
604 #print 'python records:', records # dbg
605 records = _fixed_getinnerframes(etb, context,self.tb_offset)
605 records = _fixed_getinnerframes(etb, context,self.tb_offset)
606 #print 'alex records:', records # dbg
606 #print 'alex records:', records # dbg
607 except:
607 except:
608
608
609 # FIXME: I've been getting many crash reports from python 2.3
609 # FIXME: I've been getting many crash reports from python 2.3
610 # users, traceable to inspect.py. If I can find a small test-case
610 # users, traceable to inspect.py. If I can find a small test-case
611 # to reproduce this, I should either write a better workaround or
611 # to reproduce this, I should either write a better workaround or
612 # file a bug report against inspect (if that's the real problem).
612 # file a bug report against inspect (if that's the real problem).
613 # So far, I haven't been able to find an isolated example to
613 # So far, I haven't been able to find an isolated example to
614 # reproduce the problem.
614 # reproduce the problem.
615 inspect_error()
615 inspect_error()
616 traceback.print_exc(file=Term.cerr)
616 traceback.print_exc(file=Term.cerr)
617 info('\nUnfortunately, your original traceback can not be constructed.\n')
617 info('\nUnfortunately, your original traceback can not be constructed.\n')
618 return ''
618 return ''
619
619
620 # build some color string templates outside these nested loops
620 # build some color string templates outside these nested loops
621 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
621 tpl_link = '%s%%s%s' % (Colors.filenameEm,ColorsNormal)
622 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
622 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
623 ColorsNormal)
623 ColorsNormal)
624 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
624 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
625 (Colors.vName, Colors.valEm, ColorsNormal)
625 (Colors.vName, Colors.valEm, ColorsNormal)
626 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
626 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
627 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
627 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
628 Colors.vName, ColorsNormal)
628 Colors.vName, ColorsNormal)
629 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
629 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
630 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
630 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
631 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
631 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm,Colors.line,
632 ColorsNormal)
632 ColorsNormal)
633
633
634 # now, loop over all records printing context and info
634 # now, loop over all records printing context and info
635 abspath = os.path.abspath
635 abspath = os.path.abspath
636 for frame, file, lnum, func, lines, index in records:
636 for frame, file, lnum, func, lines, index in records:
637 #print '*** record:',file,lnum,func,lines,index # dbg
637 #print '*** record:',file,lnum,func,lines,index # dbg
638 try:
638 try:
639 file = file and abspath(file) or '?'
639 file = file and abspath(file) or '?'
640 except OSError:
640 except OSError:
641 # if file is '<console>' or something not in the filesystem,
641 # if file is '<console>' or something not in the filesystem,
642 # the abspath call will throw an OSError. Just ignore it and
642 # the abspath call will throw an OSError. Just ignore it and
643 # keep the original file string.
643 # keep the original file string.
644 pass
644 pass
645 link = tpl_link % file
645 link = tpl_link % file
646 try:
646 try:
647 args, varargs, varkw, locals = inspect.getargvalues(frame)
647 args, varargs, varkw, locals = inspect.getargvalues(frame)
648 except:
648 except:
649 # This can happen due to a bug in python2.3. We should be
649 # This can happen due to a bug in python2.3. We should be
650 # able to remove this try/except when 2.4 becomes a
650 # able to remove this try/except when 2.4 becomes a
651 # requirement. Bug details at http://python.org/sf/1005466
651 # requirement. Bug details at http://python.org/sf/1005466
652 inspect_error()
652 inspect_error()
653 traceback.print_exc(file=Term.cerr)
653 traceback.print_exc(file=Term.cerr)
654 info("\nIPython's exception reporting continues...\n")
654 info("\nIPython's exception reporting continues...\n")
655
655
656 if func == '?':
656 if func == '?':
657 call = ''
657 call = ''
658 else:
658 else:
659 # Decide whether to include variable details or not
659 # Decide whether to include variable details or not
660 var_repr = self.include_vars and eqrepr or nullrepr
660 var_repr = self.include_vars and eqrepr or nullrepr
661 try:
661 try:
662 call = tpl_call % (func,inspect.formatargvalues(args,
662 call = tpl_call % (func,inspect.formatargvalues(args,
663 varargs, varkw,
663 varargs, varkw,
664 locals,formatvalue=var_repr))
664 locals,formatvalue=var_repr))
665 except KeyError:
665 except KeyError:
666 # Very odd crash from inspect.formatargvalues(). The
666 # Very odd crash from inspect.formatargvalues(). The
667 # scenario under which it appeared was a call to
667 # scenario under which it appeared was a call to
668 # view(array,scale) in NumTut.view.view(), where scale had
668 # view(array,scale) in NumTut.view.view(), where scale had
669 # been defined as a scalar (it should be a tuple). Somehow
669 # been defined as a scalar (it should be a tuple). Somehow
670 # inspect messes up resolving the argument list of view()
670 # inspect messes up resolving the argument list of view()
671 # and barfs out. At some point I should dig into this one
671 # and barfs out. At some point I should dig into this one
672 # and file a bug report about it.
672 # and file a bug report about it.
673 inspect_error()
673 inspect_error()
674 traceback.print_exc(file=Term.cerr)
674 traceback.print_exc(file=Term.cerr)
675 info("\nIPython's exception reporting continues...\n")
675 info("\nIPython's exception reporting continues...\n")
676 call = tpl_call_fail % func
676 call = tpl_call_fail % func
677
677
678 # Initialize a list of names on the current line, which the
678 # Initialize a list of names on the current line, which the
679 # tokenizer below will populate.
679 # tokenizer below will populate.
680 names = []
680 names = []
681
681
682 def tokeneater(token_type, token, start, end, line):
682 def tokeneater(token_type, token, start, end, line):
683 """Stateful tokeneater which builds dotted names.
683 """Stateful tokeneater which builds dotted names.
684
684
685 The list of names it appends to (from the enclosing scope) can
685 The list of names it appends to (from the enclosing scope) can
686 contain repeated composite names. This is unavoidable, since
686 contain repeated composite names. This is unavoidable, since
687 there is no way to disambguate partial dotted structures until
687 there is no way to disambguate partial dotted structures until
688 the full list is known. The caller is responsible for pruning
688 the full list is known. The caller is responsible for pruning
689 the final list of duplicates before using it."""
689 the final list of duplicates before using it."""
690
690
691 # build composite names
691 # build composite names
692 if token == '.':
692 if token == '.':
693 try:
693 try:
694 names[-1] += '.'
694 names[-1] += '.'
695 # store state so the next token is added for x.y.z names
695 # store state so the next token is added for x.y.z names
696 tokeneater.name_cont = True
696 tokeneater.name_cont = True
697 return
697 return
698 except IndexError:
698 except IndexError:
699 pass
699 pass
700 if token_type == tokenize.NAME and token not in keyword.kwlist:
700 if token_type == tokenize.NAME and token not in keyword.kwlist:
701 if tokeneater.name_cont:
701 if tokeneater.name_cont:
702 # Dotted names
702 # Dotted names
703 names[-1] += token
703 names[-1] += token
704 tokeneater.name_cont = False
704 tokeneater.name_cont = False
705 else:
705 else:
706 # Regular new names. We append everything, the caller
706 # Regular new names. We append everything, the caller
707 # will be responsible for pruning the list later. It's
707 # will be responsible for pruning the list later. It's
708 # very tricky to try to prune as we go, b/c composite
708 # very tricky to try to prune as we go, b/c composite
709 # names can fool us. The pruning at the end is easy
709 # names can fool us. The pruning at the end is easy
710 # to do (or the caller can print a list with repeated
710 # to do (or the caller can print a list with repeated
711 # names if so desired.
711 # names if so desired.
712 names.append(token)
712 names.append(token)
713 elif token_type == tokenize.NEWLINE:
713 elif token_type == tokenize.NEWLINE:
714 raise IndexError
714 raise IndexError
715 # we need to store a bit of state in the tokenizer to build
715 # we need to store a bit of state in the tokenizer to build
716 # dotted names
716 # dotted names
717 tokeneater.name_cont = False
717 tokeneater.name_cont = False
718
718
719 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
719 def linereader(file=file, lnum=[lnum], getline=linecache.getline):
720 line = getline(file, lnum[0])
720 line = getline(file, lnum[0])
721 lnum[0] += 1
721 lnum[0] += 1
722 return line
722 return line
723
723
724 # Build the list of names on this line of code where the exception
724 # Build the list of names on this line of code where the exception
725 # occurred.
725 # occurred.
726 try:
726 try:
727 # This builds the names list in-place by capturing it from the
727 # This builds the names list in-place by capturing it from the
728 # enclosing scope.
728 # enclosing scope.
729 tokenize.tokenize(linereader, tokeneater)
729 tokenize.tokenize(linereader, tokeneater)
730 except IndexError:
730 except IndexError:
731 # signals exit of tokenizer
731 # signals exit of tokenizer
732 pass
732 pass
733 except tokenize.TokenError,msg:
733 except tokenize.TokenError,msg:
734 _m = ("An unexpected error occurred while tokenizing input\n"
734 _m = ("An unexpected error occurred while tokenizing input\n"
735 "The following traceback may be corrupted or invalid\n"
735 "The following traceback may be corrupted or invalid\n"
736 "The error message is: %s\n" % msg)
736 "The error message is: %s\n" % msg)
737 error(_m)
737 error(_m)
738
738
739 # prune names list of duplicates, but keep the right order
739 # prune names list of duplicates, but keep the right order
740 unique_names = uniq_stable(names)
740 unique_names = uniq_stable(names)
741
741
742 # Start loop over vars
742 # Start loop over vars
743 lvals = []
743 lvals = []
744 if self.include_vars:
744 if self.include_vars:
745 for name_full in unique_names:
745 for name_full in unique_names:
746 name_base = name_full.split('.',1)[0]
746 name_base = name_full.split('.',1)[0]
747 if name_base in frame.f_code.co_varnames:
747 if name_base in frame.f_code.co_varnames:
748 if locals.has_key(name_base):
748 if locals.has_key(name_base):
749 try:
749 try:
750 value = repr(eval(name_full,locals))
750 value = repr(eval(name_full,locals))
751 except:
751 except:
752 value = undefined
752 value = undefined
753 else:
753 else:
754 value = undefined
754 value = undefined
755 name = tpl_local_var % name_full
755 name = tpl_local_var % name_full
756 else:
756 else:
757 if frame.f_globals.has_key(name_base):
757 if frame.f_globals.has_key(name_base):
758 try:
758 try:
759 value = repr(eval(name_full,frame.f_globals))
759 value = repr(eval(name_full,frame.f_globals))
760 except:
760 except:
761 value = undefined
761 value = undefined
762 else:
762 else:
763 value = undefined
763 value = undefined
764 name = tpl_global_var % name_full
764 name = tpl_global_var % name_full
765 lvals.append(tpl_name_val % (name,value))
765 lvals.append(tpl_name_val % (name,value))
766 if lvals:
766 if lvals:
767 lvals = '%s%s' % (indent,em_normal.join(lvals))
767 lvals = '%s%s' % (indent,em_normal.join(lvals))
768 else:
768 else:
769 lvals = ''
769 lvals = ''
770
770
771 level = '%s %s\n' % (link,call)
771 level = '%s %s\n' % (link,call)
772
772
773 if index is None:
773 if index is None:
774 frames.append(level)
774 frames.append(level)
775 else:
775 else:
776 frames.append('%s%s' % (level,''.join(
776 frames.append('%s%s' % (level,''.join(
777 _formatTracebackLines(lnum,index,lines,Colors,lvals,
777 _formatTracebackLines(lnum,index,lines,Colors,lvals,
778 col_scheme))))
778 col_scheme))))
779
779
780 # Get (safely) a string form of the exception info
780 # Get (safely) a string form of the exception info
781 try:
781 try:
782 etype_str,evalue_str = map(str,(etype,evalue))
782 etype_str,evalue_str = map(str,(etype,evalue))
783 except:
783 except:
784 # User exception is improperly defined.
784 # User exception is improperly defined.
785 etype,evalue = str,sys.exc_info()[:2]
785 etype,evalue = str,sys.exc_info()[:2]
786 etype_str,evalue_str = map(str,(etype,evalue))
786 etype_str,evalue_str = map(str,(etype,evalue))
787 # ... and format it
787 # ... and format it
788 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
788 exception = ['%s%s%s: %s' % (Colors.excName, etype_str,
789 ColorsNormal, evalue_str)]
789 ColorsNormal, evalue_str)]
790 if type(evalue) is types.InstanceType:
790 if type(evalue) is types.InstanceType:
791 try:
791 try:
792 names = [w for w in dir(evalue) if isinstance(w, basestring)]
792 names = [w for w in dir(evalue) if isinstance(w, basestring)]
793 except:
793 except:
794 # Every now and then, an object with funny inernals blows up
794 # Every now and then, an object with funny inernals blows up
795 # when dir() is called on it. We do the best we can to report
795 # when dir() is called on it. We do the best we can to report
796 # the problem and continue
796 # the problem and continue
797 _m = '%sException reporting error (object with broken dir())%s:'
797 _m = '%sException reporting error (object with broken dir())%s:'
798 exception.append(_m % (Colors.excName,ColorsNormal))
798 exception.append(_m % (Colors.excName,ColorsNormal))
799 etype_str,evalue_str = map(str,sys.exc_info()[:2])
799 etype_str,evalue_str = map(str,sys.exc_info()[:2])
800 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
800 exception.append('%s%s%s: %s' % (Colors.excName,etype_str,
801 ColorsNormal, evalue_str))
801 ColorsNormal, evalue_str))
802 names = []
802 names = []
803 for name in names:
803 for name in names:
804 value = text_repr(getattr(evalue, name))
804 value = text_repr(getattr(evalue, name))
805 exception.append('\n%s%s = %s' % (indent, name, value))
805 exception.append('\n%s%s = %s' % (indent, name, value))
806
806
807 # vds: >>
807 # vds: >>
808 if records:
808 if records:
809 filepath, lnum = records[-1][1:3]
809 filepath, lnum = records[-1][1:3]
810 #print "file:", str(file), "linenb", str(lnum) # dbg
810 #print "file:", str(file), "linenb", str(lnum) # dbg
811 filepath = os.path.abspath(filepath)
811 filepath = os.path.abspath(filepath)
812 __IPYTHON__.hooks.synchronize_with_editor(filepath, lnum, 0)
812 ipapi.get().IP.hooks.synchronize_with_editor(filepath, lnum, 0)
813 # vds: <<
813 # vds: <<
814
814
815 # return all our info assembled as a single string
815 # return all our info assembled as a single string
816 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
816 return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
817
817
818 def debugger(self,force=False):
818 def debugger(self,force=False):
819 """Call up the pdb debugger if desired, always clean up the tb
819 """Call up the pdb debugger if desired, always clean up the tb
820 reference.
820 reference.
821
821
822 Keywords:
822 Keywords:
823
823
824 - force(False): by default, this routine checks the instance call_pdb
824 - force(False): by default, this routine checks the instance call_pdb
825 flag and does not actually invoke the debugger if the flag is false.
825 flag and does not actually invoke the debugger if the flag is false.
826 The 'force' option forces the debugger to activate even if the flag
826 The 'force' option forces the debugger to activate even if the flag
827 is false.
827 is false.
828
828
829 If the call_pdb flag is set, the pdb interactive debugger is
829 If the call_pdb flag is set, the pdb interactive debugger is
830 invoked. In all cases, the self.tb reference to the current traceback
830 invoked. In all cases, the self.tb reference to the current traceback
831 is deleted to prevent lingering references which hamper memory
831 is deleted to prevent lingering references which hamper memory
832 management.
832 management.
833
833
834 Note that each call to pdb() does an 'import readline', so if your app
834 Note that each call to pdb() does an 'import readline', so if your app
835 requires a special setup for the readline completers, you'll have to
835 requires a special setup for the readline completers, you'll have to
836 fix that by hand after invoking the exception handler."""
836 fix that by hand after invoking the exception handler."""
837
837
838 if force or self.call_pdb:
838 if force or self.call_pdb:
839 if self.pdb is None:
839 if self.pdb is None:
840 self.pdb = Debugger.Pdb(
840 self.pdb = Debugger.Pdb(
841 self.color_scheme_table.active_scheme_name)
841 self.color_scheme_table.active_scheme_name)
842 # the system displayhook may have changed, restore the original
842 # the system displayhook may have changed, restore the original
843 # for pdb
843 # for pdb
844 dhook = sys.displayhook
844 dhook = sys.displayhook
845 sys.displayhook = sys.__displayhook__
845 sys.displayhook = sys.__displayhook__
846 self.pdb.reset()
846 self.pdb.reset()
847 # Find the right frame so we don't pop up inside ipython itself
847 # Find the right frame so we don't pop up inside ipython itself
848 if hasattr(self,'tb'):
848 if hasattr(self,'tb'):
849 etb = self.tb
849 etb = self.tb
850 else:
850 else:
851 etb = self.tb = sys.last_traceback
851 etb = self.tb = sys.last_traceback
852 while self.tb.tb_next is not None:
852 while self.tb.tb_next is not None:
853 self.tb = self.tb.tb_next
853 self.tb = self.tb.tb_next
854 try:
854 try:
855 if etb and etb.tb_next:
855 if etb and etb.tb_next:
856 etb = etb.tb_next
856 etb = etb.tb_next
857 self.pdb.botframe = etb.tb_frame
857 self.pdb.botframe = etb.tb_frame
858 self.pdb.interaction(self.tb.tb_frame, self.tb)
858 self.pdb.interaction(self.tb.tb_frame, self.tb)
859 finally:
859 finally:
860 sys.displayhook = dhook
860 sys.displayhook = dhook
861
861
862 if hasattr(self,'tb'):
862 if hasattr(self,'tb'):
863 del self.tb
863 del self.tb
864
864
865 def handler(self, info=None):
865 def handler(self, info=None):
866 (etype, evalue, etb) = info or sys.exc_info()
866 (etype, evalue, etb) = info or sys.exc_info()
867 self.tb = etb
867 self.tb = etb
868 Term.cout.flush()
868 Term.cout.flush()
869 print >> Term.cerr, self.text(etype, evalue, etb)
869 print >> Term.cerr, self.text(etype, evalue, etb)
870 Term.cerr.flush()
870 Term.cerr.flush()
871
871
872 # Changed so an instance can just be called as VerboseTB_inst() and print
872 # Changed so an instance can just be called as VerboseTB_inst() and print
873 # out the right info on its own.
873 # out the right info on its own.
874 def __call__(self, etype=None, evalue=None, etb=None):
874 def __call__(self, etype=None, evalue=None, etb=None):
875 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
875 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
876 if etb is None:
876 if etb is None:
877 self.handler()
877 self.handler()
878 else:
878 else:
879 self.handler((etype, evalue, etb))
879 self.handler((etype, evalue, etb))
880 try:
880 try:
881 self.debugger()
881 self.debugger()
882 except KeyboardInterrupt:
882 except KeyboardInterrupt:
883 print "\nKeyboardInterrupt"
883 print "\nKeyboardInterrupt"
884
884
885 #----------------------------------------------------------------------------
885 #----------------------------------------------------------------------------
886 class FormattedTB(VerboseTB,ListTB):
886 class FormattedTB(VerboseTB,ListTB):
887 """Subclass ListTB but allow calling with a traceback.
887 """Subclass ListTB but allow calling with a traceback.
888
888
889 It can thus be used as a sys.excepthook for Python > 2.1.
889 It can thus be used as a sys.excepthook for Python > 2.1.
890
890
891 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
891 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
892
892
893 Allows a tb_offset to be specified. This is useful for situations where
893 Allows a tb_offset to be specified. This is useful for situations where
894 one needs to remove a number of topmost frames from the traceback (such as
894 one needs to remove a number of topmost frames from the traceback (such as
895 occurs with python programs that themselves execute other python code,
895 occurs with python programs that themselves execute other python code,
896 like Python shells). """
896 like Python shells). """
897
897
898 def __init__(self, mode = 'Plain', color_scheme='Linux',
898 def __init__(self, mode = 'Plain', color_scheme='Linux',
899 tb_offset = 0,long_header=0,call_pdb=0,include_vars=0):
899 tb_offset = 0,long_header=0,call_pdb=0,include_vars=0):
900
900
901 # NEVER change the order of this list. Put new modes at the end:
901 # NEVER change the order of this list. Put new modes at the end:
902 self.valid_modes = ['Plain','Context','Verbose']
902 self.valid_modes = ['Plain','Context','Verbose']
903 self.verbose_modes = self.valid_modes[1:3]
903 self.verbose_modes = self.valid_modes[1:3]
904
904
905 VerboseTB.__init__(self,color_scheme,tb_offset,long_header,
905 VerboseTB.__init__(self,color_scheme,tb_offset,long_header,
906 call_pdb=call_pdb,include_vars=include_vars)
906 call_pdb=call_pdb,include_vars=include_vars)
907 self.set_mode(mode)
907 self.set_mode(mode)
908
908
909 def _extract_tb(self,tb):
909 def _extract_tb(self,tb):
910 if tb:
910 if tb:
911 return traceback.extract_tb(tb)
911 return traceback.extract_tb(tb)
912 else:
912 else:
913 return None
913 return None
914
914
915 def text(self, etype, value, tb,context=5,mode=None):
915 def text(self, etype, value, tb,context=5,mode=None):
916 """Return formatted traceback.
916 """Return formatted traceback.
917
917
918 If the optional mode parameter is given, it overrides the current
918 If the optional mode parameter is given, it overrides the current
919 mode."""
919 mode."""
920
920
921 if mode is None:
921 if mode is None:
922 mode = self.mode
922 mode = self.mode
923 if mode in self.verbose_modes:
923 if mode in self.verbose_modes:
924 # verbose modes need a full traceback
924 # verbose modes need a full traceback
925 return VerboseTB.text(self,etype, value, tb,context=5)
925 return VerboseTB.text(self,etype, value, tb,context=5)
926 else:
926 else:
927 # We must check the source cache because otherwise we can print
927 # We must check the source cache because otherwise we can print
928 # out-of-date source code.
928 # out-of-date source code.
929 linecache.checkcache()
929 linecache.checkcache()
930 # Now we can extract and format the exception
930 # Now we can extract and format the exception
931 elist = self._extract_tb(tb)
931 elist = self._extract_tb(tb)
932 if len(elist) > self.tb_offset:
932 if len(elist) > self.tb_offset:
933 del elist[:self.tb_offset]
933 del elist[:self.tb_offset]
934 return ListTB.text(self,etype,value,elist)
934 return ListTB.text(self,etype,value,elist)
935
935
936 def set_mode(self,mode=None):
936 def set_mode(self,mode=None):
937 """Switch to the desired mode.
937 """Switch to the desired mode.
938
938
939 If mode is not specified, cycles through the available modes."""
939 If mode is not specified, cycles through the available modes."""
940
940
941 if not mode:
941 if not mode:
942 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
942 new_idx = ( self.valid_modes.index(self.mode) + 1 ) % \
943 len(self.valid_modes)
943 len(self.valid_modes)
944 self.mode = self.valid_modes[new_idx]
944 self.mode = self.valid_modes[new_idx]
945 elif mode not in self.valid_modes:
945 elif mode not in self.valid_modes:
946 raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
946 raise ValueError, 'Unrecognized mode in FormattedTB: <'+mode+'>\n'\
947 'Valid modes: '+str(self.valid_modes)
947 'Valid modes: '+str(self.valid_modes)
948 else:
948 else:
949 self.mode = mode
949 self.mode = mode
950 # include variable details only in 'Verbose' mode
950 # include variable details only in 'Verbose' mode
951 self.include_vars = (self.mode == self.valid_modes[2])
951 self.include_vars = (self.mode == self.valid_modes[2])
952
952
953 # some convenient shorcuts
953 # some convenient shorcuts
954 def plain(self):
954 def plain(self):
955 self.set_mode(self.valid_modes[0])
955 self.set_mode(self.valid_modes[0])
956
956
957 def context(self):
957 def context(self):
958 self.set_mode(self.valid_modes[1])
958 self.set_mode(self.valid_modes[1])
959
959
960 def verbose(self):
960 def verbose(self):
961 self.set_mode(self.valid_modes[2])
961 self.set_mode(self.valid_modes[2])
962
962
963 #----------------------------------------------------------------------------
963 #----------------------------------------------------------------------------
964 class AutoFormattedTB(FormattedTB):
964 class AutoFormattedTB(FormattedTB):
965 """A traceback printer which can be called on the fly.
965 """A traceback printer which can be called on the fly.
966
966
967 It will find out about exceptions by itself.
967 It will find out about exceptions by itself.
968
968
969 A brief example:
969 A brief example:
970
970
971 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
971 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
972 try:
972 try:
973 ...
973 ...
974 except:
974 except:
975 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
975 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
976 """
976 """
977 def __call__(self,etype=None,evalue=None,etb=None,
977 def __call__(self,etype=None,evalue=None,etb=None,
978 out=None,tb_offset=None):
978 out=None,tb_offset=None):
979 """Print out a formatted exception traceback.
979 """Print out a formatted exception traceback.
980
980
981 Optional arguments:
981 Optional arguments:
982 - out: an open file-like object to direct output to.
982 - out: an open file-like object to direct output to.
983
983
984 - tb_offset: the number of frames to skip over in the stack, on a
984 - tb_offset: the number of frames to skip over in the stack, on a
985 per-call basis (this overrides temporarily the instance's tb_offset
985 per-call basis (this overrides temporarily the instance's tb_offset
986 given at initialization time. """
986 given at initialization time. """
987
987
988 if out is None:
988 if out is None:
989 out = Term.cerr
989 out = Term.cerr
990 Term.cout.flush()
990 Term.cout.flush()
991 if tb_offset is not None:
991 if tb_offset is not None:
992 tb_offset, self.tb_offset = self.tb_offset, tb_offset
992 tb_offset, self.tb_offset = self.tb_offset, tb_offset
993 print >> out, self.text(etype, evalue, etb)
993 print >> out, self.text(etype, evalue, etb)
994 self.tb_offset = tb_offset
994 self.tb_offset = tb_offset
995 else:
995 else:
996 print >> out, self.text(etype, evalue, etb)
996 print >> out, self.text(etype, evalue, etb)
997 out.flush()
997 out.flush()
998 try:
998 try:
999 self.debugger()
999 self.debugger()
1000 except KeyboardInterrupt:
1000 except KeyboardInterrupt:
1001 print "\nKeyboardInterrupt"
1001 print "\nKeyboardInterrupt"
1002
1002
1003 def text(self,etype=None,value=None,tb=None,context=5,mode=None):
1003 def text(self,etype=None,value=None,tb=None,context=5,mode=None):
1004 if etype is None:
1004 if etype is None:
1005 etype,value,tb = sys.exc_info()
1005 etype,value,tb = sys.exc_info()
1006 self.tb = tb
1006 self.tb = tb
1007 return FormattedTB.text(self,etype,value,tb,context=5,mode=mode)
1007 return FormattedTB.text(self,etype,value,tb,context=5,mode=mode)
1008
1008
1009 #---------------------------------------------------------------------------
1009 #---------------------------------------------------------------------------
1010 # A simple class to preserve Nathan's original functionality.
1010 # A simple class to preserve Nathan's original functionality.
1011 class ColorTB(FormattedTB):
1011 class ColorTB(FormattedTB):
1012 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1012 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1013 def __init__(self,color_scheme='Linux',call_pdb=0):
1013 def __init__(self,color_scheme='Linux',call_pdb=0):
1014 FormattedTB.__init__(self,color_scheme=color_scheme,
1014 FormattedTB.__init__(self,color_scheme=color_scheme,
1015 call_pdb=call_pdb)
1015 call_pdb=call_pdb)
1016
1016
1017 #----------------------------------------------------------------------------
1017 #----------------------------------------------------------------------------
1018 # module testing (minimal)
1018 # module testing (minimal)
1019 if __name__ == "__main__":
1019 if __name__ == "__main__":
1020 def spam(c, (d, e)):
1020 def spam(c, (d, e)):
1021 x = c + d
1021 x = c + d
1022 y = c * d
1022 y = c * d
1023 foo(x, y)
1023 foo(x, y)
1024
1024
1025 def foo(a, b, bar=1):
1025 def foo(a, b, bar=1):
1026 eggs(a, b + bar)
1026 eggs(a, b + bar)
1027
1027
1028 def eggs(f, g, z=globals()):
1028 def eggs(f, g, z=globals()):
1029 h = f + g
1029 h = f + g
1030 i = f - g
1030 i = f - g
1031 return h / i
1031 return h / i
1032
1032
1033 print ''
1033 print ''
1034 print '*** Before ***'
1034 print '*** Before ***'
1035 try:
1035 try:
1036 print spam(1, (2, 3))
1036 print spam(1, (2, 3))
1037 except:
1037 except:
1038 traceback.print_exc()
1038 traceback.print_exc()
1039 print ''
1039 print ''
1040
1040
1041 handler = ColorTB()
1041 handler = ColorTB()
1042 print '*** ColorTB ***'
1042 print '*** ColorTB ***'
1043 try:
1043 try:
1044 print spam(1, (2, 3))
1044 print spam(1, (2, 3))
1045 except:
1045 except:
1046 apply(handler, sys.exc_info() )
1046 apply(handler, sys.exc_info() )
1047 print ''
1047 print ''
1048
1048
1049 handler = VerboseTB()
1049 handler = VerboseTB()
1050 print '*** VerboseTB ***'
1050 print '*** VerboseTB ***'
1051 try:
1051 try:
1052 print spam(1, (2, 3))
1052 print spam(1, (2, 3))
1053 except:
1053 except:
1054 apply(handler, sys.exc_info() )
1054 apply(handler, sys.exc_info() )
1055 print ''
1055 print ''
1056
1056
General Comments 0
You need to be logged in to leave comments. Login now