Skip to content

Commit

Permalink
Merge pull request #906 from ioam/streams_traceback
Browse files Browse the repository at this point in the history
Improved error reporting on comms
  • Loading branch information
jlstevens committed Oct 6, 2016
2 parents 670e1aa + 9cb1f14 commit 02f6f32
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 3 deletions.
3 changes: 3 additions & 0 deletions holoviews/plotting/bokeh/callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ class Callback(object):
var comm = HoloViewsWidget.comms["{comms_target}"];
var comm_state = HoloViewsWidget.comm_state["{comms_target}"];
if (msg.msg_type == "Ready") {{
if (msg.content) {{
console.log("Python callback returned following output:", msg.content);
}}
if (comm_state.event) {{
comm.send(comm_state.event);
}} else {{
Expand Down
48 changes: 45 additions & 3 deletions holoviews/plotting/comms.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,38 @@
import json
import uuid
import sys
import os
import traceback
try:
from StringIO import StringIO
except:
from io import StringIO

from ipykernel.comm import Comm as IPyComm
from IPython import get_ipython


class StandardOutput(list):
"""
Context manager to capture standard output for any code it
is wrapping and make it available as a list, e.g.:
>>> with StandardOutput() as stdout:
... print('This gets captured')
>>> print(stdout[0])
This gets captured
"""

def __enter__(self):
self._stdout = sys.stdout
sys.stdout = self._stringio = StringIO()
return self

def __exit__(self, *args):
self.extend(self._stringio.getvalue().splitlines())
sys.stdout = self._stdout


class Comm(object):
"""
Comm encompasses any uni- or bi-directional connection between
Expand Down Expand Up @@ -70,12 +98,26 @@ def _handle_msg(self, msg):
if it has been defined.
"""
try:
stdout = []
msg = self.decode(msg)
if self._on_msg:
self._on_msg(self.decode(msg))
# Comm swallows standard output so we need to capture
# it and then send it to the frontend
with StandardOutput() as stdout:
self._on_msg(msg)
except Exception as e:
msg = {'msg_type': "Error", 'traceback': str(e)}
frame =traceback.extract_tb(sys.exc_info()[2])[-2]
fname,lineno,fn,text = frame
error_kwargs = dict(type=type(e).__name__, fn=fn, fname=fname,
line=lineno, error=str(e))
error = '{fname} {fn} L{line}\n\t{type}: {error}'.format(**error_kwargs)
if stdout:
stdout = '\n\t'+'\n\t'.join(stdout)
error = '\n'.join([stdout, error])
msg = {'msg_type': "Error", 'traceback': error}
else:
msg = {'msg_type': "Ready"}
stdout = '\n\t'+'\n\t'.join(stdout) if stdout else ''
msg = {'msg_type': "Ready", 'content': stdout}
self.comm.send(json.dumps(msg))


Expand Down

0 comments on commit 02f6f32

Please sign in to comment.