{"id":6434,"library":"pysignalr","title":"PySignalR Client","description":"pysignalr is a modern, reliable, and async-ready client for the SignalR protocol, designed to connect Python applications to SignalR hubs. It is currently at version 1.3.1 and maintains an active release cadence with regular updates and new feature additions, ensuring compatibility with the latest Python versions and SignalR protocol specifications.","status":"active","version":"1.3.1","language":"en","source_language":"en","source_url":"https://github.com/baking-bad/pysignalr","tags":["SignalR","websocket","async","client","real-time","asyncio"],"install":[{"cmd":"pip install pysignalr","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Core dependency for WebSocket communication, frequently updated.","package":"websockets","optional":false},{"reason":"Used for faster JSON deserialization, automatically detected if installed.","package":"orjson","optional":true}],"imports":[{"symbol":"SignalRClient","correct":"from pysignalr.client import SignalRClient"},{"symbol":"CompletionMessage","correct":"from pysignalr.messages import CompletionMessage"}],"quickstart":{"code":"import asyncio\nfrom contextlib import suppress\nfrom typing import Any, Dict, List\nfrom pysignalr.client import SignalRClient\nfrom pysignalr.messages import CompletionMessage\nimport os\n\nasync def on_open() -> None:\n    print('Connected to the server')\n\nasync def on_close() -> None:\n    print('Disconnected from the server')\n\nasync def on_message(message: List[Dict[str, Any]]) -> None:\n    print(f'Received message: {message}')\n\nasync def on_client_result(message: list[dict[str, Any]]) -> str:\n    print(f'Received message requesting result: {message}')\n    return 'reply_from_client'\n\nasync def on_error(message: CompletionMessage) -> None:\n    print(f'Received error: {message.error}')\n\nasync def main() -> None:\n    # Replace with your SignalR hub URL\n    # For example, a public API like TzKT.io or your own local/remote hub\n    signalr_url = os.environ.get('SIGNALR_HUB_URL', 'https://api.tzkt.io/v1/ws')\n    access_token = os.environ.get('SIGNALR_ACCESS_TOKEN', '') # Optional: for authenticated hubs\n\n    client_args = {'url': signalr_url}\n    if access_token:\n        # For authenticated hubs, provide an access token factory\n        client_args['access_token_factory'] = lambda: access_token\n\n    client = SignalRClient(**client_args)\n    client.on_open(on_open)\n    client.on_close(on_close)\n    client.on_error(on_error)\n\n    # Register handlers for specific events from the server\n    client.on('operations', on_message) # Example: subscribing to 'operations' event\n    client.on('client_result', on_client_result) # Example: handling a server request for a client result\n\n    await asyncio.gather(\n        client.run(),\n        # Example: Sending a message to the server (e.g., to subscribe to a topic)\n        client.send('SubscribeToOperations', [{}]), \n    )\n\nif __name__ == '__main__':\n    with suppress(KeyboardInterrupt, asyncio.CancelledError):\n        asyncio.run(main())\n","lang":"python","description":"This quickstart demonstrates how to establish a connection to a SignalR hub, register event handlers for incoming messages, and send messages to the server. It includes examples for connection lifecycle events (open, close, error) and handling specific server events, including those requesting a client result."},"warnings":[{"fix":"Upgrade Python to version 3.10 or newer. If unable to upgrade, pin `pysignalr` to a version prior to 1.3.0 (e.g., `pysignalr<1.3.0`).","message":"Python 3.9 support was officially dropped in `pysignalr` version 1.3.0. Users on Python 3.9 or older must upgrade their Python environment to at least 3.10 to use versions 1.3.0 and newer.","severity":"breaking","affected_versions":">=1.3.0"},{"fix":"Upgrade to `pysignalr` version 1.3.1 or newer to ensure full protocol compliance and stability.","message":"Version 1.3.1 introduced several fixes for SignalR Hub Protocol spec compliance in JSON and MessagePack codecs (e.g., `streamIds`, `invocationId`, `ResultKind`, headers, varint framing). Older versions might have exhibited non-compliant behavior that could lead to subtle issues or unexpected interactions with some SignalR servers.","severity":"gotcha","affected_versions":"<1.3.1"},{"fix":"Upgrade to `pysignalr` version 1.1.0 or newer to benefit from improved reconnection stability.","message":"Prior to version 1.1.0, the reconnection logic in `pysignalr` was prone to issues. Applications relying on stable and automatic reconnections in the face of network interruptions might experience unreliability in older versions.","severity":"gotcha","affected_versions":"<1.1.0"},{"fix":"Ensure exact matching of method names and parameter types/counts between server invocations and client `on()` handlers. Enable client-side logging (`logging.DEBUG`) to diagnose unhandled messages or errors.","message":"SignalR itself can silently fail to invoke client methods if the method name or signature sent from the server does not exactly match a registered client-side handler. The server will not receive an error.","severity":"gotcha","affected_versions":"All versions (SignalR protocol behavior)"},{"fix":"Adopt the `access_token_factory` for dynamic token management, especially with expiring JWTs, to ensure continuous authentication without manual re-connection.","message":"The `access_token_factory` argument was added in 1.1.0, allowing dynamic token generation for authentication. If you were using older, less flexible authentication methods or hardcoding tokens, you might need to refactor your authentication logic when upgrading to leverage this feature or if your token needs refreshing.","severity":"gotcha","affected_versions":"<1.1.0"}],"env_vars":null,"last_verified":"2026-04-15T00:00:00.000Z","next_check":"2026-07-14T00:00:00.000Z"}