##// END OF EJS Templates
Lots of work on exception handling, including tests for traceback printing....
Fernando Perez -
Show More
@@ -0,0 +1,32 b''
1 """Error script. DO NOT EDIT FURTHER! It will break exception doctests!!!"""
2 import sys
3
4 def div0():
5 "foo"
6 x = 1
7 y = 0
8 x/y
9
10 def sysexit(stat, mode):
11 raise SystemExit(stat, 'Mode = %s' % mode)
12
13 def bar(mode):
14 "bar"
15 if mode=='div':
16 div0()
17 elif mode=='exit':
18 try:
19 stat = int(sys.argv[2])
20 except:
21 stat = 1
22 sysexit(stat, mode)
23 else:
24 raise ValueError('Unknown mode')
25
26 if __name__ == '__main__':
27 try:
28 mode = sys.argv[1]
29 except IndexError:
30 mode = 'div'
31
32 bar(mode)
@@ -1243,7 +1243,8 b' class InteractiveShell(Component, Magic):'
1243 1243 """
1244 1244 self.showtraceback((etype,value,tb),tb_offset=0)
1245 1245
1246 def showtraceback(self,exc_tuple = None,filename=None,tb_offset=None):
1246 def showtraceback(self,exc_tuple = None,filename=None,tb_offset=None,
1247 exception_only=False):
1247 1248 """Display the exception that just occurred.
1248 1249
1249 1250 If nothing is known about the exception, this is the method which
@@ -1255,17 +1256,23 b' class InteractiveShell(Component, Magic):'
1255 1256 SyntaxError exception, don't try to analyze the stack manually and
1256 1257 simply call this method."""
1257 1258
1258
1259 # Though this won't be called by syntax errors in the input line,
1260 # there may be SyntaxError cases whith imported code.
1261
1262 1259 try:
1263 1260 if exc_tuple is None:
1264 1261 etype, value, tb = sys.exc_info()
1265 1262 else:
1266 1263 etype, value, tb = exc_tuple
1267 1264
1265 if etype is None:
1266 if hasattr(sys, 'last_type'):
1267 etype, value, tb = sys.last_type, sys.last_value, \
1268 sys.last_traceback
1269 else:
1270 self.write('No traceback available to show.\n')
1271 return
1272
1268 1273 if etype is SyntaxError:
1274 # Though this won't be called by syntax errors in the input
1275 # line, there may be SyntaxError cases whith imported code.
1269 1276 self.showsyntaxerror(filename)
1270 1277 elif etype is UsageError:
1271 1278 print "UsageError:", value
@@ -1281,13 +1288,21 b' class InteractiveShell(Component, Magic):'
1281 1288 if etype in self.custom_exceptions:
1282 1289 self.CustomTB(etype,value,tb)
1283 1290 else:
1291 if exception_only:
1292 m = ('An exception has occurred, use %tb to see the '
1293 'full traceback.')
1294 print m
1295 self.InteractiveTB.show_exception_only(etype, value)
1296 else:
1284 1297 self.InteractiveTB(etype,value,tb,tb_offset=tb_offset)
1285 1298 if self.InteractiveTB.call_pdb:
1286 1299 # pdb mucks up readline, fix it back
1287 1300 self.set_completer()
1301
1288 1302 except KeyboardInterrupt:
1289 1303 self.write("\nKeyboardInterrupt\n")
1290 1304
1305
1291 1306 def showsyntaxerror(self, filename=None):
1292 1307 """Display the syntax error that just occurred.
1293 1308
@@ -1299,7 +1314,7 b' class InteractiveShell(Component, Magic):'
1299 1314 """
1300 1315 etype, value, last_traceback = sys.exc_info()
1301 1316
1302 # See note about these variables in showtraceback() below
1317 # See note about these variables in showtraceback() above
1303 1318 sys.last_type = etype
1304 1319 sys.last_value = value
1305 1320 sys.last_traceback = last_traceback
@@ -1865,6 +1880,9 b' class InteractiveShell(Component, Magic):'
1865 1880 # We are off again...
1866 1881 __builtin__.__dict__['__IPYTHON__active'] -= 1
1867 1882
1883 # Turn off the exit flag, so the mainloop can be restarted if desired
1884 self.exit_now = False
1885
1868 1886 def safe_execfile(self, fname, *where, **kw):
1869 1887 """A safe version of the builtin execfile().
1870 1888
@@ -1880,7 +1898,8 b' class InteractiveShell(Component, Magic):'
1880 1898 One or two namespaces, passed to execfile() as (globals,locals).
1881 1899 If only one is given, it is passed as both.
1882 1900 exit_ignore : bool (False)
1883 If True, then don't print errors for non-zero exit statuses.
1901 If True, then silence SystemExit for non-zero status (it is always
1902 silenced for zero status, as it is so common).
1884 1903 """
1885 1904 kw.setdefault('exit_ignore', False)
1886 1905
@@ -1905,40 +1924,21 b' class InteractiveShell(Component, Magic):'
1905 1924
1906 1925 with prepended_to_syspath(dname):
1907 1926 try:
1908 if sys.platform == 'win32' and sys.version_info < (2,5,1):
1909 # Work around a bug in Python for Windows. The bug was
1910 # fixed in in Python 2.5 r54159 and 54158, but that's still
1911 # SVN Python as of March/07. For details, see:
1912 # http://projects.scipy.org/ipython/ipython/ticket/123
1913 try:
1914 globs,locs = where[0:2]
1915 except:
1916 try:
1917 globs = locs = where[0]
1918 except:
1919 globs = locs = globals()
1920 exec file(fname) in globs,locs
1921 else:
1922 1927 execfile(fname,*where)
1923 except SyntaxError:
1924 self.showsyntaxerror()
1925 warn('Failure executing file: <%s>' % fname)
1926 1928 except SystemExit, status:
1927 # Code that correctly sets the exit status flag to success (0)
1928 # shouldn't be bothered with a traceback. Note that a plain
1929 # sys.exit() does NOT set the message to 0 (it's empty) so that
1930 # will still get a traceback. Note that the structure of the
1931 # SystemExit exception changed between Python 2.4 and 2.5, so
1932 # the checks must be done in a version-dependent way.
1933 show = False
1934 if status.args[0]==0 and not kw['exit_ignore']:
1935 show = True
1936 if show:
1937 self.showtraceback()
1938 warn('Failure executing file: <%s>' % fname)
1929 # If the call was made with 0 or None exit status (sys.exit(0)
1930 # or sys.exit() ), don't bother showing a traceback, as both of
1931 # these are considered normal by the OS:
1932 # > python -c'import sys;sys.exit(0)'; echo $?
1933 # 0
1934 # > python -c'import sys;sys.exit()'; echo $?
1935 # 0
1936 # For other exit status, we show the exception unless
1937 # explicitly silenced, but only in short form.
1938 if status.code not in (0, None) and not kw['exit_ignore']:
1939 self.showtraceback(exception_only=True)
1939 1940 except:
1940 1941 self.showtraceback()
1941 warn('Failure executing file: <%s>' % fname)
1942 1942
1943 1943 def safe_execfile_ipy(self, fname):
1944 1944 """Like safe_execfile, but for .ipy files with IPython syntax.
@@ -2152,9 +2152,8 b' class InteractiveShell(Component, Magic):'
2152 2152 sys.excepthook = old_excepthook
2153 2153 except SystemExit:
2154 2154 self.resetbuffer()
2155 self.showtraceback()
2156 warn("Type %exit or %quit to exit IPython "
2157 "(%Exit or %Quit do so unconditionally).",level=1)
2155 self.showtraceback(exception_only=True)
2156 warn("To exit: use any of 'exit', 'quit', %Exit or Ctrl-D.", level=1)
2158 2157 except self.custom_exceptions:
2159 2158 etype,value,tb = sys.exc_info()
2160 2159 self.CustomTB(etype,value,tb)
@@ -3603,4 +3603,10 b' Defaulting color scheme to \'NoColor\'"""'
3603 3603 """
3604 3604 self.shell.enable_pylab(s)
3605 3605
3606 def magic_tb(self, s):
3607 """Print the last traceback with the currently active exception mode.
3608
3609 See %xmode for changing exception reporting modes."""
3610 self.shell.showtraceback()
3611
3606 3612 # end Magic
@@ -13,31 +13,15 b' import tempfile'
13 13 import nose.tools as nt
14 14
15 15 # our own packages
16 from IPython.core import iplib
17 from IPython.core import ipapi
18 16 from IPython.testing import decorators as dec
17 from IPython.testing.globalipapp import get_ipython
19 18
20 19 #-----------------------------------------------------------------------------
21 20 # Globals
22 21 #-----------------------------------------------------------------------------
23 22
24 # Useful global ipapi object and main IPython one. Unfortunately we have a
25 # long precedent of carrying the 'ipapi' global object which is injected into
26 # the system namespace as _ip, but that keeps a pointer to the actual IPython
27 # InteractiveShell instance, which is named IP. Since in testing we do need
28 # access to the real thing (we want to probe beyond what ipapi exposes), make
29 # here a global reference to each. In general, things that are exposed by the
30 # ipapi instance should be read from there, but we also will often need to use
31 # the actual IPython one.
32
33 # Get the public instance of IPython, and if it's None, make one so we can use
34 # it for testing
35 ip = ipapi.get()
36 if ip is None:
37 # IPython not running yet, make one from the testing machinery for
38 # consistency when the test suite is being run via iptest
39 from IPython.testing.plugin import ipdoctest
40 ip = ipapi.get()
23 # Get the public instance of IPython
24 ip = get_ipython()
41 25
42 26 #-----------------------------------------------------------------------------
43 27 # Test functions
@@ -73,3 +57,189 b' def test_reset():'
73 57 nvars_expected = 0
74 58
75 59 yield nt.assert_equals(len(ns), nvars_expected)
60
61
62 # Tests for reporting of exceptions in various modes, handling of SystemExit,
63 # and %tb functionality. This is really a mix of testing ultraTB and iplib.
64
65 def doctest_tb_plain():
66 """
67 In [18]: xmode plain
68 Exception reporting mode: Plain
69
70 In [19]: run simpleerr.py
71 Traceback (most recent call last):
72 ...line 32, in <module>
73 bar(mode)
74 ...line 16, in bar
75 div0()
76 ...line 8, in div0
77 x/y
78 ZeroDivisionError: integer division or modulo by zero
79 """
80
81
82 def doctest_tb_context():
83 """
84 In [3]: xmode context
85 Exception reporting mode: Context
86
87 In [4]: run simpleerr.py
88 ---------------------------------------------------------------------------
89 ZeroDivisionError Traceback (most recent call last)
90 <BLANKLINE>
91 ... in <module>()
92 30 mode = 'div'
93 31
94 ---> 32 bar(mode)
95 33
96 34
97 <BLANKLINE>
98 ... in bar(mode)
99 14 "bar"
100 15 if mode=='div':
101 ---> 16 div0()
102 17 elif mode=='exit':
103 18 try:
104 <BLANKLINE>
105 ... in div0()
106 6 x = 1
107 7 y = 0
108 ----> 8 x/y
109 9
110 10 def sysexit(stat, mode):
111 <BLANKLINE>
112 ZeroDivisionError: integer division or modulo by zero
113 """
114
115
116 def doctest_tb_verbose():
117 """
118 In [5]: xmode verbose
119 Exception reporting mode: Verbose
120
121 In [6]: run simpleerr.py
122 ---------------------------------------------------------------------------
123 ZeroDivisionError Traceback (most recent call last)
124 <BLANKLINE>
125 ... in <module>()
126 30 mode = 'div'
127 31
128 ---> 32 bar(mode)
129 global bar = <function bar at ...>
130 global mode = 'div'
131 33
132 34
133 <BLANKLINE>
134 ... in bar(mode='div')
135 14 "bar"
136 15 if mode=='div':
137 ---> 16 div0()
138 global div0 = <function div0 at ...>
139 17 elif mode=='exit':
140 18 try:
141 <BLANKLINE>
142 ... in div0()
143 6 x = 1
144 7 y = 0
145 ----> 8 x/y
146 x = 1
147 y = 0
148 9
149 10 def sysexit(stat, mode):
150 <BLANKLINE>
151 ZeroDivisionError: integer division or modulo by zero
152 """
153
154
155 def doctest_tb_sysexit():
156 """
157 In [17]: %xmode plain
158 Exception reporting mode: Plain
159
160 In [18]: %run simpleerr.py exit
161 An exception has occurred, use %tb to see the full traceback.
162 SystemExit: (1, 'Mode = exit')
163
164 In [19]: %run simpleerr.py exit 2
165 An exception has occurred, use %tb to see the full traceback.
166 SystemExit: (2, 'Mode = exit')
167
168 In [20]: %tb
169 Traceback (most recent call last):
170 File ... in <module>
171 bar(mode)
172 File ... line 22, in bar
173 sysexit(stat, mode)
174 File ... line 11, in sysexit
175 raise SystemExit(stat, 'Mode = %s' % mode)
176 SystemExit: (2, 'Mode = exit')
177
178 In [21]: %xmode context
179 Exception reporting mode: Context
180
181 In [22]: %tb
182 ---------------------------------------------------------------------------
183 SystemExit Traceback (most recent call last)
184 <BLANKLINE>
185 ...<module>()
186 30 mode = 'div'
187 31
188 ---> 32 bar(mode)
189 33
190 34
191 <BLANKLINE>
192 ...bar(mode)
193 20 except:
194 21 stat = 1
195 ---> 22 sysexit(stat, mode)
196 23 else:
197 24 raise ValueError('Unknown mode')
198 <BLANKLINE>
199 ...sysexit(stat, mode)
200 9
201 10 def sysexit(stat, mode):
202 ---> 11 raise SystemExit(stat, 'Mode = %s' % mode)
203 12
204 13 def bar(mode):
205 <BLANKLINE>
206 SystemExit: (2, 'Mode = exit')
207
208 In [23]: %xmode verbose
209 Exception reporting mode: Verbose
210
211 In [24]: %tb
212 ---------------------------------------------------------------------------
213 SystemExit Traceback (most recent call last)
214 <BLANKLINE>
215 ... in <module>()
216 30 mode = 'div'
217 31
218 ---> 32 bar(mode)
219 global bar = <function bar at ...>
220 global mode = 'exit'
221 33
222 34
223 <BLANKLINE>
224 ... in bar(mode='exit')
225 20 except:
226 21 stat = 1
227 ---> 22 sysexit(stat, mode)
228 global sysexit = <function sysexit at ...>
229 stat = 2
230 mode = 'exit'
231 23 else:
232 24 raise ValueError('Unknown mode')
233 <BLANKLINE>
234 ... in sysexit(stat=2, mode='exit')
235 9
236 10 def sysexit(stat, mode):
237 ---> 11 raise SystemExit(stat, 'Mode = %s' % mode)
238 global SystemExit = undefined
239 stat = 2
240 mode = 'exit'
241 12
242 13 def bar(mode):
243 <BLANKLINE>
244 SystemExit: (2, 'Mode = exit')
245 """
@@ -312,6 +312,11 b' def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):'
312 312 # Module classes
313 313 class TBTools:
314 314 """Basic tools used by all traceback printer classes."""
315 #: Default output stream, can be overridden at call time. A special value
316 #: of 'stdout' *as a string* can be given to force extraction of sys.stdout
317 #: at runtime. This allows testing exception printing with doctests, that
318 #: swap sys.stdout just at execution time.
319 out_stream = sys.stderr
315 320
316 321 def __init__(self,color_scheme = 'NoColor',call_pdb=False):
317 322 # Whether to call the interactive pdb debugger after printing
@@ -380,12 +385,28 b' class ListTB(TBTools):'
380 385 Term.cerr.flush()
381 386
382 387 def text(self,etype, value, elist,context=5):
383 """Return a color formatted string with the traceback info."""
388 """Return a color formatted string with the traceback info.
389
390 Parameters
391 ----------
392 etype : exception type
393 Type of the exception raised.
394
395 value : object
396 Data stored in the exception
397
398 elist : list
399 List of frames, see class docstring for details.
400
401 Returns
402 -------
403 String with formatted exception.
404 """
384 405
385 406 Colors = self.Colors
386 out_string = ['%s%s%s\n' % (Colors.topline,'-'*60,Colors.Normal)]
407 out_string = []
387 408 if elist:
388 out_string.append('Traceback %s(most recent call last)%s:' % \
409 out_string.append('Traceback %s(most recent call last)%s:' %
389 410 (Colors.normalEm, Colors.Normal) + '\n')
390 411 out_string.extend(self._format_list(elist))
391 412 lines = self._format_exception_only(etype, value)
@@ -492,15 +513,29 b' class ListTB(TBTools):'
492 513 else:
493 514 list.append('%s\n' % str(stype))
494 515
495 # vds:>>
516 # sync with user hooks
496 517 if have_filedata:
497 518 ipinst = ipapi.get()
498 519 if ipinst is not None:
499 520 ipinst.hooks.synchronize_with_editor(filename, lineno, 0)
500 # vds:<<
501 521
502 522 return list
503 523
524 def show_exception_only(self, etype, value):
525 """Only print the exception type and message, without a traceback.
526
527 Parameters
528 ----------
529 etype : exception type
530 value : exception value
531 """
532 # This method needs to use __call__ from *this* class, not the one from
533 # a subclass whose signature or behavior may be different
534 Term.cout.flush()
535 ostream = sys.stdout if self.out_stream == 'stdout' else Term.cerr
536 print >> ostream, ListTB.text(self, etype, value, []),
537 ostream.flush()
538
504 539 def _some_str(self, value):
505 540 # Lifted from traceback.py
506 541 try:
@@ -980,6 +1015,7 b' class AutoFormattedTB(FormattedTB):'
980 1015 except:
981 1016 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
982 1017 """
1018
983 1019 def __call__(self,etype=None,evalue=None,etb=None,
984 1020 out=None,tb_offset=None):
985 1021 """Print out a formatted exception traceback.
@@ -992,7 +1028,7 b' class AutoFormattedTB(FormattedTB):'
992 1028 given at initialization time. """
993 1029
994 1030 if out is None:
995 out = Term.cerr
1031 out = sys.stdout if self.out_stream=='stdout' else self.out_stream
996 1032 Term.cout.flush()
997 1033 if tb_offset is not None:
998 1034 tb_offset, self.tb_offset = self.tb_offset, tb_offset
@@ -20,6 +20,7 b' import os'
20 20 import sys
21 21
22 22 from . import tools
23 from IPython.utils.genutils import Term
23 24
24 25 #-----------------------------------------------------------------------------
25 26 # Functions
@@ -96,7 +97,7 b' class ipnsdict(dict):'
96 97
97 98 def get_ipython():
98 99 # This will get replaced by the real thing once we start IPython below
99 return None
100 return start_ipython()
100 101
101 102 def start_ipython():
102 103 """Start a global IPython shell, which we need for IPython-specific syntax.
@@ -133,6 +134,10 b' def start_ipython():'
133 134 ip = ipapp.IPythonApp(argv, user_ns=user_ns, user_global_ns=global_ns)
134 135 ip.initialize()
135 136 ip.shell.builtin_trap.set()
137 # Set stderr to stdout so nose can doctest exceptions
138 ## Term.cerr = sys.stdout
139 ## sys.stderr = sys.stdout
140 ip.shell.InteractiveTB.out_stream = 'stdout'
136 141 # Butcher the logger
137 142 ip.shell.log = lambda *a,**k: None
138 143
@@ -143,8 +148,8 b' def start_ipython():'
143 148 sys.excepthook = _excepthook
144 149
145 150 # So that ipython magics and aliases can be doctested (they work by making
146 # a call into a global _ip object)
147
151 # a call into a global _ip object). Also make the top-level get_ipython
152 # now return this without calling here again
148 153 _ip = ip.shell
149 154 get_ipython = _ip.get_ipython
150 155 __builtin__._ip = _ip
@@ -155,11 +160,6 b' def start_ipython():'
155 160 # doctest machinery would miss them.
156 161 ip.shell.system = xsys
157 162
158 # Also patch our %run function in.
159 ## im = new.instancemethod(_run_ns_sync,_ip, _ip.__class__)
160 ## ip.shell.magic_run_ori = _ip.magic_run
161 ## ip.shell.magic_run = im
162
163 163 # XXX - For some very bizarre reason, the loading of %history by default is
164 164 # failing. This needs to be fixed later, but for now at least this ensures
165 165 # that tests that use %hist run to completion.
@@ -167,3 +167,5 b' def start_ipython():'
167 167 history.init_ipython(ip.shell)
168 168 if not hasattr(ip.shell,'magic_history'):
169 169 raise RuntimeError("Can't load magics, aborting")
170
171 return _ip
General Comments 0
You need to be logged in to leave comments. Login now