Merge pull request #5067 from minrk/widget-error

show traceback in widget handlers
This commit is contained in:
Brian E. Granger 2014-02-08 11:16:02 -08:00
commit 47abe842b2
2 changed files with 28 additions and 2 deletions

View File

@ -20,6 +20,7 @@ except ImportError:
from IPython.utils.signatures import signature, Parameter from IPython.utils.signatures import signature, Parameter
from inspect import getcallargs from inspect import getcallargs
from IPython.core.getipython import get_ipython
from IPython.html.widgets import (Widget, TextWidget, from IPython.html.widgets import (Widget, TextWidget,
FloatSliderWidget, IntSliderWidget, CheckboxWidget, DropdownWidget, FloatSliderWidget, IntSliderWidget, CheckboxWidget, DropdownWidget,
ContainerWidget, DOMWidget) ContainerWidget, DOMWidget)
@ -205,7 +206,14 @@ def interactive(__interact_f, **kwargs):
container.kwargs[widget.description] = value container.kwargs[widget.description] = value
if co: if co:
clear_output(wait=True) clear_output(wait=True)
container.result = f(**container.kwargs) try:
container.result = f(**container.kwargs)
except Exception as e:
ip = get_ipython()
if ip is None:
container.log.warn("Exception in interact callback: %s", e, exc_info=True)
else:
ip.showtraceback()
# Wire up the widgets # Wire up the widgets
for widget in kwargs_widgets: for widget in kwargs_widgets:

View File

@ -14,6 +14,7 @@ in the IPython notebook front-end.
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
from contextlib import contextmanager from contextlib import contextmanager
from IPython.core.getipython import get_ipython
from IPython.kernel.comm import Comm from IPython.kernel.comm import Comm
from IPython.config import LoggingConfigurable from IPython.config import LoggingConfigurable
from IPython.utils.traitlets import Unicode, Dict, Instance, Bool, List, Tuple from IPython.utils.traitlets import Unicode, Dict, Instance, Bool, List, Tuple
@ -33,7 +34,11 @@ class CallbackDispatcher(LoggingConfigurable):
try: try:
local_value = callback(*args, **kwargs) local_value = callback(*args, **kwargs)
except Exception as e: except Exception as e:
self.log.warn("Exception in callback %s: %s", callback, e) ip = get_ipython()
if ip is None:
self.log.warn("Exception in callback %s: %s", callback, e, exc_info=True)
else:
ip.showtraceback()
else: else:
value = local_value if local_value is not None else value value = local_value if local_value is not None else value
return value return value
@ -54,6 +59,18 @@ class CallbackDispatcher(LoggingConfigurable):
elif not remove and callback not in self.callbacks: elif not remove and callback not in self.callbacks:
self.callbacks.append(callback) self.callbacks.append(callback)
def _show_traceback(method):
"""decorator for showing tracebacks in IPython"""
def m(self, *args, **kwargs):
try:
return(method(self, *args, **kwargs))
except Exception as e:
ip = get_ipython()
if ip is None:
self.log.warn("Exception in widget method %s: %s", method, e, exc_info=True)
else:
ip.showtraceback()
return m
class Widget(LoggingConfigurable): class Widget(LoggingConfigurable):
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
@ -241,6 +258,7 @@ class Widget(LoggingConfigurable):
value != self._property_lock[1] value != self._property_lock[1]
# Event handlers # Event handlers
@_show_traceback
def _handle_msg(self, msg): def _handle_msg(self, msg):
"""Called when a msg is received from the front-end""" """Called when a msg is received from the front-end"""
data = msg['content']['data'] data = msg['content']['data']