diff --git a/IPython/html/base/zmqhandlers.py b/IPython/html/base/zmqhandlers.py index f1159e8..5ddb5d2 100644 --- a/IPython/html/base/zmqhandlers.py +++ b/IPython/html/base/zmqhandlers.py @@ -8,6 +8,7 @@ import os import json import struct import warnings +import sys try: from urllib.parse import urlparse # Py 3 @@ -43,6 +44,8 @@ def serialize_binary_message(msg): # don't modify msg or buffer list in-place msg = msg.copy() buffers = list(msg.pop('buffers')) + if sys.version_info < (3, 4): + buffers = [x.tobytes() for x in buffers] bmsg = json.dumps(msg, default=date_default).encode('utf8') buffers.insert(0, bmsg) nbufs = len(buffers) diff --git a/IPython/html/tests/test_serialize.py b/IPython/html/tests/test_serialize.py index 7a88b29..9d45d6b 100644 --- a/IPython/html/tests/test_serialize.py +++ b/IPython/html/tests/test_serialize.py @@ -13,14 +13,14 @@ from ..base.zmqhandlers import ( def test_serialize_binary(): s = Session() msg = s.msg('data_pub', content={'a': 'b'}) - msg['buffers'] = [ os.urandom(3) for i in range(3) ] + msg['buffers'] = [ memoryview(os.urandom(3)) for i in range(3) ] bmsg = serialize_binary_message(msg) nt.assert_is_instance(bmsg, bytes) def test_deserialize_binary(): s = Session() msg = s.msg('data_pub', content={'a': 'b'}) - msg['buffers'] = [ os.urandom(2) for i in range(3) ] + msg['buffers'] = [ memoryview(os.urandom(2)) for i in range(3) ] bmsg = serialize_binary_message(msg) msg2 = deserialize_binary_message(bmsg) nt.assert_equal(msg2, msg) diff --git a/IPython/kernel/zmq/session.py b/IPython/kernel/zmq/session.py index c13ce0a..85d1fef 100644 --- a/IPython/kernel/zmq/session.py +++ b/IPython/kernel/zmq/session.py @@ -810,18 +810,19 @@ class Session(Configurable): Whether to unpack the content dict (True), or leave it packed (False). copy : bool (True) - Whether to return the bytes (True), or the non-copying Message - object in each place (False). + Whether msg_list contains bytes (True) or the non-copying Message + objects in each place (False). Returns ------- msg : dict The nested message dict with top-level keys [header, parent_header, - content, buffers]. + content, buffers]. The buffers are returned as memoryviews. """ minlen = 5 message = {} if not copy: + # pyzmq didn't copy the first parts of the message, so we'll do it for i in range(minlen): msg_list[i] = msg_list[i].bytes if self.auth is not None: @@ -846,8 +847,11 @@ class Session(Configurable): message['content'] = self.unpack(msg_list[4]) else: message['content'] = msg_list[4] - - message['buffers'] = msg_list[5:] + buffers = [memoryview(b) for b in msg_list[5:]] + if buffers and buffers[0].shape is None: + # force copy to workaround pyzmq #646 + buffers = [memoryview(b.bytes) for b in msg_list[5:]] + message['buffers'] = buffers # adapt to the current version return adapt(message)