diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 711b2f9..edf5c9c 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -29,6 +29,7 @@ import sys import tempfile from contextlib import nested +from IPython.config.configurable import Configurable from IPython.core import debugger, oinspect from IPython.core import history as ipcorehist from IPython.core import prefilter @@ -36,8 +37,8 @@ from IPython.core import shadowns from IPython.core import ultratb from IPython.core.alias import AliasManager from IPython.core.builtin_trap import BuiltinTrap -from IPython.config.configurable import Configurable from IPython.core.display_trap import DisplayTrap +from IPython.core.displayhook import DisplayHook from IPython.core.error import UsageError from IPython.core.extensions import ExtensionManager from IPython.core.fakemodule import FakeModule, init_fakemod_dict @@ -47,24 +48,22 @@ from IPython.core.magic import Magic from IPython.core.payload import PayloadManager from IPython.core.plugin import PluginManager from IPython.core.prefilter import PrefilterManager -from IPython.core.displayhook import DisplayHook -import IPython.core.hooks from IPython.external.Itpl import ItplNS from IPython.utils import PyColorize +from IPython.utils import io from IPython.utils import pickleshare from IPython.utils.doctestreload import doctest_reload +from IPython.utils.io import ask_yes_no, rprint from IPython.utils.ipstruct import Struct -import IPython.utils.io -from IPython.utils.io import ask_yes_no from IPython.utils.path import get_home_dir, get_ipython_dir, HomeDirError from IPython.utils.process import getoutput, getoutputerror from IPython.utils.strdispatch import StrDispatch from IPython.utils.syspathcontext import prepended_to_syspath from IPython.utils.text import num_ini_spaces +from IPython.utils.traitlets import (Int, Str, CBool, CaselessStrEnum, Enum, + List, Unicode, Instance, Type) from IPython.utils.warn import warn, error, fatal -from IPython.utils.traitlets import ( - Int, Str, CBool, CaselessStrEnum, Enum, List, Unicode, Instance, Type -) +import IPython.core.hooks # from IPython.utils import growl # growl.start("IPython") @@ -430,12 +429,12 @@ class InteractiveShell(Configurable, Magic): def init_io(self): import IPython.utils.io if sys.platform == 'win32' and self.has_readline: - Term = IPython.utils.io.IOTerm( + Term = io.IOTerm( cout=self.readline._outputfile,cerr=self.readline._outputfile ) else: - Term = IPython.utils.io.IOTerm() - IPython.utils.io.Term = Term + Term = io.IOTerm() + io.Term = Term def init_prompts(self): # TODO: This is a pass for now because the prompts are managed inside @@ -1181,7 +1180,7 @@ class InteractiveShell(Configurable, Magic): # Set the exception mode self.InteractiveTB.set_mode(mode=self.xmode) - def set_custom_exc(self,exc_tuple,handler): + def set_custom_exc(self, exc_tuple, handler): """set_custom_exc(exc_tuple,handler) Set a custom exception handler, which will be called if any of the @@ -1198,7 +1197,12 @@ class InteractiveShell(Configurable, Magic): exc_tuple == (MyCustomException,) - handler: this must be defined as a function with the following - basic interface: def my_handler(self,etype,value,tb). + basic interface:: + + def my_handler(self, etype, value, tb, tb_offset=None) + ... + # The return value must be + return structured_traceback This will be made into an instance method (via new.instancemethod) of IPython itself, and it will be called if any of the exceptions @@ -1272,7 +1276,7 @@ class InteractiveShell(Configurable, Magic): etype, value, tb = sys.last_type, sys.last_value, \ sys.last_traceback else: - self.write('No traceback available to show.\n') + self.write_err('No traceback available to show.\n') return if etype is SyntaxError: @@ -1291,22 +1295,39 @@ class InteractiveShell(Configurable, Magic): sys.last_traceback = tb if etype in self.custom_exceptions: - self.CustomTB(etype,value,tb) + # FIXME: Old custom traceback objects may just return a + # string, in that case we just put it into a list + stb = self.CustomTB(etype, value, tb, tb_offset) + if isinstance(ctb, basestring): + stb = [stb] else: if exception_only: - m = ('An exception has occurred, use %tb to see the ' - 'full traceback.') - print m - self.InteractiveTB.show_exception_only(etype, value) + stb = ['An exception has occurred, use %tb to see ' + 'the full traceback.'] + stb.extend(self.InteractiveTB.get_exception_only(etype, + value)) else: - self.InteractiveTB(etype,value,tb,tb_offset=tb_offset) + stb = self.InteractiveTB.structured_traceback(etype, + value, tb, tb_offset=tb_offset) + # FIXME: the pdb calling should be done by us, not by + # the code computing the traceback. if self.InteractiveTB.call_pdb: # pdb mucks up readline, fix it back self.set_completer() - + + # Actually show the traceback + self._showtraceback(etype, value, stb) + except KeyboardInterrupt: - self.write("\nKeyboardInterrupt\n") - + self.write_err("\nKeyboardInterrupt\n") + + def _showtraceback(self, etype, evalue, stb): + """Actually show a traceback. + + Subclasses may override this method to put the traceback on a different + place, like a side channel. + """ + self.write_err('\n'.join(stb)) def showsyntaxerror(self, filename=None): """Display the syntax error that just occurred. @@ -1339,7 +1360,8 @@ class InteractiveShell(Configurable, Magic): except: # If that failed, assume SyntaxError is a string value = msg, (filename, lineno, offset, line) - self.SyntaxTB(etype,value,[]) + stb = self.SyntaxTB.structured_traceback(etype, value, []) + self._showtraceback(etype, value, stb) #------------------------------------------------------------------------- # Things related to tab completion @@ -1792,7 +1814,7 @@ class InteractiveShell(Configurable, Magic): exposes IPython's processing machinery, the given strings can contain magic calls (%magic), special shell access (!cmd), etc. """ - + if isinstance(lines, (list, tuple)): lines = '\n'.join(lines) @@ -1912,6 +1934,7 @@ class InteractiveShell(Configurable, Magic): try: try: self.hooks.pre_runcode_hook() + #rprint('Running code') # dbg exec code_obj in self.user_global_ns, self.user_ns finally: # Reset our crash handler in place @@ -2080,12 +2103,12 @@ class InteractiveShell(Configurable, Magic): # TODO: This should be removed when Term is refactored. def write(self,data): """Write a string to the default output""" - IPython.utils.io.Term.cout.write(data) + io.Term.cout.write(data) # TODO: This should be removed when Term is refactored. def write_err(self,data): """Write a string to the default error output""" - IPython.utils.io.Term.cerr.write(data) + io.Term.cerr.write(data) def ask_yes_no(self,prompt,default=True): if self.quiet: diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 7606ab6..8a4cabd 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -90,12 +90,12 @@ from inspect import getsourcefile, getfile, getmodule,\ # IPython's own modules # Modified pdb which doesn't damage IPython's readline handling -from IPython.utils import PyColorize from IPython.core import debugger, ipapi from IPython.core.display_trap import DisplayTrap from IPython.core.excolors import exception_colors +from IPython.utils import PyColorize +from IPython.utils import io from IPython.utils.data import uniq_stable -import IPython.utils.io from IPython.utils.warn import info, error # Globals @@ -310,7 +310,7 @@ def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None): #--------------------------------------------------------------------------- # Module classes -class TBTools: +class TBTools(object): """Basic tools used by all traceback printer classes.""" # This attribute us used in globalipapp.py to have stdout used for @@ -319,6 +319,9 @@ class TBTools: # the string 'stdout' which will cause the override to sys.stdout. out_stream = None + # Number of frames to skip when reporting tracebacks + tb_offset = 0 + def __init__(self,color_scheme = 'NoColor',call_pdb=False): # Whether to call the interactive pdb debugger after printing # tracebacks or not @@ -357,6 +360,24 @@ class TBTools: self.color_scheme_table.set_active_scheme('NoColor') self.Colors = self.color_scheme_table.active_colors + def text(self, etype, value, tb, tb_offset=None, context=5): + """Return formatted traceback. + + Subclasses may override this if they add extra arguments. + """ + tb_list = self.structured_traceback(etype, value, tb, + tb_offset, context) + return '\n'.join(tb_list) + + def structured_traceback(self, etype, evalue, tb, tb_offset=None, + context=5, mode=None): + """Return a list of traceback frames. + + Must be implemented by each class. + """ + raise NotImplementedError() + + #--------------------------------------------------------------------------- class ListTB(TBTools): """Print traceback information from a traceback list, with optional color. @@ -381,11 +402,12 @@ class ListTB(TBTools): TBTools.__init__(self,color_scheme = color_scheme,call_pdb=0) def __call__(self, etype, value, elist): - IPython.utils.io.Term.cout.flush() - IPython.utils.io.Term.cerr.write(self.text(etype,value,elist)) - IPython.utils.io.Term.cerr.write('\n') + io.Term.cout.flush() + io.Term.cerr.write(self.text(etype, value, elist)) + io.Term.cerr.write('\n') - def structured_traceback(self, etype, value, elist, context=5): + def structured_traceback(self, etype, value, elist, tb_offset=None, + context=5): """Return a color formatted string with the traceback info. Parameters @@ -399,28 +421,43 @@ class ListTB(TBTools): elist : list List of frames, see class docstring for details. + tb_offset : int, optional + Number of frames in the traceback to skip. If not given, the + instance value is used (set in constructor). + + context : int, optional + Number of lines of context information to print. + Returns ------- String with formatted exception. """ - + tb_offset = self.tb_offset if tb_offset is None else tb_offset Colors = self.Colors - out_string = [] + out_list = [] if elist: - out_string.append('Traceback %s(most recent call last)%s:' % + + if tb_offset and len(elist) > tb_offset: + elist = elist[tb_offset:] + + out_list.append('Traceback %s(most recent call last)%s:' % (Colors.normalEm, Colors.Normal) + '\n') - out_string.extend(self._format_list(elist)) - lines = self._format_exception_only(etype, value) - for line in lines[:-1]: - out_string.append(" "+line) - out_string.append(lines[-1]) - return out_string - - def text(self, etype, value, elist, context=5): - out_string = ListTB.structured_traceback( - self, etype, value, elist, context - ) - return ''.join(out_string) + out_list.extend(self._format_list(elist)) + # The exception info should be a single entry in the list. + lines = ''.join(self._format_exception_only(etype, value)) + out_list.append(lines) + + # Note: this code originally read: + + ## for line in lines[:-1]: + ## out_list.append(" "+line) + ## out_list.append(lines[-1]) + + # This means it was indenting everything but the last line by a little + # bit. I've disabled this for now, but if we see ugliness somewhre we + # can restore it. + + return out_list def _format_list(self, extracted_list): """Format a list of traceback entry tuples for printing. @@ -457,6 +494,7 @@ class ListTB(TBTools): item = item + '%s %s%s\n' % (Colors.line, line.strip(), Colors.Normal) list.append(item) + #from pprint import pformat; print 'LISTTB', pformat(list) # dbg return list def _format_exception_only(self, etype, value): @@ -528,6 +566,17 @@ class ListTB(TBTools): return list + def get_exception_only(self, etype, value): + """Only print the exception type and message, without a traceback. + + Parameters + ---------- + etype : exception type + value : exception value + """ + return ListTB.structured_traceback(self, etype, value, []) + + def show_exception_only(self, etype, value): """Only print the exception type and message, without a traceback. @@ -541,9 +590,9 @@ class ListTB(TBTools): if self.out_stream == 'stdout': ostream = sys.stdout else: - ostream = IPython.utils.io.Term.cerr + ostream = io.Term.cerr ostream.flush() - ostream.write(ListTB.text(self, etype, value, [])) + ostream.write('\n'.join(self.get_exception_only(etype, evalue))) ostream.flush() def _some_str(self, value): @@ -575,9 +624,12 @@ class VerboseTB(TBTools): self.long_header = long_header self.include_vars = include_vars - def structured_traceback(self, etype, evalue, etb, context=5): + def structured_traceback(self, etype, evalue, etb, tb_offset=None, + context=5): """Return a nice text document describing the traceback.""" + tb_offset = self.tb_offset if tb_offset is None else tb_offset + # some locals try: etype = etype.__name__ @@ -652,9 +704,9 @@ class VerboseTB(TBTools): # Try the default getinnerframes and Alex's: Alex's fixes some # problems, but it generates empty tracebacks for console errors # (5 blanks lines) where none should be returned. - #records = inspect.getinnerframes(etb, context)[self.tb_offset:] + #records = inspect.getinnerframes(etb, context)[tb_offset:] #print 'python records:', records # dbg - records = _fixed_getinnerframes(etb, context,self.tb_offset) + records = _fixed_getinnerframes(etb, context, tb_offset) #print 'alex records:', records # dbg except: @@ -665,7 +717,7 @@ class VerboseTB(TBTools): # So far, I haven't been able to find an isolated example to # reproduce the problem. inspect_error() - traceback.print_exc(file=IPython.utils.io.Term.cerr) + traceback.print_exc(file=io.Term.cerr) info('\nUnfortunately, your original traceback can not be constructed.\n') return '' @@ -702,7 +754,7 @@ class VerboseTB(TBTools): # able to remove this try/except when 2.4 becomes a # requirement. Bug details at http://python.org/sf/1005466 inspect_error() - traceback.print_exc(file=IPython.utils.io.Term.cerr) + traceback.print_exc(file=io.Term.cerr) info("\nIPython's exception reporting continues...\n") if func == '?': @@ -723,7 +775,7 @@ class VerboseTB(TBTools): # and barfs out. At some point I should dig into this one # and file a bug report about it. inspect_error() - traceback.print_exc(file=IPython.utils.io.Term.cerr) + traceback.print_exc(file=io.Term.cerr) info("\nIPython's exception reporting continues...\n") call = tpl_call_fail % func @@ -869,13 +921,7 @@ class VerboseTB(TBTools): # return all our info assembled as a single string # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) ) return [head] + frames + [''.join(exception[0])] - - def text(self, etype, evalue, etb, context=5): - tb_list = VerboseTB.structured_traceback( - self, etype, evalue, etb, context - ) - return '\n'.join(tb_list) - + def debugger(self,force=False): """Call up the pdb debugger if desired, always clean up the tb reference. @@ -923,9 +969,9 @@ class VerboseTB(TBTools): def handler(self, info=None): (etype, evalue, etb) = info or sys.exc_info() self.tb = etb - IPython.utils.io.Term.cout.flush() - IPython.utils.io.Term.cerr.write(self.text(etype, evalue, etb)) - IPython.utils.io.Term.cerr.write('\n') + io.Term.cout.flush() + io.Term.cerr.write(self.text(etype, evalue, etb)) + io.Term.cerr.write('\n') # Changed so an instance can just be called as VerboseTB_inst() and print # out the right info on its own. @@ -941,7 +987,7 @@ class VerboseTB(TBTools): print "\nKeyboardInterrupt" #---------------------------------------------------------------------------- -class FormattedTB(VerboseTB,ListTB): +class FormattedTB(VerboseTB, ListTB): """Subclass ListTB but allow calling with a traceback. It can thus be used as a sys.excepthook for Python > 2.1. @@ -953,8 +999,8 @@ class FormattedTB(VerboseTB,ListTB): occurs with python programs that themselves execute other python code, like Python shells). """ - def __init__(self, mode = 'Plain', color_scheme='Linux', - tb_offset = 0,long_header=0,call_pdb=0,include_vars=0): + def __init__(self, mode='Plain', color_scheme='Linux', + tb_offset=0, long_header=0, call_pdb=0, include_vars=0): # NEVER change the order of this list. Put new modes at the end: self.valid_modes = ['Plain','Context','Verbose'] @@ -970,12 +1016,14 @@ class FormattedTB(VerboseTB,ListTB): else: return None - def structured_traceback(self, etype, value, tb, context=5, mode=None): + def structured_traceback(self, etype, value, tb, tb_offset=None, + context=5, mode=None): + tb_offset = self.tb_offset if tb_offset is None else tb_offset mode = self.mode if mode is None else mode if mode in self.verbose_modes: # Verbose modes need a full traceback return VerboseTB.structured_traceback( - self, etype, value, tb, context + self, etype, value, tb, tb_offset, context ) else: # We must check the source cache because otherwise we can print @@ -983,21 +1031,21 @@ class FormattedTB(VerboseTB,ListTB): linecache.checkcache() # Now we can extract and format the exception elist = self._extract_tb(tb) - if len(elist) > self.tb_offset: - del elist[:self.tb_offset] return ListTB.structured_traceback( - self, etype, value, elist, context + self, etype, value, elist, tb_offset, context ) - def text(self, etype, value, tb, context=5, mode=None): + def text(self, etype, value, tb, tb_offset=None, context=5, mode=None): """Return formatted traceback. If the optional mode parameter is given, it overrides the current mode.""" - tb_list = FormattedTB.structured_traceback( - self, etype, value, tb, context, mode - ) + + mode = self.mode if mode is None else mode + tb_list = self.structured_traceback(etype, value, tb, tb_offset, + context, mode) return '\n'.join(tb_list) + def set_mode(self,mode=None): """Switch to the desired mode. @@ -1056,36 +1104,25 @@ class AutoFormattedTB(FormattedTB): if self.out_stream == 'stdout': out = sys.stdout else: - out = IPython.utils.io.Term.cerr + out = io.Term.cerr out.flush() - if tb_offset is not None: - tb_offset, self.tb_offset = self.tb_offset, tb_offset - out.write(self.text(etype, evalue, etb)) - out.write('\n') - self.tb_offset = tb_offset - else: - out.write(self.text(etype, evalue, etb)) - out.write('\n') + out.write(self.text(etype, evalue, etb, tb_offset)) + out.write('\n') out.flush() + # FIXME: we should remove the auto pdb behavior from here and leave + # that to the clients. try: self.debugger() except KeyboardInterrupt: print "\nKeyboardInterrupt" def structured_traceback(self, etype=None, value=None, tb=None, - context=5, mode=None): + tb_offset=None, context=5, mode=None): if etype is None: etype,value,tb = sys.exc_info() self.tb = tb return FormattedTB.structured_traceback( - self, etype, value, tb, context, mode - ) - - def text(self, etype=None, value=None, tb=None, context=5, mode=None): - tb_list = AutoFormattedTB.structured_traceback( - self, etype, value, tb, context, mode - ) - return '\n'.join(tb_list) + self, etype, value, tb, tb_offset, context, mode ) #--------------------------------------------------------------------------- @@ -1114,6 +1151,15 @@ class SyntaxTB(ListTB): self.last_syntax_error = None return e + def text(self, etype, value, tb, tb_offset=None, context=5): + """Return formatted traceback. + + Subclasses may override this if they add extra arguments. + """ + tb_list = self.structured_traceback(etype, value, tb, + tb_offset, context) + return ''.join(tb_list) + #---------------------------------------------------------------------------- # module testing (minimal) if __name__ == "__main__": diff --git a/IPython/frontend/qt/console/ipython_widget.py b/IPython/frontend/qt/console/ipython_widget.py index b140e7b..e6e5334 100644 --- a/IPython/frontend/qt/console/ipython_widget.py +++ b/IPython/frontend/qt/console/ipython_widget.py @@ -94,7 +94,7 @@ class IPythonWidget(FrontendWidget): def execute_file(self, path, hidden=False): """ Reimplemented to use the 'run' magic. """ - self.execute('run %s' % path, hidden=hidden) + self.execute('%%run %s' % path, hidden=hidden) #--------------------------------------------------------------------------- # 'FrontendWidget' protected interface @@ -109,16 +109,24 @@ class IPythonWidget(FrontendWidget): """ Reimplemented for IPython-style traceback formatting. """ content = msg['content'] - traceback_lines = content['traceback'][:] - traceback = ''.join(traceback_lines) - traceback = traceback.replace(' ', ' ') - traceback = traceback.replace('\n', '
') - ename = content['ename'] - ename_styled = '%s' % ename - traceback = traceback.replace(ename, ename_styled) + traceback = '\n'.join(content['traceback']) - self._append_html(traceback) + if 0: + # FIXME: for now, tracebacks come as plain text, so we can't use + # the html renderer yet. Once we refactor ultratb to produce + # properly styled tracebacks, this branch should be the default + traceback = traceback.replace(' ', ' ') + traceback = traceback.replace('\n', '
') + + ename = content['ename'] + ename_styled = '%s' % ename + traceback = traceback.replace(ename, ename_styled) + + self._append_html(traceback) + else: + # This is the fallback for now, using plain text with ansi escapes + self._append_plain_text(traceback) def _process_execute_payload(self, item): """ Reimplemented to handle %edit and paging payloads. diff --git a/IPython/frontend/qt/console/scripts/ipythonqt.py b/IPython/frontend/qt/console/scripts/ipythonqt.py index cdf50a2..1a8033c 100755 --- a/IPython/frontend/qt/console/scripts/ipythonqt.py +++ b/IPython/frontend/qt/console/scripts/ipythonqt.py @@ -61,6 +61,10 @@ def main(): kernel_manager.start_kernel() kernel_manager.start_channels() + # FIXME: this is a hack, set colors to lightbg by default in qt terminal + # unconditionally, regardless of user settings in config files. + kernel_manager.xreq_channel.execute("%colors lightbg") + # Launch the application. app = QtGui.QApplication([]) if args.pure: diff --git a/IPython/utils/io.py b/IPython/utils/io.py index e38445b..e32c49f 100644 --- a/IPython/utils/io.py +++ b/IPython/utils/io.py @@ -13,7 +13,6 @@ IO related utilities. #----------------------------------------------------------------------------- # Imports #----------------------------------------------------------------------------- - import sys import tempfile @@ -278,4 +277,10 @@ def temp_pyfile(src, ext='.py'): return fname, f - +def rprint(*info): + """Raw print to sys.__stderr__""" + + for item in info: + print >> sys.__stderr__, item, + print >> sys.__stderr__ + sys.__stderr__.flush() diff --git a/IPython/zmq/ipkernel.py b/IPython/zmq/ipkernel.py index bcdf342..4839785 100755 --- a/IPython/zmq/ipkernel.py +++ b/IPython/zmq/ipkernel.py @@ -66,6 +66,9 @@ class Kernel(Configurable): self.shell.displayhook.session = self.session self.shell.displayhook.pub_socket = self.pub_socket + # TMP - hack while developing + self.shell._reply_content = None + # Build dict of handlers for message types msg_types = [ 'execute_request', 'complete_request', 'object_info_request', 'prompt_request', @@ -156,19 +159,20 @@ class Kernel(Configurable): sys.stdout.set_parent(parent) sys.stderr.set_parent(parent) + # FIXME: runlines calls the exception handler itself. We should + # clean this up. + self.shell._reply_content = None self.shell.runlines(code) except: + # FIXME: this code right now isn't being used yet by default, + # because the runlines() call above directly fires off exception + # reporting. This code, therefore, is only active in the scenario + # where runlines itself has an unhandled exception. We need to + # uniformize this, for all exception construction to come from a + # single location in the codbase. etype, evalue, tb = sys.exc_info() - tb = traceback.format_exception(etype, evalue, tb) - exc_content = { - u'status' : u'error', - u'traceback' : tb, - u'ename' : unicode(etype.__name__), - u'evalue' : unicode(evalue) - } - exc_msg = self.session.msg(u'pyerr', exc_content, parent) - self.pub_socket.send_json(exc_msg) - reply_content = exc_content + tb_list = traceback.format_exception(etype, evalue, tb) + reply_content = self.shell._showtraceback(etype, evalue, tb_list) else: payload = self.shell.payload_manager.read_payload() # Be agressive about clearing the payload because we don't want @@ -185,6 +189,11 @@ class Kernel(Configurable): 'input_sep' : self.shell.displayhook.input_sep} reply_content['next_prompt'] = next_prompt + # TMP - fish exception info out of shell, possibly left there by + # runlines + if self.shell._reply_content is not None: + reply_content.update(self.shell._reply_content) + # Flush output before sending the reply. sys.stderr.flush() sys.stdout.flush() diff --git a/IPython/zmq/zmqshell.py b/IPython/zmq/zmqshell.py index ecbf85e..0e2c1a8 100644 --- a/IPython/zmq/zmqshell.py +++ b/IPython/zmq/zmqshell.py @@ -8,6 +8,7 @@ from IPython.core.interactiveshell import ( ) from IPython.core.displayhook import DisplayHook from IPython.core.macro import Macro +from IPython.utils.io import rprint from IPython.utils.path import get_py_filename from IPython.utils.text import StringTypes from IPython.utils.traitlets import Instance, Type, Dict @@ -359,7 +360,30 @@ class ZMQInteractiveShell(InteractiveShell): self.payload_manager.write_payload(payload) -InteractiveShellABC.register(ZMQInteractiveShell) + def _showtraceback(self, etype, evalue, stb): + exc_content = { + u'status' : u'error', + u'traceback' : stb, + u'ename' : unicode(etype.__name__), + u'evalue' : unicode(evalue) + } + dh = self.displayhook + exc_msg = dh.session.msg(u'pyerr', exc_content, dh.parent_header) + # Send exception info over pub socket for other clients than the caller + # to pick up + dh.pub_socket.send_json(exc_msg) + + # FIXME - Hack: store exception info in shell object. Right now, the + # caller is reading this info after the fact, we need to fix this logic + # to remove this hack. + self._reply_content = exc_content + # /FIXME + + return exc_content + def runlines(self, lines, clean=False): + return InteractiveShell.runlines(self, lines, clean) + +InteractiveShellABC.register(ZMQInteractiveShell)