Hello,
I've found an issue with emitting binary data using Test Client. Is there a way that I can use it in tests? As far as I looked into the code I found that this class always set binary argument to False. Why? Was it done on purpose?
Example use:
web_socket.test_client(app)
...
image = open('example_file.dcm', 'rb')
binary_data = image.read()
web_socket_client.emit('my_event', {'ref_id': 123, 'image': binary_data}, namespace='/my_namespace')
Example error:
venv/lib/python3.6/site-packages/flask_socketio/test_client.py:121: in emit
self.socketio.server._handle_eio_message(self.sid, pkt.encode())
venv/lib/python3.6/site-packages/socketio/packet.py:71: in encode
encoded_packet += self.json.dumps(data, separators=(',', ':'))
/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/__init__.py:238: in dumps
**kw).encode(obj)
/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py:199: in encode
chunks = self.iterencode(o, _one_shot=True)
/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py:257: in iterencode
return _iterencode(o, 0)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <json.encoder.JSONEncoder object at 0x1109da6a0>
o = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00...00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
def default(self, o):
"""Implement this method in a subclass such that it returns
a serializable object for ``o``, or calls the base implementation
(to raise a ``TypeError``).
For example, to support arbitrary iterators, you could
implement default like this::
def default(self, o):
try:
iterable = iter(o)
except TypeError:
pass
else:
return list(iterable)
# Let the base class default method raise the TypeError
return JSONEncoder.default(self, o)
"""
raise TypeError("Object of type '%s' is not JSON serializable" %
> o.__class__.__name__)
E TypeError: Object of type 'bytes' is not JSON serializable
/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py:180: TypeError
FYI: I can properly send binary data from the JS level but I cannot manage Flask-SocketIO itself to be used during testing.
Does anybody managed to workaround this issue somehow or tried to resolve this bug? Maybe am I using it wrong?
I'll look into it, seems like it was an oversight on my part.
Did you find out where the root cause of this issue is? I've tried to fix it on myself but I don鈥檛 have enough knowledge about this library, so I failed :(
Let me know if I could help somehow as this is blocking tests on my project.
@jpowie01 Can I ask you to retest your application with the master branch in this repo? I think binary packets should work now.
Thank you very much for such quick help :) It works properly!
But I've got another concern. I've used Test Client like above:
web_socket_client = web_socket.test_client(app)
...
image = open('example_file.dcm', 'rb')
binary_data = image.read()
web_socket_client.emit('my_event', {'ref_id': 123, 'image': binary_data}, namespace='/my_namespace')
assert web_socket_client.get_received(namespace='/my_namespace')
... and it failed. I've checked the queue inside of the Test Client and it was empty:
>>> print(web_socket_client.queue)
{'a40cc08de24348c9a0acc957cf9a7da4': []}
But the logs show me that some message has been sent:
------------------------------------------------ Captured stderr call ------------------------------------------------
received event "my_event" from a40cc08de24348c9a0acc957cf9a7da4 [/my_namespace]
emitting event "my_response" to a40cc08de24348c9a0acc957cf9a7da4 [/my_namespace]
Code used for handling such event looks like this:
class MyEventNamespace(Namespace):
def on_my_event(self, request: Dict) -> None:
...
emit('my_response', {'data': some_data})
web_socket.on_namespace(MyEventNamespace('/my_namespace'))
My solution to this problem was to change the client to work on a specific namespace like this:
web_socket_client = web_socket.test_client(app, namespace='/my_namespace')
...and it works! I've received this message and I could find it on the queue.
Do I have to create Test Client for each of my namespaces? Or is it another bug? Maybe is it a proper behaviour? Could you expain what happened here?
Yes, you have to think of the test client in the same way you use a real client. When you create the test client, it "connects" to the server, using the namespace provided. In the most common case the arguments that you pass to the test_client() function are passed directly to connect(), so you definitely need to pass the namespace there.
As a side note, you can call connect() directly if you want, even call it multiple times to connect multiple namespaces.
Cool! Thanks for help :)