##// END OF EJS Templates
Improvements to exception handling to transport structured tracebacks....
Fernando Perez -
r2838:cbe60016
parent child
Show More
@@ -29,6 +29,7 import sys
29 import tempfile
29 import tempfile
30 from contextlib import nested
30 from contextlib import nested
31
31
32 from IPython.config.configurable import Configurable
32 from IPython.core import debugger, oinspect
33 from IPython.core import debugger, oinspect
33 from IPython.core import history as ipcorehist
34 from IPython.core import history as ipcorehist
34 from IPython.core import prefilter
35 from IPython.core import prefilter
@@ -36,8 +37,8 from IPython.core import shadowns
36 from IPython.core import ultratb
37 from IPython.core import ultratb
37 from IPython.core.alias import AliasManager
38 from IPython.core.alias import AliasManager
38 from IPython.core.builtin_trap import BuiltinTrap
39 from IPython.core.builtin_trap import BuiltinTrap
39 from IPython.config.configurable import Configurable
40 from IPython.core.display_trap import DisplayTrap
40 from IPython.core.display_trap import DisplayTrap
41 from IPython.core.displayhook import DisplayHook
41 from IPython.core.error import UsageError
42 from IPython.core.error import UsageError
42 from IPython.core.extensions import ExtensionManager
43 from IPython.core.extensions import ExtensionManager
43 from IPython.core.fakemodule import FakeModule, init_fakemod_dict
44 from IPython.core.fakemodule import FakeModule, init_fakemod_dict
@@ -47,24 +48,22 from IPython.core.magic import Magic
47 from IPython.core.payload import PayloadManager
48 from IPython.core.payload import PayloadManager
48 from IPython.core.plugin import PluginManager
49 from IPython.core.plugin import PluginManager
49 from IPython.core.prefilter import PrefilterManager
50 from IPython.core.prefilter import PrefilterManager
50 from IPython.core.displayhook import DisplayHook
51 import IPython.core.hooks
52 from IPython.external.Itpl import ItplNS
51 from IPython.external.Itpl import ItplNS
53 from IPython.utils import PyColorize
52 from IPython.utils import PyColorize
53 from IPython.utils import io
54 from IPython.utils import pickleshare
54 from IPython.utils import pickleshare
55 from IPython.utils.doctestreload import doctest_reload
55 from IPython.utils.doctestreload import doctest_reload
56 from IPython.utils.io import ask_yes_no, rprint
56 from IPython.utils.ipstruct import Struct
57 from IPython.utils.ipstruct import Struct
57 import IPython.utils.io
58 from IPython.utils.io import ask_yes_no
59 from IPython.utils.path import get_home_dir, get_ipython_dir, HomeDirError
58 from IPython.utils.path import get_home_dir, get_ipython_dir, HomeDirError
60 from IPython.utils.process import getoutput, getoutputerror
59 from IPython.utils.process import getoutput, getoutputerror
61 from IPython.utils.strdispatch import StrDispatch
60 from IPython.utils.strdispatch import StrDispatch
62 from IPython.utils.syspathcontext import prepended_to_syspath
61 from IPython.utils.syspathcontext import prepended_to_syspath
63 from IPython.utils.text import num_ini_spaces
62 from IPython.utils.text import num_ini_spaces
63 from IPython.utils.traitlets import (Int, Str, CBool, CaselessStrEnum, Enum,
64 List, Unicode, Instance, Type)
64 from IPython.utils.warn import warn, error, fatal
65 from IPython.utils.warn import warn, error, fatal
65 from IPython.utils.traitlets import (
66 import IPython.core.hooks
66 Int, Str, CBool, CaselessStrEnum, Enum, List, Unicode, Instance, Type
67 )
68
67
69 # from IPython.utils import growl
68 # from IPython.utils import growl
70 # growl.start("IPython")
69 # growl.start("IPython")
@@ -430,12 +429,12 class InteractiveShell(Configurable, Magic):
430 def init_io(self):
429 def init_io(self):
431 import IPython.utils.io
430 import IPython.utils.io
432 if sys.platform == 'win32' and self.has_readline:
431 if sys.platform == 'win32' and self.has_readline:
433 Term = IPython.utils.io.IOTerm(
432 Term = io.IOTerm(
434 cout=self.readline._outputfile,cerr=self.readline._outputfile
433 cout=self.readline._outputfile,cerr=self.readline._outputfile
435 )
434 )
436 else:
435 else:
437 Term = IPython.utils.io.IOTerm()
436 Term = io.IOTerm()
438 IPython.utils.io.Term = Term
437 io.Term = Term
439
438
440 def init_prompts(self):
439 def init_prompts(self):
441 # TODO: This is a pass for now because the prompts are managed inside
440 # TODO: This is a pass for now because the prompts are managed inside
@@ -1181,7 +1180,7 class InteractiveShell(Configurable, Magic):
1181 # Set the exception mode
1180 # Set the exception mode
1182 self.InteractiveTB.set_mode(mode=self.xmode)
1181 self.InteractiveTB.set_mode(mode=self.xmode)
1183
1182
1184 def set_custom_exc(self,exc_tuple,handler):
1183 def set_custom_exc(self, exc_tuple, handler):
1185 """set_custom_exc(exc_tuple,handler)
1184 """set_custom_exc(exc_tuple,handler)
1186
1185
1187 Set a custom exception handler, which will be called if any of the
1186 Set a custom exception handler, which will be called if any of the
@@ -1198,7 +1197,12 class InteractiveShell(Configurable, Magic):
1198 exc_tuple == (MyCustomException,)
1197 exc_tuple == (MyCustomException,)
1199
1198
1200 - handler: this must be defined as a function with the following
1199 - handler: this must be defined as a function with the following
1201 basic interface: def my_handler(self,etype,value,tb).
1200 basic interface::
1201
1202 def my_handler(self, etype, value, tb, tb_offset=None)
1203 ...
1204 # The return value must be
1205 return structured_traceback
1202
1206
1203 This will be made into an instance method (via new.instancemethod)
1207 This will be made into an instance method (via new.instancemethod)
1204 of IPython itself, and it will be called if any of the exceptions
1208 of IPython itself, and it will be called if any of the exceptions
@@ -1272,7 +1276,7 class InteractiveShell(Configurable, Magic):
1272 etype, value, tb = sys.last_type, sys.last_value, \
1276 etype, value, tb = sys.last_type, sys.last_value, \
1273 sys.last_traceback
1277 sys.last_traceback
1274 else:
1278 else:
1275 self.write('No traceback available to show.\n')
1279 self.write_err('No traceback available to show.\n')
1276 return
1280 return
1277
1281
1278 if etype is SyntaxError:
1282 if etype is SyntaxError:
@@ -1291,22 +1295,39 class InteractiveShell(Configurable, Magic):
1291 sys.last_traceback = tb
1295 sys.last_traceback = tb
1292
1296
1293 if etype in self.custom_exceptions:
1297 if etype in self.custom_exceptions:
1294 self.CustomTB(etype,value,tb)
1298 # FIXME: Old custom traceback objects may just return a
1299 # string, in that case we just put it into a list
1300 stb = self.CustomTB(etype, value, tb, tb_offset)
1301 if isinstance(ctb, basestring):
1302 stb = [stb]
1295 else:
1303 else:
1296 if exception_only:
1304 if exception_only:
1297 m = ('An exception has occurred, use %tb to see the '
1305 stb = ['An exception has occurred, use %tb to see '
1298 'full traceback.')
1306 'the full traceback.']
1299 print m
1307 stb.extend(self.InteractiveTB.get_exception_only(etype,
1300 self.InteractiveTB.show_exception_only(etype, value)
1308 value))
1301 else:
1309 else:
1302 self.InteractiveTB(etype,value,tb,tb_offset=tb_offset)
1310 stb = self.InteractiveTB.structured_traceback(etype,
1311 value, tb, tb_offset=tb_offset)
1312 # FIXME: the pdb calling should be done by us, not by
1313 # the code computing the traceback.
1303 if self.InteractiveTB.call_pdb:
1314 if self.InteractiveTB.call_pdb:
1304 # pdb mucks up readline, fix it back
1315 # pdb mucks up readline, fix it back
1305 self.set_completer()
1316 self.set_completer()
1306
1317
1318 # Actually show the traceback
1319 self._showtraceback(etype, value, stb)
1320
1307 except KeyboardInterrupt:
1321 except KeyboardInterrupt:
1308 self.write("\nKeyboardInterrupt\n")
1322 self.write_err("\nKeyboardInterrupt\n")
1309
1323
1324 def _showtraceback(self, etype, evalue, stb):
1325 """Actually show a traceback.
1326
1327 Subclasses may override this method to put the traceback on a different
1328 place, like a side channel.
1329 """
1330 self.write_err('\n'.join(stb))
1310
1331
1311 def showsyntaxerror(self, filename=None):
1332 def showsyntaxerror(self, filename=None):
1312 """Display the syntax error that just occurred.
1333 """Display the syntax error that just occurred.
@@ -1339,7 +1360,8 class InteractiveShell(Configurable, Magic):
1339 except:
1360 except:
1340 # If that failed, assume SyntaxError is a string
1361 # If that failed, assume SyntaxError is a string
1341 value = msg, (filename, lineno, offset, line)
1362 value = msg, (filename, lineno, offset, line)
1342 self.SyntaxTB(etype,value,[])
1363 stb = self.SyntaxTB.structured_traceback(etype, value, [])
1364 self._showtraceback(etype, value, stb)
1343
1365
1344 #-------------------------------------------------------------------------
1366 #-------------------------------------------------------------------------
1345 # Things related to tab completion
1367 # Things related to tab completion
@@ -1792,7 +1814,7 class InteractiveShell(Configurable, Magic):
1792 exposes IPython's processing machinery, the given strings can contain
1814 exposes IPython's processing machinery, the given strings can contain
1793 magic calls (%magic), special shell access (!cmd), etc.
1815 magic calls (%magic), special shell access (!cmd), etc.
1794 """
1816 """
1795
1817
1796 if isinstance(lines, (list, tuple)):
1818 if isinstance(lines, (list, tuple)):
1797 lines = '\n'.join(lines)
1819 lines = '\n'.join(lines)
1798
1820
@@ -1912,6 +1934,7 class InteractiveShell(Configurable, Magic):
1912 try:
1934 try:
1913 try:
1935 try:
1914 self.hooks.pre_runcode_hook()
1936 self.hooks.pre_runcode_hook()
1937 #rprint('Running code') # dbg
1915 exec code_obj in self.user_global_ns, self.user_ns
1938 exec code_obj in self.user_global_ns, self.user_ns
1916 finally:
1939 finally:
1917 # Reset our crash handler in place
1940 # Reset our crash handler in place
@@ -2080,12 +2103,12 class InteractiveShell(Configurable, Magic):
2080 # TODO: This should be removed when Term is refactored.
2103 # TODO: This should be removed when Term is refactored.
2081 def write(self,data):
2104 def write(self,data):
2082 """Write a string to the default output"""
2105 """Write a string to the default output"""
2083 IPython.utils.io.Term.cout.write(data)
2106 io.Term.cout.write(data)
2084
2107
2085 # TODO: This should be removed when Term is refactored.
2108 # TODO: This should be removed when Term is refactored.
2086 def write_err(self,data):
2109 def write_err(self,data):
2087 """Write a string to the default error output"""
2110 """Write a string to the default error output"""
2088 IPython.utils.io.Term.cerr.write(data)
2111 io.Term.cerr.write(data)
2089
2112
2090 def ask_yes_no(self,prompt,default=True):
2113 def ask_yes_no(self,prompt,default=True):
2091 if self.quiet:
2114 if self.quiet:
@@ -90,12 +90,12 from inspect import getsourcefile, getfile, getmodule,\
90
90
91 # IPython's own modules
91 # IPython's own modules
92 # Modified pdb which doesn't damage IPython's readline handling
92 # Modified pdb which doesn't damage IPython's readline handling
93 from IPython.utils import PyColorize
94 from IPython.core import debugger, ipapi
93 from IPython.core import debugger, ipapi
95 from IPython.core.display_trap import DisplayTrap
94 from IPython.core.display_trap import DisplayTrap
96 from IPython.core.excolors import exception_colors
95 from IPython.core.excolors import exception_colors
96 from IPython.utils import PyColorize
97 from IPython.utils import io
97 from IPython.utils.data import uniq_stable
98 from IPython.utils.data import uniq_stable
98 import IPython.utils.io
99 from IPython.utils.warn import info, error
99 from IPython.utils.warn import info, error
100
100
101 # Globals
101 # Globals
@@ -310,7 +310,7 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
310
310
311 #---------------------------------------------------------------------------
311 #---------------------------------------------------------------------------
312 # Module classes
312 # Module classes
313 class TBTools:
313 class TBTools(object):
314 """Basic tools used by all traceback printer classes."""
314 """Basic tools used by all traceback printer classes."""
315
315
316 # This attribute us used in globalipapp.py to have stdout used for
316 # This attribute us used in globalipapp.py to have stdout used for
@@ -319,6 +319,9 class TBTools:
319 # the string 'stdout' which will cause the override to sys.stdout.
319 # the string 'stdout' which will cause the override to sys.stdout.
320 out_stream = None
320 out_stream = None
321
321
322 # Number of frames to skip when reporting tracebacks
323 tb_offset = 0
324
322 def __init__(self,color_scheme = 'NoColor',call_pdb=False):
325 def __init__(self,color_scheme = 'NoColor',call_pdb=False):
323 # Whether to call the interactive pdb debugger after printing
326 # Whether to call the interactive pdb debugger after printing
324 # tracebacks or not
327 # tracebacks or not
@@ -357,6 +360,24 class TBTools:
357 self.color_scheme_table.set_active_scheme('NoColor')
360 self.color_scheme_table.set_active_scheme('NoColor')
358 self.Colors = self.color_scheme_table.active_colors
361 self.Colors = self.color_scheme_table.active_colors
359
362
363 def text(self, etype, value, tb, tb_offset=None, context=5):
364 """Return formatted traceback.
365
366 Subclasses may override this if they add extra arguments.
367 """
368 tb_list = self.structured_traceback(etype, value, tb,
369 tb_offset, context)
370 return '\n'.join(tb_list)
371
372 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
373 context=5, mode=None):
374 """Return a list of traceback frames.
375
376 Must be implemented by each class.
377 """
378 raise NotImplementedError()
379
380
360 #---------------------------------------------------------------------------
381 #---------------------------------------------------------------------------
361 class ListTB(TBTools):
382 class ListTB(TBTools):
362 """Print traceback information from a traceback list, with optional color.
383 """Print traceback information from a traceback list, with optional color.
@@ -381,11 +402,12 class ListTB(TBTools):
381 TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0)
402 TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0)
382
403
383 def __call__(self, etype, value, elist):
404 def __call__(self, etype, value, elist):
384 IPython.utils.io.Term.cout.flush()
405 io.Term.cout.flush()
385 IPython.utils.io.Term.cerr.write(self.text(etype,value,elist))
406 io.Term.cerr.write(self.text(etype, value, elist))
386 IPython.utils.io.Term.cerr.write('\n')
407 io.Term.cerr.write('\n')
387
408
388 def structured_traceback(self, etype, value, elist, context=5):
409 def structured_traceback(self, etype, value, elist, tb_offset=None,
410 context=5):
389 """Return a color formatted string with the traceback info.
411 """Return a color formatted string with the traceback info.
390
412
391 Parameters
413 Parameters
@@ -399,28 +421,43 class ListTB(TBTools):
399 elist : list
421 elist : list
400 List of frames, see class docstring for details.
422 List of frames, see class docstring for details.
401
423
424 tb_offset : int, optional
425 Number of frames in the traceback to skip. If not given, the
426 instance value is used (set in constructor).
427
428 context : int, optional
429 Number of lines of context information to print.
430
402 Returns
431 Returns
403 -------
432 -------
404 String with formatted exception.
433 String with formatted exception.
405 """
434 """
406
435 tb_offset = self.tb_offset if tb_offset is None else tb_offset
407 Colors = self.Colors
436 Colors = self.Colors
408 out_string = []
437 out_list = []
409 if elist:
438 if elist:
410 out_string.append('Traceback %s(most recent call last)%s:' %
439
440 if tb_offset and len(elist) > tb_offset:
441 elist = elist[tb_offset:]
442
443 out_list.append('Traceback %s(most recent call last)%s:' %
411 (Colors.normalEm, Colors.Normal) + '\n')
444 (Colors.normalEm, Colors.Normal) + '\n')
412 out_string.extend(self._format_list(elist))
445 out_list.extend(self._format_list(elist))
413 lines = self._format_exception_only(etype, value)
446 # The exception info should be a single entry in the list.
414 for line in lines[:-1]:
447 lines = ''.join(self._format_exception_only(etype, value))
415 out_string.append(" "+line)
448 out_list.append(lines)
416 out_string.append(lines[-1])
449
417 return out_string
450 # Note: this code originally read:
418
451
419 def text(self, etype, value, elist, context=5):
452 ## for line in lines[:-1]:
420 out_string = ListTB.structured_traceback(
453 ## out_list.append(" "+line)
421 self, etype, value, elist, context
454 ## out_list.append(lines[-1])
422 )
455
423 return ''.join(out_string)
456 # This means it was indenting everything but the last line by a little
457 # bit. I've disabled this for now, but if we see ugliness somewhre we
458 # can restore it.
459
460 return out_list
424
461
425 def _format_list(self, extracted_list):
462 def _format_list(self, extracted_list):
426 """Format a list of traceback entry tuples for printing.
463 """Format a list of traceback entry tuples for printing.
@@ -457,6 +494,7 class ListTB(TBTools):
457 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
494 item = item + '%s %s%s\n' % (Colors.line, line.strip(),
458 Colors.Normal)
495 Colors.Normal)
459 list.append(item)
496 list.append(item)
497 #from pprint import pformat; print 'LISTTB', pformat(list) # dbg
460 return list
498 return list
461
499
462 def _format_exception_only(self, etype, value):
500 def _format_exception_only(self, etype, value):
@@ -528,6 +566,17 class ListTB(TBTools):
528
566
529 return list
567 return list
530
568
569 def get_exception_only(self, etype, value):
570 """Only print the exception type and message, without a traceback.
571
572 Parameters
573 ----------
574 etype : exception type
575 value : exception value
576 """
577 return ListTB.structured_traceback(self, etype, value, [])
578
579
531 def show_exception_only(self, etype, value):
580 def show_exception_only(self, etype, value):
532 """Only print the exception type and message, without a traceback.
581 """Only print the exception type and message, without a traceback.
533
582
@@ -541,9 +590,9 class ListTB(TBTools):
541 if self.out_stream == 'stdout':
590 if self.out_stream == 'stdout':
542 ostream = sys.stdout
591 ostream = sys.stdout
543 else:
592 else:
544 ostream = IPython.utils.io.Term.cerr
593 ostream = io.Term.cerr
545 ostream.flush()
594 ostream.flush()
546 ostream.write(ListTB.text(self, etype, value, []))
595 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
547 ostream.flush()
596 ostream.flush()
548
597
549 def _some_str(self, value):
598 def _some_str(self, value):
@@ -575,9 +624,12 class VerboseTB(TBTools):
575 self.long_header = long_header
624 self.long_header = long_header
576 self.include_vars = include_vars
625 self.include_vars = include_vars
577
626
578 def structured_traceback(self, etype, evalue, etb, context=5):
627 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
628 context=5):
579 """Return a nice text document describing the traceback."""
629 """Return a nice text document describing the traceback."""
580
630
631 tb_offset = self.tb_offset if tb_offset is None else tb_offset
632
581 # some locals
633 # some locals
582 try:
634 try:
583 etype = etype.__name__
635 etype = etype.__name__
@@ -652,9 +704,9 class VerboseTB(TBTools):
652 # Try the default getinnerframes and Alex's: Alex's fixes some
704 # Try the default getinnerframes and Alex's: Alex's fixes some
653 # problems, but it generates empty tracebacks for console errors
705 # problems, but it generates empty tracebacks for console errors
654 # (5 blanks lines) where none should be returned.
706 # (5 blanks lines) where none should be returned.
655 #records = inspect.getinnerframes(etb, context)[self.tb_offset:]
707 #records = inspect.getinnerframes(etb, context)[tb_offset:]
656 #print 'python records:', records # dbg
708 #print 'python records:', records # dbg
657 records = _fixed_getinnerframes(etb, context,self.tb_offset)
709 records = _fixed_getinnerframes(etb, context, tb_offset)
658 #print 'alex records:', records # dbg
710 #print 'alex records:', records # dbg
659 except:
711 except:
660
712
@@ -665,7 +717,7 class VerboseTB(TBTools):
665 # So far, I haven't been able to find an isolated example to
717 # So far, I haven't been able to find an isolated example to
666 # reproduce the problem.
718 # reproduce the problem.
667 inspect_error()
719 inspect_error()
668 traceback.print_exc(file=IPython.utils.io.Term.cerr)
720 traceback.print_exc(file=io.Term.cerr)
669 info('\nUnfortunately, your original traceback can not be constructed.\n')
721 info('\nUnfortunately, your original traceback can not be constructed.\n')
670 return ''
722 return ''
671
723
@@ -702,7 +754,7 class VerboseTB(TBTools):
702 # able to remove this try/except when 2.4 becomes a
754 # able to remove this try/except when 2.4 becomes a
703 # requirement. Bug details at http://python.org/sf/1005466
755 # requirement. Bug details at http://python.org/sf/1005466
704 inspect_error()
756 inspect_error()
705 traceback.print_exc(file=IPython.utils.io.Term.cerr)
757 traceback.print_exc(file=io.Term.cerr)
706 info("\nIPython's exception reporting continues...\n")
758 info("\nIPython's exception reporting continues...\n")
707
759
708 if func == '?':
760 if func == '?':
@@ -723,7 +775,7 class VerboseTB(TBTools):
723 # and barfs out. At some point I should dig into this one
775 # and barfs out. At some point I should dig into this one
724 # and file a bug report about it.
776 # and file a bug report about it.
725 inspect_error()
777 inspect_error()
726 traceback.print_exc(file=IPython.utils.io.Term.cerr)
778 traceback.print_exc(file=io.Term.cerr)
727 info("\nIPython's exception reporting continues...\n")
779 info("\nIPython's exception reporting continues...\n")
728 call = tpl_call_fail % func
780 call = tpl_call_fail % func
729
781
@@ -869,13 +921,7 class VerboseTB(TBTools):
869 # return all our info assembled as a single string
921 # return all our info assembled as a single string
870 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
922 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
871 return [head] + frames + [''.join(exception[0])]
923 return [head] + frames + [''.join(exception[0])]
872
924
873 def text(self, etype, evalue, etb, context=5):
874 tb_list = VerboseTB.structured_traceback(
875 self, etype, evalue, etb, context
876 )
877 return '\n'.join(tb_list)
878
879 def debugger(self,force=False):
925 def debugger(self,force=False):
880 """Call up the pdb debugger if desired, always clean up the tb
926 """Call up the pdb debugger if desired, always clean up the tb
881 reference.
927 reference.
@@ -923,9 +969,9 class VerboseTB(TBTools):
923 def handler(self, info=None):
969 def handler(self, info=None):
924 (etype, evalue, etb) = info or sys.exc_info()
970 (etype, evalue, etb) = info or sys.exc_info()
925 self.tb = etb
971 self.tb = etb
926 IPython.utils.io.Term.cout.flush()
972 io.Term.cout.flush()
927 IPython.utils.io.Term.cerr.write(self.text(etype, evalue, etb))
973 io.Term.cerr.write(self.text(etype, evalue, etb))
928 IPython.utils.io.Term.cerr.write('\n')
974 io.Term.cerr.write('\n')
929
975
930 # Changed so an instance can just be called as VerboseTB_inst() and print
976 # Changed so an instance can just be called as VerboseTB_inst() and print
931 # out the right info on its own.
977 # out the right info on its own.
@@ -941,7 +987,7 class VerboseTB(TBTools):
941 print "\nKeyboardInterrupt"
987 print "\nKeyboardInterrupt"
942
988
943 #----------------------------------------------------------------------------
989 #----------------------------------------------------------------------------
944 class FormattedTB(VerboseTB,ListTB):
990 class FormattedTB(VerboseTB, ListTB):
945 """Subclass ListTB but allow calling with a traceback.
991 """Subclass ListTB but allow calling with a traceback.
946
992
947 It can thus be used as a sys.excepthook for Python > 2.1.
993 It can thus be used as a sys.excepthook for Python > 2.1.
@@ -953,8 +999,8 class FormattedTB(VerboseTB,ListTB):
953 occurs with python programs that themselves execute other python code,
999 occurs with python programs that themselves execute other python code,
954 like Python shells). """
1000 like Python shells). """
955
1001
956 def __init__(self, mode = 'Plain', color_scheme='Linux',
1002 def __init__(self, mode='Plain', color_scheme='Linux',
957 tb_offset = 0,long_header=0,call_pdb=0,include_vars=0):
1003 tb_offset=0, long_header=0, call_pdb=0, include_vars=0):
958
1004
959 # NEVER change the order of this list. Put new modes at the end:
1005 # NEVER change the order of this list. Put new modes at the end:
960 self.valid_modes = ['Plain','Context','Verbose']
1006 self.valid_modes = ['Plain','Context','Verbose']
@@ -970,12 +1016,14 class FormattedTB(VerboseTB,ListTB):
970 else:
1016 else:
971 return None
1017 return None
972
1018
973 def structured_traceback(self, etype, value, tb, context=5, mode=None):
1019 def structured_traceback(self, etype, value, tb, tb_offset=None,
1020 context=5, mode=None):
1021 tb_offset = self.tb_offset if tb_offset is None else tb_offset
974 mode = self.mode if mode is None else mode
1022 mode = self.mode if mode is None else mode
975 if mode in self.verbose_modes:
1023 if mode in self.verbose_modes:
976 # Verbose modes need a full traceback
1024 # Verbose modes need a full traceback
977 return VerboseTB.structured_traceback(
1025 return VerboseTB.structured_traceback(
978 self, etype, value, tb, context
1026 self, etype, value, tb, tb_offset, context
979 )
1027 )
980 else:
1028 else:
981 # We must check the source cache because otherwise we can print
1029 # We must check the source cache because otherwise we can print
@@ -983,21 +1031,21 class FormattedTB(VerboseTB,ListTB):
983 linecache.checkcache()
1031 linecache.checkcache()
984 # Now we can extract and format the exception
1032 # Now we can extract and format the exception
985 elist = self._extract_tb(tb)
1033 elist = self._extract_tb(tb)
986 if len(elist) > self.tb_offset:
987 del elist[:self.tb_offset]
988 return ListTB.structured_traceback(
1034 return ListTB.structured_traceback(
989 self, etype, value, elist, context
1035 self, etype, value, elist, tb_offset, context
990 )
1036 )
991
1037
992 def text(self, etype, value, tb, context=5, mode=None):
1038 def text(self, etype, value, tb, tb_offset=None, context=5, mode=None):
993 """Return formatted traceback.
1039 """Return formatted traceback.
994
1040
995 If the optional mode parameter is given, it overrides the current
1041 If the optional mode parameter is given, it overrides the current
996 mode."""
1042 mode."""
997 tb_list = FormattedTB.structured_traceback(
1043
998 self, etype, value, tb, context, mode
1044 mode = self.mode if mode is None else mode
999 )
1045 tb_list = self.structured_traceback(etype, value, tb, tb_offset,
1046 context, mode)
1000 return '\n'.join(tb_list)
1047 return '\n'.join(tb_list)
1048
1001
1049
1002 def set_mode(self,mode=None):
1050 def set_mode(self,mode=None):
1003 """Switch to the desired mode.
1051 """Switch to the desired mode.
@@ -1056,36 +1104,25 class AutoFormattedTB(FormattedTB):
1056 if self.out_stream == 'stdout':
1104 if self.out_stream == 'stdout':
1057 out = sys.stdout
1105 out = sys.stdout
1058 else:
1106 else:
1059 out = IPython.utils.io.Term.cerr
1107 out = io.Term.cerr
1060 out.flush()
1108 out.flush()
1061 if tb_offset is not None:
1109 out.write(self.text(etype, evalue, etb, tb_offset))
1062 tb_offset, self.tb_offset = self.tb_offset, tb_offset
1110 out.write('\n')
1063 out.write(self.text(etype, evalue, etb))
1064 out.write('\n')
1065 self.tb_offset = tb_offset
1066 else:
1067 out.write(self.text(etype, evalue, etb))
1068 out.write('\n')
1069 out.flush()
1111 out.flush()
1112 # FIXME: we should remove the auto pdb behavior from here and leave
1113 # that to the clients.
1070 try:
1114 try:
1071 self.debugger()
1115 self.debugger()
1072 except KeyboardInterrupt:
1116 except KeyboardInterrupt:
1073 print "\nKeyboardInterrupt"
1117 print "\nKeyboardInterrupt"
1074
1118
1075 def structured_traceback(self, etype=None, value=None, tb=None,
1119 def structured_traceback(self, etype=None, value=None, tb=None,
1076 context=5, mode=None):
1120 tb_offset=None, context=5, mode=None):
1077 if etype is None:
1121 if etype is None:
1078 etype,value,tb = sys.exc_info()
1122 etype,value,tb = sys.exc_info()
1079 self.tb = tb
1123 self.tb = tb
1080 return FormattedTB.structured_traceback(
1124 return FormattedTB.structured_traceback(
1081 self, etype, value, tb, context, mode
1125 self, etype, value, tb, tb_offset, context, mode )
1082 )
1083
1084 def text(self, etype=None, value=None, tb=None, context=5, mode=None):
1085 tb_list = AutoFormattedTB.structured_traceback(
1086 self, etype, value, tb, context, mode
1087 )
1088 return '\n'.join(tb_list)
1089
1126
1090 #---------------------------------------------------------------------------
1127 #---------------------------------------------------------------------------
1091
1128
@@ -1114,6 +1151,15 class SyntaxTB(ListTB):
1114 self.last_syntax_error = None
1151 self.last_syntax_error = None
1115 return e
1152 return e
1116
1153
1154 def text(self, etype, value, tb, tb_offset=None, context=5):
1155 """Return formatted traceback.
1156
1157 Subclasses may override this if they add extra arguments.
1158 """
1159 tb_list = self.structured_traceback(etype, value, tb,
1160 tb_offset, context)
1161 return ''.join(tb_list)
1162
1117 #----------------------------------------------------------------------------
1163 #----------------------------------------------------------------------------
1118 # module testing (minimal)
1164 # module testing (minimal)
1119 if __name__ == "__main__":
1165 if __name__ == "__main__":
@@ -94,7 +94,7 class IPythonWidget(FrontendWidget):
94 def execute_file(self, path, hidden=False):
94 def execute_file(self, path, hidden=False):
95 """ Reimplemented to use the 'run' magic.
95 """ Reimplemented to use the 'run' magic.
96 """
96 """
97 self.execute('run %s' % path, hidden=hidden)
97 self.execute('%%run %s' % path, hidden=hidden)
98
98
99 #---------------------------------------------------------------------------
99 #---------------------------------------------------------------------------
100 # 'FrontendWidget' protected interface
100 # 'FrontendWidget' protected interface
@@ -109,16 +109,24 class IPythonWidget(FrontendWidget):
109 """ Reimplemented for IPython-style traceback formatting.
109 """ Reimplemented for IPython-style traceback formatting.
110 """
110 """
111 content = msg['content']
111 content = msg['content']
112 traceback_lines = content['traceback'][:]
113 traceback = ''.join(traceback_lines)
114 traceback = traceback.replace(' ', ' ')
115 traceback = traceback.replace('\n', '<br/>')
116
112
117 ename = content['ename']
113 traceback = '\n'.join(content['traceback'])
118 ename_styled = '<span class="error">%s</span>' % ename
119 traceback = traceback.replace(ename, ename_styled)
120
114
121 self._append_html(traceback)
115 if 0:
116 # FIXME: for now, tracebacks come as plain text, so we can't use
117 # the html renderer yet. Once we refactor ultratb to produce
118 # properly styled tracebacks, this branch should be the default
119 traceback = traceback.replace(' ', '&nbsp;')
120 traceback = traceback.replace('\n', '<br/>')
121
122 ename = content['ename']
123 ename_styled = '<span class="error">%s</span>' % ename
124 traceback = traceback.replace(ename, ename_styled)
125
126 self._append_html(traceback)
127 else:
128 # This is the fallback for now, using plain text with ansi escapes
129 self._append_plain_text(traceback)
122
130
123 def _process_execute_payload(self, item):
131 def _process_execute_payload(self, item):
124 """ Reimplemented to handle %edit and paging payloads.
132 """ Reimplemented to handle %edit and paging payloads.
@@ -61,6 +61,10 def main():
61 kernel_manager.start_kernel()
61 kernel_manager.start_kernel()
62 kernel_manager.start_channels()
62 kernel_manager.start_channels()
63
63
64 # FIXME: this is a hack, set colors to lightbg by default in qt terminal
65 # unconditionally, regardless of user settings in config files.
66 kernel_manager.xreq_channel.execute("%colors lightbg")
67
64 # Launch the application.
68 # Launch the application.
65 app = QtGui.QApplication([])
69 app = QtGui.QApplication([])
66 if args.pure:
70 if args.pure:
@@ -13,7 +13,6 IO related utilities.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
17 import sys
16 import sys
18 import tempfile
17 import tempfile
19
18
@@ -278,4 +277,10 def temp_pyfile(src, ext='.py'):
278 return fname, f
277 return fname, f
279
278
280
279
281
280 def rprint(*info):
281 """Raw print to sys.__stderr__"""
282
283 for item in info:
284 print >> sys.__stderr__, item,
285 print >> sys.__stderr__
286 sys.__stderr__.flush()
@@ -66,6 +66,9 class Kernel(Configurable):
66 self.shell.displayhook.session = self.session
66 self.shell.displayhook.session = self.session
67 self.shell.displayhook.pub_socket = self.pub_socket
67 self.shell.displayhook.pub_socket = self.pub_socket
68
68
69 # TMP - hack while developing
70 self.shell._reply_content = None
71
69 # Build dict of handlers for message types
72 # Build dict of handlers for message types
70 msg_types = [ 'execute_request', 'complete_request',
73 msg_types = [ 'execute_request', 'complete_request',
71 'object_info_request', 'prompt_request',
74 'object_info_request', 'prompt_request',
@@ -156,19 +159,20 class Kernel(Configurable):
156 sys.stdout.set_parent(parent)
159 sys.stdout.set_parent(parent)
157 sys.stderr.set_parent(parent)
160 sys.stderr.set_parent(parent)
158
161
162 # FIXME: runlines calls the exception handler itself. We should
163 # clean this up.
164 self.shell._reply_content = None
159 self.shell.runlines(code)
165 self.shell.runlines(code)
160 except:
166 except:
167 # FIXME: this code right now isn't being used yet by default,
168 # because the runlines() call above directly fires off exception
169 # reporting. This code, therefore, is only active in the scenario
170 # where runlines itself has an unhandled exception. We need to
171 # uniformize this, for all exception construction to come from a
172 # single location in the codbase.
161 etype, evalue, tb = sys.exc_info()
173 etype, evalue, tb = sys.exc_info()
162 tb = traceback.format_exception(etype, evalue, tb)
174 tb_list = traceback.format_exception(etype, evalue, tb)
163 exc_content = {
175 reply_content = self.shell._showtraceback(etype, evalue, tb_list)
164 u'status' : u'error',
165 u'traceback' : tb,
166 u'ename' : unicode(etype.__name__),
167 u'evalue' : unicode(evalue)
168 }
169 exc_msg = self.session.msg(u'pyerr', exc_content, parent)
170 self.pub_socket.send_json(exc_msg)
171 reply_content = exc_content
172 else:
176 else:
173 payload = self.shell.payload_manager.read_payload()
177 payload = self.shell.payload_manager.read_payload()
174 # Be agressive about clearing the payload because we don't want
178 # Be agressive about clearing the payload because we don't want
@@ -185,6 +189,11 class Kernel(Configurable):
185 'input_sep' : self.shell.displayhook.input_sep}
189 'input_sep' : self.shell.displayhook.input_sep}
186 reply_content['next_prompt'] = next_prompt
190 reply_content['next_prompt'] = next_prompt
187
191
192 # TMP - fish exception info out of shell, possibly left there by
193 # runlines
194 if self.shell._reply_content is not None:
195 reply_content.update(self.shell._reply_content)
196
188 # Flush output before sending the reply.
197 # Flush output before sending the reply.
189 sys.stderr.flush()
198 sys.stderr.flush()
190 sys.stdout.flush()
199 sys.stdout.flush()
@@ -8,6 +8,7 from IPython.core.interactiveshell import (
8 )
8 )
9 from IPython.core.displayhook import DisplayHook
9 from IPython.core.displayhook import DisplayHook
10 from IPython.core.macro import Macro
10 from IPython.core.macro import Macro
11 from IPython.utils.io import rprint
11 from IPython.utils.path import get_py_filename
12 from IPython.utils.path import get_py_filename
12 from IPython.utils.text import StringTypes
13 from IPython.utils.text import StringTypes
13 from IPython.utils.traitlets import Instance, Type, Dict
14 from IPython.utils.traitlets import Instance, Type, Dict
@@ -359,7 +360,30 class ZMQInteractiveShell(InteractiveShell):
359 self.payload_manager.write_payload(payload)
360 self.payload_manager.write_payload(payload)
360
361
361
362
362 InteractiveShellABC.register(ZMQInteractiveShell)
363 def _showtraceback(self, etype, evalue, stb):
363
364
365 exc_content = {
366 u'status' : u'error',
367 u'traceback' : stb,
368 u'ename' : unicode(etype.__name__),
369 u'evalue' : unicode(evalue)
370 }
364
371
372 dh = self.displayhook
373 exc_msg = dh.session.msg(u'pyerr', exc_content, dh.parent_header)
374 # Send exception info over pub socket for other clients than the caller
375 # to pick up
376 dh.pub_socket.send_json(exc_msg)
377
378 # FIXME - Hack: store exception info in shell object. Right now, the
379 # caller is reading this info after the fact, we need to fix this logic
380 # to remove this hack.
381 self._reply_content = exc_content
382 # /FIXME