Architecture

Overview

pgwidgets follows a client-server architecture. Python is the server; the browser is the client. Widget constructors and method calls in Python are translated to JSON messages and sent over WebSocket to the browser, where the pgwidgets JavaScript library executes them. User interactions (clicks, input, etc.) travel back as callback messages.

Python (server)                     Browser (client)
+-----------------+                 +------------------+
| Application     |   WebSocket    | pgwidgets JS     |
|   Session  <----|----JSON------->|   widget tree     |
|     widgets     |                |   DOM rendering   |
+-----------------+                +------------------+
       |
       | HTTP (static files)
       v
JS/CSS assets served to browser

Servers

The Application class starts two servers:

HTTP server (default port 9501)

Serves the pgwidgets JavaScript/CSS assets and a connector HTML page. When a browser hits /, it gets remote.html with the WebSocket URL injected. Set http_server=False if you serve the static files from your own web server (Flask, FastAPI, nginx, etc.).

WebSocket server (default port 9500)

Carries the JSON command protocol. Each browser tab opens one WebSocket connection, which becomes one Session.

JSON Protocol

All messages are JSON objects with a type field.

Python -> Browser:

  • {"type": "init", "id": 0} – reset the browser to a clean slate.

  • {"type": "create", "wid": 1, "class": "Button", "args": ["Click"]} – create a widget.

  • {"type": "call", "wid": 1, "method": "set_text", "args": ["New"]} – call a method on a widget.

  • {"type": "listen", "wid": 1, "action": "activated"} – subscribe to a callback.

  • {"type": "unlisten", "wid": 1, "action": "activated"} – unsubscribe.

Browser -> Python:

  • {"type": "result", "id": 1, "value": ...} – method return value.

  • {"type": "error", "id": 1, "error": "..."} – method error.

  • {"type": "callback", "wid": 1, "action": "activated", "args": [...]} – user interaction.

  • {"type": "file-chunk", ...} – chunked file data (see Callback System).

Session Model

Each browser tab that connects gets its own Session object. The session owns:

  • A widget map (wid -> Python widget wrapper)

  • A callback registry ("wid:action" -> handler function)

  • A message-ID counter for request/response matching

Multiple sessions can be active concurrently (controlled by max_sessions).

Lifecycle:

  1. Browser opens the URL and loads remote.html.

  2. JavaScript connects to the WebSocket server.

  3. Python sends init; browser acknowledges.

  4. on_connect callback fires with the new Session.

  5. User code creates widgets, registers callbacks.

  6. When the browser tab closes, on_disconnect fires and the session is cleaned up.

Widget References

Widgets are identified by integer IDs (wid). When a Python widget is passed as an argument to another widget’s method (e.g., vbox.add_widget(btn, 0)), the framework automatically converts the Python Widget object to a {"__wid__": N} reference on the wire, and converts it back on return values.