From 63c1460ad09f3b90165b7a54c7aea6484f0ebf4a Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Wed, 5 Oct 2016 23:36:12 +0100
Subject: [PATCH 1/7] Improved error reporting on comms
---
holoviews/plotting/comms.py | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/holoviews/plotting/comms.py b/holoviews/plotting/comms.py
index d9d73440cd..1ab82a3ce8 100644
--- a/holoviews/plotting/comms.py
+++ b/holoviews/plotting/comms.py
@@ -1,5 +1,8 @@
import json
import uuid
+import sys
+import os
+import traceback
from ipykernel.comm import Comm as IPyComm
from IPython import get_ipython
@@ -70,10 +73,16 @@ def _handle_msg(self, msg):
if it has been defined.
"""
try:
+ msg = self.decode(msg)
if self._on_msg:
- self._on_msg(self.decode(msg))
+ 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)
+ msg = {'msg_type': "Error", 'traceback': error}
else:
msg = {'msg_type': "Ready"}
self.comm.send(json.dumps(msg))
From 8ab54e98e13f9f1b882e4348ef2b2b40efe10e75 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Thu, 6 Oct 2016 02:49:19 +0100
Subject: [PATCH 2/7] Comms capture standard output and print it to the console
---
holoviews/plotting/bokeh/callbacks.py | 3 +++
holoviews/plotting/comms.py | 21 ++++++++++++++++++---
2 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/holoviews/plotting/bokeh/callbacks.py b/holoviews/plotting/bokeh/callbacks.py
index bda3bf1218..83bf78414a 100644
--- a/holoviews/plotting/bokeh/callbacks.py
+++ b/holoviews/plotting/bokeh/callbacks.py
@@ -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 {{
diff --git a/holoviews/plotting/comms.py b/holoviews/plotting/comms.py
index 1ab82a3ce8..22b998ce27 100644
--- a/holoviews/plotting/comms.py
+++ b/holoviews/plotting/comms.py
@@ -3,11 +3,22 @@
import sys
import os
import traceback
+from cStringIO import StringIO
from ipykernel.comm import Comm as IPyComm
from IPython import get_ipython
+class Capturing(list):
+ 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
@@ -73,18 +84,22 @@ def _handle_msg(self, msg):
if it has been defined.
"""
try:
+ stdout = ''
msg = self.decode(msg)
if self._on_msg:
- self._on_msg(msg)
+ with Capturing() as stdout:
+ self._on_msg(msg)
except Exception as 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))
+ stdout = '\n\t'+'\n\t'.join(stdout)
error = '{fname} {fn} L{line}\n\t{type}: {error}'.format(**error_kwargs)
- msg = {'msg_type': "Error", 'traceback': error}
+ msg = {'msg_type': "Error", 'traceback': '\n'.join([stdout, error])}
else:
- msg = {'msg_type': "Ready"}
+ stdout = '\n\t'+'\n\t'.join(stdout)
+ msg = {'msg_type': "Ready", 'content': stdout}
self.comm.send(json.dumps(msg))
From c20051a6f4c58add06eac472ab31bcae86d2c792 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Thu, 6 Oct 2016 03:09:50 +0100
Subject: [PATCH 3/7] Python3 fixes for Comm stdout handling
---
holoviews/plotting/comms.py | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/holoviews/plotting/comms.py b/holoviews/plotting/comms.py
index 22b998ce27..6bf34ca5a1 100644
--- a/holoviews/plotting/comms.py
+++ b/holoviews/plotting/comms.py
@@ -3,7 +3,7 @@
import sys
import os
import traceback
-from cStringIO import StringIO
+from io import BytesIO
from ipykernel.comm import Comm as IPyComm
from IPython import get_ipython
@@ -12,7 +12,7 @@
class Capturing(list):
def __enter__(self):
self._stdout = sys.stdout
- sys.stdout = self._stringio = StringIO()
+ sys.stdout = self._stringio = BytesIO()
return self
def __exit__(self, *args):
self.extend(self._stringio.getvalue().splitlines())
@@ -84,7 +84,7 @@ def _handle_msg(self, msg):
if it has been defined.
"""
try:
- stdout = ''
+ stdout = []
msg = self.decode(msg)
if self._on_msg:
with Capturing() as stdout:
@@ -98,8 +98,9 @@ def _handle_msg(self, msg):
error = '{fname} {fn} L{line}\n\t{type}: {error}'.format(**error_kwargs)
msg = {'msg_type': "Error", 'traceback': '\n'.join([stdout, error])}
else:
- stdout = '\n\t'+'\n\t'.join(stdout)
- msg = {'msg_type': "Ready", 'content': stdout}
+ if stdout:
+ stdout = '\n\t'+'\n\t'.join(stdout)
+ msg = {'msg_type': "Ready", 'content': stdout if stdout else ''}
self.comm.send(json.dumps(msg))
From e2c55ec9ae06198da1fc68554b4a93af6e028273 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Thu, 6 Oct 2016 12:45:22 +0100
Subject: [PATCH 4/7] Cleaned up standard output capturing on Comm
---
holoviews/plotting/comms.py | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/holoviews/plotting/comms.py b/holoviews/plotting/comms.py
index 6bf34ca5a1..f07e1ead12 100644
--- a/holoviews/plotting/comms.py
+++ b/holoviews/plotting/comms.py
@@ -9,11 +9,22 @@
from IPython import get_ipython
-class Capturing(list):
+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 = BytesIO()
return self
+
def __exit__(self, *args):
self.extend(self._stringio.getvalue().splitlines())
sys.stdout = self._stdout
@@ -87,20 +98,21 @@ def _handle_msg(self, msg):
stdout = []
msg = self.decode(msg)
if self._on_msg:
- with Capturing() as stdout:
+ with StandardOutput() as stdout:
self._on_msg(msg)
except Exception as 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))
- stdout = '\n\t'+'\n\t'.join(stdout)
error = '{fname} {fn} L{line}\n\t{type}: {error}'.format(**error_kwargs)
- msg = {'msg_type': "Error", 'traceback': '\n'.join([stdout, error])}
- else:
if stdout:
stdout = '\n\t'+'\n\t'.join(stdout)
- msg = {'msg_type': "Ready", 'content': stdout if stdout else ''}
+ error = '\n'.join([stdout, error])
+ msg = {'msg_type': "Error", 'traceback': error}
+ else:
+ stdout = '\n\t'+'\n\t'.join(stdout) if stdout else ''
+ msg = {'msg_type': "Ready", 'content': stdout}
self.comm.send(json.dumps(msg))
From 96d6e0d1449d7487c228c62bda05030ef5b296e6 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Thu, 6 Oct 2016 12:58:54 +0100
Subject: [PATCH 5/7] Added comment to explain why stdout is captured in comms
---
holoviews/plotting/comms.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/holoviews/plotting/comms.py b/holoviews/plotting/comms.py
index f07e1ead12..2118aca71d 100644
--- a/holoviews/plotting/comms.py
+++ b/holoviews/plotting/comms.py
@@ -98,6 +98,8 @@ def _handle_msg(self, msg):
stdout = []
msg = self.decode(msg)
if self._on_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:
From c18b406305c02b553387a43d22e2c3e075181fe4 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Thu, 6 Oct 2016 13:43:42 +0100
Subject: [PATCH 6/7] Fixed StandardOutput doctest
---
holoviews/plotting/comms.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/holoviews/plotting/comms.py b/holoviews/plotting/comms.py
index 2118aca71d..99dc984db4 100644
--- a/holoviews/plotting/comms.py
+++ b/holoviews/plotting/comms.py
@@ -14,10 +14,10 @@ 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'
+ >>> with StandardOutput() as stdout:
+ ... print('This gets captured')
+ >>> print(stdout[0])
+ This gets captured
"""
def __enter__(self):
From 9cb1f144ce8bcfa2abcc9b1c22d50420fcc069b7 Mon Sep 17 00:00:00 2001
From: Philipp Rudiger
Date: Thu, 6 Oct 2016 14:14:20 +0100
Subject: [PATCH 7/7] Use StringIO to capture standard output
---
holoviews/plotting/comms.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/holoviews/plotting/comms.py b/holoviews/plotting/comms.py
index 99dc984db4..21044125f3 100644
--- a/holoviews/plotting/comms.py
+++ b/holoviews/plotting/comms.py
@@ -3,7 +3,10 @@
import sys
import os
import traceback
-from io import BytesIO
+try:
+ from StringIO import StringIO
+except:
+ from io import StringIO
from ipykernel.comm import Comm as IPyComm
from IPython import get_ipython
@@ -22,7 +25,7 @@ class StandardOutput(list):
def __enter__(self):
self._stdout = sys.stdout
- sys.stdout = self._stringio = BytesIO()
+ sys.stdout = self._stringio = StringIO()
return self
def __exit__(self, *args):