Coverage for src/lexigram/web/websocket/decorators.py: 25%
16 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-25 04:37 +0800
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-25 04:37 +0800
1"""WebSocket Decorators.
3Provides decorators for marking classes as WebSocket handlers.
4"""
6from __future__ import annotations
8from typing import Any, cast
11def websocket_handler(
12 path: str,
13 *,
14 ping_interval: int | None = None,
15 ping_timeout: int | None = None,
16 max_connections_per_user: int | None = None,
17) -> Any:
18 """Decorator to mark a class as a WebSocket handler.
20 This decorator registers the handler class with the router
21 and configures the WebSocket path.
23 Args:
24 path: URL path for the WebSocket endpoint (can include path parameters)
25 ping_interval: Override default ping interval
26 ping_timeout: Override default ping timeout
27 max_connections_per_user: Override max connections per user
29 Example:
30 ```python
31 @websocket_handler("/ws/chat/{room}")
32 class ChatHandler(AbstractWebSocketHandler):
33 async def on_connect(self, websocket):
34 await websocket.accept()
35 await self.broadcast({"type": "join", "user": "..."})
37 async def on_message(self, websocket, message):
38 await self.broadcast(message)
40 async def on_disconnect(self, websocket):
41 await self.broadcast({"type": "leave", "user": "..."})
42 ```
43 """
45 def decorator(cls: type) -> type:
46 # Store route metadata on the class using setattr to satisfy mypy
47 cast("Any", cls)._ws_path = path
48 cast("Any", cls)._ws_metadata = {
49 "path": path,
50 "ping_interval": ping_interval,
51 "ping_timeout": ping_timeout,
52 "max_connections_per_user": max_connections_per_user,
53 }
55 # Override class attributes if provided
56 if ping_interval is not None:
57 cast("Any", cls).ping_interval = ping_interval
58 if ping_timeout is not None:
59 cast("Any", cls).ping_timeout = ping_timeout
60 if max_connections_per_user is not None:
61 cast("Any", cls).max_connections_per_user = max_connections_per_user
63 # Mark as WebSocket handler for router discovery
64 cast("Any", cls)._is_websocket_handler = True
66 return cls
68 return decorator
71__all__ = ["websocket_handler"]