Metadata-Version: 2.4
Name: pgwidgets-python
Version: 0.2.0
Summary: Python bindings for the pgwidgets JavaScript widget library
Author: PGWidgets Developers
License: BSD-3-Clause
Project-URL: Homepage, https://github.com/naojsoft/pgwidgets-python
Project-URL: Repository, https://github.com/naojsoft/pgwidgets-python
Keywords: widgets,ui,gui,websocket,browser
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: User Interfaces
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE.md
Requires-Dist: pgwidgets-js
Requires-Dist: websockets>=12
Provides-Extra: dev
Requires-Dist: sphinx; extra == "dev"
Requires-Dist: furo; extra == "dev"
Requires-Dist: sphinx-autodoc-typehints; extra == "dev"
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Dynamic: license-file

# pgwidgets — Python Bindings

Python bindings for the [pgwidgets](https://github.com/naojsoft/pgwidgets-js)
JavaScript widget library. Build desktop-style browser UIs from Python
with a familiar Qt/GTK-style API.

## Documentation

Full documentation is available at
[pgwidgets-python.readthedocs.io](https://pgwidgets-python.readthedocs.io/en/latest/).

## Installation

```bash
pip install pgwidgets-python
```

This will also install `pgwidgets-js` (the JavaScript assets) and
`websockets` as dependencies.

## Quick Start

```python
from pgwidgets.sync import Application

app = Application()

@app.on_connect
def setup(session):
    Widgets = session.get_widgets()

    top = Widgets.TopLevel(title="Hello", resizable=True)
    top.resize(400, 300)

    vbox = Widgets.VBox(spacing=8, padding=10)
    btn = Widgets.Button("Click me")
    label = Widgets.Label("Ready")

    btn.on("activated", lambda: label.set_text("Clicked!"))

    vbox.add_widget(btn, 0)
    vbox.add_widget(label, 1)
    top.set_widget(vbox)
    top.show()

app.run()
```

Run the script, then open the printed URL in your browser.

## Sync vs Async

Both APIs provide the same widget classes and methods.

**Synchronous** (recommended for most use cases):
```python
from pgwidgets.sync import Application
app = Application()

@app.on_connect
def setup(session):
    Widgets = session.get_widgets()
    btn = Widgets.Button("Click")      # blocking call
    btn.set_text("New text")           # blocking call

app.run()
```

**Asynchronous** (for asyncio applications):
```python
from pgwidgets.async_ import Application
app = Application()

@app.on_connect
async def setup(session):
    Widgets = session.get_widgets()
    btn = await Widgets.Button("Click")    # awaitable
    await btn.set_text("New text")         # awaitable

await app.run()
```

## How It Works

The `Application` class starts two servers:
- An **HTTP server** (default port 9501) that serves the pgwidgets JS/CSS
  and a connector page
- A **WebSocket server** (default port 9500) for the JSON command protocol

When you open the URL in a browser, the page loads pgwidgets and connects
back over WebSocket. Python widget constructors and method calls are
translated to JSON messages and executed in the browser. Callbacks are
forwarded back to Python.

## Sessions and Reconnection

Sessions persist independently of browser connections. When a browser
disconnects (page refresh, network drop, tab close), the session and its
widget tree remain alive on the Python side. When the browser reconnects,
the entire UI is automatically reconstructed.

```python
app = Application(max_sessions=4, logger=logger)

@app.on_connect
def setup(session):
    Widgets = session.get_widgets()
    # Build your UI...
    # If the browser refreshes, this UI is reconstructed automatically.
```

**Key features:**

- **Automatic reconstruction** -- refresh the browser and the UI reappears
  in its current state (widget positions, text, slider values, etc.).
- **Multi-browser support** -- open the same session URL in a second browser
  tab or window. Both browsers show the same UI and stay synchronized.
  Widget state changes (slider moves, tab switches, tree expand/collapse)
  are pushed to all connected browsers in real time.
- **Headless sessions** -- create sessions without a browser using
  `app.create_session()`, build the widget tree, then connect a browser
  later to see the pre-built UI.

## License

BSD 3-Clause
