Where assert statements are guarding against invalid ASGI messaging, use RuntimeError instead.
See original GitHub issueChecklist
- There are no similar issues or pull requests for this yet.
- I discussed this idea on the community chat and feedback is positive.
Is your feature related to a problem? Please describe.
There are assert
statements in the source code which raise a vague and hard to debug AssertionError
. For example on this line.
If some kind of exception (for example something along the lines of: WebSocketMessageType
) were raised it would make debugging a lot clearer. I spent a lot more time than I should have just working out where exactly this AssertionError
was coming from and what the root cause was.
Describe the solution you would like.
This is by no means the right solution but at least it’s an idea of the kind of thing that might help:
class WebSocketMessageType(Exception):
pass
class WebSocket(HTTPConnection):
...
async def send(self, message: Message) -> None:
"""
Send ASGI websocket messages, ensuring valid state transitions.
"""
if self.application_state == WebSocketState.CONNECTING:
message_type = message["type"]
if message_type not in {"websocket.accept", "websocket.close"}:
raise WebSocketMessageType("expected message_type to be websocket.accept or websocket.close")
if message_type == "websocket.close":
self.application_state = WebSocketState.DISCONNECTED
else:
self.application_state = WebSocketState.CONNECTED
await self._send(message)
elif self.application_state == WebSocketState.CONNECTED:
message_type = message["type"]
if message_type not in {"websocket.send", "websocket.close"}:
raise WebSocketMessageType("expected message_type to be websocket.send or websocket.close")
if message_type == "websocket.close":
self.application_state = WebSocketState.DISCONNECTED
await self._send(message)
else:
raise RuntimeError('Cannot call "send" once a close message has been sent.')
Describe alternatives you considered
No response
Additional context
The error I was seeing:
ERROR root:a_file.py:31 {'message': 'Job processing failed', 'job': <Job coro=<<coroutine object a_class.a_method at 0x7f6d7a7c1ec0>>>, 'exception': AssertionError()}
NoneType: None
And this would be it with a raise
statement: admittedly there is still no mention of starlette
so a user would still have to diagnose that as the root cause.
ERROR root:a_file.py:31 {'message': 'Job processing failed', 'job': <Job coro=<<coroutine object a_class.a_method at 0x7fb99c2ed940>>>, 'exception': WebSocketMessageType('expected message_type to be websocket.accept or websocket.close')}
NoneType: None
Also, I have no idea where that NoneType: None
is coming from or what that means.
Issue Analytics
- State:
- Created 2 years ago
- Reactions:1
- Comments:6 (4 by maintainers)
Top GitHub Comments
Even in the case of such asserts, they ought to be accompanied with an appropriate error message (e.g.
assert False, "foo should not be happening"
)By all means, yup. Suggestion - keep it tightly scoped - just consider
websockets.py
in your pull request. (We con look at if there’s other cases as a follow-up)