-
-
Notifications
You must be signed in to change notification settings - Fork 532
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Accept bytes-like objects #478
Comments
In fact |
>>> import io
>>> output = io.BytesIO()
>>> m = memoryview(b'binary payload')
>>> output.write(m)
14
>>> output.write(m[2:10:3])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
BufferError: memoryview: underlying buffer is not C-contiguous Let's leave users call |
I thought this would do the job: diff --git a/src/websockets/framing.py b/src/websockets/framing.py
index afbc664..c393f79 100644
--- a/src/websockets/framing.py
+++ b/src/websockets/framing.py
@@ -245,10 +245,10 @@ def encode_data(data):
# Expect str or bytes, return bytes.
if isinstance(data, str):
return data.encode('utf-8')
- elif isinstance(data, bytes):
+ elif isinstance(data, collections.abc.ByteString):
return data
else:
- raise TypeError("data must be bytes or str")
+ raise TypeError("data must be bytes-like or str")
def parse_close(data):
diff --git a/src/websockets/protocol.py b/src/websockets/protocol.py
index 6e15853..14893e7 100644
--- a/src/websockets/protocol.py
+++ b/src/websockets/protocol.py
@@ -446,7 +446,7 @@ class WebSocketCommonProtocol(asyncio.StreamReaderProtocol):
if isinstance(data, str):
yield from self.write_frame(True, OP_TEXT, data.encode('utf-8'))
- elif isinstance(data, bytes):
+ elif isinstance(data, collections.abc.ByteString):
yield from self.write_frame(True, OP_BINARY, data)
# Fragmented message -- regular iterator.
@@ -463,7 +463,7 @@ class WebSocketCommonProtocol(asyncio.StreamReaderProtocol):
if isinstance(data, str):
yield from self.write_frame(False, OP_TEXT, data.encode('utf-8'))
encode_data = True
- elif isinstance(data, bytes):
+ elif isinstance(data, collections.abc.ByteString):
yield from self.write_frame(False, OP_BINARY, data)
encode_data = False
else:
diff --git a/tests/test_framing.py b/tests/test_framing.py
index ee85157..fb43b25 100644
--- a/tests/test_framing.py
+++ b/tests/test_framing.py
@@ -158,6 +158,9 @@ class FramingTests(unittest.TestCase):
def test_encode_data_bytes(self):
self.assertEqual(encode_data(b'tea'), b'tea')
+ def test_encode_data_bytearray(self):
+ self.assertEqual(encode_data(b'tea'), bytearray(b'tea'))
+
def test_encode_data_other(self):
with self.assertRaises(TypeError):
encode_data(None)
diff --git a/tests/test_protocol.py b/tests/test_protocol.py
index d9aea19..1180ebd 100644
--- a/tests/test_protocol.py
+++ b/tests/test_protocol.py
@@ -471,6 +471,10 @@ class CommonTests:
self.loop.run_until_complete(self.protocol.send(b'tea'))
self.assertOneFrameSent(True, OP_BINARY, b'tea')
+ def test_send_binary_from_bytearray(self):
+ self.loop.run_until_complete(self.protocol.send(bytearray(b'tea')))
+ self.assertOneFrameSent(True, OP_BINARY, b'tea')
+
def test_send_type_error(self):
with self.assertRaises(TypeError):
self.loop.run_until_complete(self.protocol.send(42))
@@ -490,6 +494,14 @@ class CommonTests:
(False, OP_BINARY, b'te'), (False, OP_CONT, b'a'), (True, OP_CONT, b'')
)
+ def test_send_iterable_binary_from_bytearray(self):
+ self.loop.run_until_complete(
+ self.protocol.send([bytearray(b'te'), bytearray(b'a')])
+ )
+ self.assertFramesSent(
+ (False, OP_BINARY, b'te'), (False, OP_CONT, b'a'), (True, OP_CONT, b'')
+ )
+
def test_send_empty_iterable(self):
self.loop.run_until_complete(self.protocol.send([]))
self.assertNoFrameSent() Alas:
|
I'd have to use a Since this discussion started from a rather theoretical "it would be nice if...", I'm not convinced it's worth putting a lot of effort into this change. |
I was exploring using bytearray and memoryview to minimize memory copies, which led me to implement this. This use case only involves C-contiguous memoryviews. For non-C-contiguous memoryviews, making a copy is inevitable, so we can simply use |
Minimize memory copies when they're C-contiguous. Fix #478.
Minimize memory copies when they're C-contiguous. Fix #478.
Minimize memory copies when they're C-contiguous. Fix #478.
Minimize memory copies when they're C-contiguous. Fix #478.
isinstance(thing, collections.abc.ByteString)
likely beatsisinstance(thing, bytes)
.We just need to make sure that it doesn't require any other changes.
Suggested by @cjerdonek in #296 (comment).
The text was updated successfully, but these errors were encountered: