{"id":19020034,"url":"https://github.com/py-zero/websocket-zero","last_synced_at":"2026-06-19T12:31:31.766Z","repository":{"id":91313694,"uuid":"251687706","full_name":"py-zero/websocket-zero","owner":"py-zero","description":"Zero-boilerplate websockets for Python","archived":false,"fork":false,"pushed_at":"2020-04-01T14:45:55.000Z","size":8,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-02T00:24:15.773Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/py-zero.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-03-31T17:59:07.000Z","updated_at":"2020-04-02T14:22:52.000Z","dependencies_parsed_at":null,"dependency_job_id":"d8b6497a-5fa6-4db1-bbbe-5ddb31edad1f","html_url":"https://github.com/py-zero/websocket-zero","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/py-zero%2Fwebsocket-zero","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/py-zero%2Fwebsocket-zero/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/py-zero%2Fwebsocket-zero/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/py-zero%2Fwebsocket-zero/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/py-zero","download_url":"https://codeload.github.com/py-zero/websocket-zero/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240064577,"owners_count":19742342,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-08T20:15:33.348Z","updated_at":"2026-04-28T05:30:17.458Z","avatar_url":"https://github.com/py-zero.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# websocket-zero\n\nZero-boilerplate websocket server/browser client for Python. This project is\ncurrently a proof-of-concept and the API is not stable.\n\nOf particular interest is what browser APIs should look like.\n\n\n## Pitch\n\nThe `wszero` module allows defining a server that responds to websocket\nmessages. Message encoding is handled by the framework using JSON. Messages\ncontain an opcode `op` that allows them to be routed to a handler, and carry a\npayload of arbitrary key-value pairs.\n\nwszero provides Python server that can exchange messages with many browser\nclients, and the browser stubs to send/receive messages from the server.\n\n\n## Python API\n\n### @on()\n\n`@on(op: str)`\n\nA decorator to create a handler for a particular opcode `op`.\n\nThe decorated function or async function should accept a first argument\n`client`, indicating the `Client` that sent the message. All other parameters\nmust be provided by the message, or contain a default argument.\n\nFor example, let's imagine a message type `announce`, which has a parameter\n`text` containing the announcement text and an optional `channel` parameter:\n\n```python\n\n@on('announce')\ndef handle_announce(client, text, channel=None):\n    ...\n\n```\n\nOr as a coroutine:\n\n```python\n\n@on('announce')\nasync def handle_announce(client, text, channel=None):\n    ...\n\n```\n\n### Special messages\n\nThere are two special messages `connect` and `disconnect` that can be\nregistered to be handled with `@on`. These have no parameters (the client is\nthe only parameter).\n\n### run_server()\n\n`run_server(port=8000)`\n\nLaunch the server, bound to all interfaces, on the port given. This function\ndoes not return until the server exits, so should be called at the end of your\nprogram.\n\n\n### Client\n\nEach connected client is represented by a `Client` object. Client objects have\na number of public methods:\n\n\n`Client.send(op: str, **params)`\n\nSend a message to this client only.\n\n\n`Client.eval_js(script: str)`\n\nExecute some Javascript code in the browser.\n\n\n### Groups and broadcasting\n\nA single message can be broadcast to many or all connected clients. A system\nof groups is used to select clients to send to.\n\n`broadcast(op, [group], **params)`\n\nBroadcast a message, with opcode `op`, to all clients in a group. If no group\nis given, then broadcast to all connected clients.\n\n\n`Client.groups`\n\nThe set of groups that this client is in.\n\n`Client.add_to_group(group: str)`\n\nAdd the client to a broadcast group named by `group`. This is idempotent, so\nwill do nothing if the client is already a member of the group.\n\n`Client.remove_from_group(group: str)`\n\nRemove the group from the broadcast group given. This is idempotent, so will\ndo nothing if the client is not a member of the group.\n\n\n## Javascript API\n\n`window.HANDLERS`\n\nA mapping of opcode to the function that should be called when a given opcode\nis received. The functions are called with a single parameter, which is the\nmapping of parameter associated with the message, including the opcode `op`.\n\n`window.send_message(msg)`\n\nSend a websocket message to the server. `msg` must be an Object containing an\nattribute `op`.\n\n\n## Goals\n\n1. Be simple enough for schoolchildren of around 10 or 11 to use. We must\n   minimise the typing required, and minimise the amount of knowledge needed to\n   use the system.\n2. Be a modern Python asyncio framework. But do not require deep asyncio\n   knowledge from a user perspective.\n3. Do not reinvent client-side technologies. It should be possible to write the\n   client side in Javascript using React or Vue, even if wszero offers its own\n   shortcuts.\n4. Do not become server-driven. The temptation for \"easy\" Python websocket\n   frameworks is to drive all logic from the server. The browser becomes merely\n   a UI host. The server sends widgets to the browser and the browser sends all\n   its events over the wire. I've seen this pattern implemented a couple of\n   times (including by myself for [an MMO]). It works, but with major\n   downsides such as latency. Where the server holds significant per-client\n   state, this reduces scalability.\n\n[an MMO]: https://github.com/lordmauve/dark-world\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpy-zero%2Fwebsocket-zero","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpy-zero%2Fwebsocket-zero","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpy-zero%2Fwebsocket-zero/lists"}