From a04b264299a2ad1e9dab35d093ff0043e429986a Mon Sep 17 00:00:00 2001 From: OSC Agent Date: Mon, 23 Mar 2026 02:17:17 +0800 Subject: [PATCH] Add is_disconnected property to WebSocket --- starlette/websockets.py | 7 +++++++ tests/test_websockets.py | 15 +++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/starlette/websockets.py b/starlette/websockets.py index 3ab709a30..397690b93 100644 --- a/starlette/websockets.py +++ b/starlette/websockets.py @@ -32,6 +32,13 @@ def __init__(self, scope: Scope, receive: Receive, send: Send) -> None: self.client_state = WebSocketState.CONNECTING self.application_state = WebSocketState.CONNECTING + @property + def is_disconnected(self) -> bool: + return ( + self.client_state == WebSocketState.DISCONNECTED + or self.application_state == WebSocketState.DISCONNECTED + ) + async def receive(self) -> Message: """ Receive ASGI websocket messages, ensuring valid state transitions. diff --git a/tests/test_websockets.py b/tests/test_websockets.py index 7ffd1f231..ccb3738a8 100644 --- a/tests/test_websockets.py +++ b/tests/test_websockets.py @@ -651,3 +651,18 @@ async def app(scope: Scope, receive: Receive, send: Send) -> None: with pytest.raises(RuntimeError): with client.websocket_connect("/") as websocket: websocket.send({"type": "websocket.connect"}) + + +def test_is_disconnected_property(test_client_factory: TestClientFactory) -> None: + async def app(scope: Scope, receive: Receive, send: Send) -> None: + websocket = WebSocket(scope, receive=receive, send=send) + assert not websocket.is_disconnected + await websocket.accept() + assert not websocket.is_disconnected + message = await websocket.receive() + websocket.client_state = WebSocketState.DISCONNECTED + assert websocket.is_disconnected + + client = test_client_factory(app) + with client.websocket_connect("/") as websocket: + websocket.send_json({"close": True})