You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: pywry/docs/docs/guides/app-show.md
+18-18Lines changed: 18 additions & 18 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,4 +1,4 @@
1
-
# The `app.show()` Method
1
+
# The app.show() Method
2
2
3
3
`app.show()` is the primary entry point for rendering content in PyWry. It accepts HTML (as a string or `HtmlContent` object), determines the correct rendering path for the current environment, and returns a handle you can use to interact with the result.
4
4
@@ -36,7 +36,7 @@ app.show(
36
36
37
37
## Parameters in Detail
38
38
39
-
### `content` — what to render
39
+
### content — what to render
40
40
41
41
Accepts either a plain HTML string or an `HtmlContent` object. When you pass a string, PyWry wraps it in a minimal document structure automatically. When you pass `HtmlContent`, you get control over CSS files, JS files, inline styles, JSON data injection, and hot reload watching. See the [HtmlContent guide](html-content.md) for details.
42
42
@@ -58,15 +58,15 @@ content = HtmlContent(
58
58
app.show(content)
59
59
```
60
60
61
-
### `title` — window title
61
+
### title — window title
62
62
63
63
Sets the title bar text in native window mode. Defaults to `"PyWry"`. Ignored in notebook and browser modes.
In native mode, `width` accepts an integer (pixels) for the OS window size. In notebook mode, `width` can also be a CSS string like `"100%"` or `"500px"`. `height` is always an integer (pixels).
Defaults come from `WindowConfig` — 1280×720 unless overridden in your configuration.
82
82
83
-
### `callbacks` — event handlers
83
+
### callbacks — event handlers
84
84
85
85
A dictionary mapping event names to Python callback functions. These are registered before the content is rendered, so they're ready to receive events immediately.
86
86
@@ -99,7 +99,7 @@ app.show(html, callbacks={
99
99
100
100
See the [Event System guide](events.md) for the full callback signature and registration patterns.
101
101
102
-
### `include_plotly` and `include_aggrid` — library loading
102
+
### include_plotly and include_aggrid — library loading
103
103
104
104
When `True`, PyWry injects the Plotly.js or AG Grid JavaScript and CSS libraries into the page. You don't need to set these manually if you use `app.show_plotly()` or `app.show_dataframe()` — they set the flags automatically.
In `MULTI_WINDOW` mode, the `label` identifies which window to create or update. In `SINGLE_WINDOW` mode, the label is fixed and this parameter is ignored. Labels are used in callbacks to target events back to a specific window.
app.emit("app:update", {"filter": data}, "chart") # target the chart window
128
128
```
129
129
130
-
### `watch` — hot reload
130
+
### watch — hot reload
131
131
132
132
When `True`, PyWry watches the CSS and JS files referenced by `HtmlContent.css_files` and `HtmlContent.script_files` for changes, and live-reloads them in the browser without a full page refresh.
133
133
@@ -142,7 +142,7 @@ app.show(content, watch=True) # or override here
142
142
143
143
See the [Hot Reload guide](hot-reload.md) for details.
144
144
145
-
### `toolbars` and `modals` — UI chrome
145
+
### toolbars and modals — UI chrome
146
146
147
147
Lists of `Toolbar` or `Modal` objects (or their dict equivalents) that wrap your content in an interactive layout. Toolbars are positioned around the content area; modals are hidden until triggered by events.
148
148
@@ -193,7 +193,7 @@ All implement the `BaseWidget` protocol, so `emit()` and `on()` work identically
193
193
194
194
`app.show()` is the general-purpose method. PyWry also provides specialized variants that configure the right options automatically:
195
195
196
-
### `app.show_plotly(figure, ...)`
196
+
### app.show_plotly(figure, ...)
197
197
198
198
Converts a Plotly figure to HTML, injects Plotly.js, and pre-wires chart events (`plotly:click`, `plotly:hover`, `plotly:selected`, `plotly:relayout`).
Converts a DataFrame to AG Grid HTML, injects the AG Grid library, and pre-wires grid events (`grid:cell-clicked`, `grid:selection-changed`, `grid:cell-edited`).
210
210
@@ -224,14 +224,14 @@ Both methods accept all the same optional parameters as `app.show()` (`title`, `
224
224
```mermaid
225
225
flowchart TD
226
226
A["app.show(content)"] --> B{"mode = BROWSER?"}
227
-
B -- Yes --> C["InlineWidget\nFastAPI + WebSocket\nopens system browser"]
227
+
B -- Yes --> C["InlineWidget<br>FastAPI + WebSocket<br>opens system browser"]
228
228
B -- No --> D{"In a notebook?"}
229
-
D -- Yes --> E{"include_plotly\nor include_aggrid?"}
230
-
E -- Yes --> F["InlineWidget\nIFrame + WebSocket\nspecialized JS"]
231
-
E -- No --> G{"anywidget\navailable?"}
232
-
G -- Yes --> H["PyWryWidget\nanywidget + traitlet sync"]
233
-
G -- No --> I["InlineWidget\nIFrame + WebSocket\nfallback"]
234
-
D -- No --> J["NativeWindowHandle\nPyTauri + OS webview"]
229
+
D -- Yes --> E{"include_plotly<br>or include_aggrid?"}
230
+
E -- Yes --> F["InlineWidget<br>IFrame + WebSocket<br>specialized JS"]
231
+
E -- No --> G{"anywidget<br>available?"}
232
+
G -- Yes --> H["PyWryWidget<br>anywidget + traitlet sync"]
233
+
G -- No --> I["InlineWidget<br>IFrame + WebSocket<br>fallback"]
234
+
D -- No --> J["NativeWindowHandle<br>PyTauri + OS webview"]
235
235
```
236
236
237
237
You can force a specific mode by setting it on the app:
Browser mode runs PyWry as a web server, opening content in your default browser instead of native windows.
3
+
Browser mode runs PyWry without native OS windows. Instead, it starts a local web server and opens your content in the system browser. All communication between Python and JavaScript happens over WebSocket.
4
4
5
-
## When to Use
5
+
## When to Use Browser Mode
6
6
7
-
-**SSH/Remote access** — No GUI available
8
-
-**Cross-platform sharing** — Share via URL
9
-
-**Development** — Use browser DevTools
7
+
| Scenario | Why browser mode helps |
8
+
|:---|:---|
9
+
| SSH / remote server | No display server available |
10
+
| Docker / CI containers | No GUI libraries installed |
11
+
| WSL | Native windows can't reach the Linux display |
12
+
| Cross-browser testing | Use browser DevTools directly |
13
+
| Sharing with others | Send a URL instead of installing an app |
10
14
11
-
## Enable Browser Mode
15
+
## Enabling Browser Mode
12
16
13
-
### Programmatic
17
+
### In Code
14
18
15
19
```python
16
20
from pywry import PyWry, WindowMode
17
21
18
22
app = PyWry(mode=WindowMode.BROWSER)
19
23
handle = app.show("<h1>Hello Browser!</h1>")
20
-
21
-
app.block() # Keep server running
24
+
app.block() # Keeps the server running
22
25
```
23
26
24
-
### Environment Variable
27
+
### Via Environment Variable
25
28
26
29
```bash
27
30
export PYWRY_WINDOW__MODE=browser
28
31
python my_app.py
29
32
```
30
33
34
+
### Via Config File
35
+
36
+
```toml
37
+
# pywry.toml
38
+
[window]
39
+
mode = "browser"
40
+
```
41
+
31
42
## How It Works
32
43
33
-
1. PyWry starts a FastAPI server with WebSocket support
34
-
2. Content is served at `http://localhost:8765/widget/{label}`
35
-
3. Browser opens automatically
36
-
4. WebSocket maintains bidirectional communication
44
+
When you call `app.show()` in browser mode:
45
+
46
+
1.**Server starts** — A FastAPI + uvicorn server launches in a background daemon thread (once, on first `show()`)
47
+
2.**Widget registers** — The rendered HTML is stored in the server's widget registry, keyed by label
48
+
3.**Browser opens** — The system default browser navigates to `http://127.0.0.1:8765/widget/{label}`
49
+
4.**WebSocket connects** — The page's JavaScript bridge opens a WebSocket back to the server for bidirectional events
50
+
5.**Events flow** — `window.pywry.emit()` in the browser sends JSON over WebSocket to Python; `handle.emit()` in Python pushes JSON back
51
+
52
+
### Server Routes
53
+
54
+
| Route | Method | Description |
55
+
|:---|:---|:---|
56
+
|`/widget/{widget_id}`| GET | Serves the widget's HTML page |
When SSL is configured, widget URLs use `https://` and WebSocket connections use `wss://`.
139
+
95
140
## WebSocket Security
96
141
97
-
Enable per-widget authentication tokens:
142
+
By default, each widget gets a unique token generated with `secrets.token_urlsafe(32)`. The browser sends this token via the `Sec-WebSocket-Protocol` header during the WebSocket handshake. Connections without a valid token are rejected.
`app.block()` in browser mode monitors WebSocket connections. It returns when all widgets have disconnected (i.e., every browser tab has been closed or navigated away):
188
+
189
+
```python
190
+
app.show(content)
191
+
app.block() # Waits until all browser tabs close
192
+
# Code continues after disconnect
193
+
```
194
+
195
+
Press `Ctrl+C` to stop immediately — PyWry calls `app.destroy()` to shut down the server cleanly.
196
+
197
+
## Relationship to Deploy Mode
105
198
106
-
For production deployments with multiple workers, see[Deploy Mode](deploy-mode.md).
199
+
Browser mode runs the server in a **background thread** alongside your script. For **production** deployments where the server _is_ your application, use[Deploy Mode](deploy-mode.md) instead — it runs uvicorn in the foreground with multi-worker support, Redis state, and proper process management.
Copy file name to clipboardExpand all lines: pywry/docs/docs/guides/content-assembly.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -24,7 +24,7 @@ Here's what happens when `app.show(content)` is called in native window mode (th
24
24
6. Assemble final HTML document
25
25
7. Send to rendering path (native / notebook / browser)
26
26
27
-
## What Goes Into `<head>`
27
+
## What Goes Into <head>
28
28
29
29
The `<head>` section is built from these components, injected in this exact order:
30
30
@@ -153,7 +153,7 @@ Each file in `HtmlContent.script_files` is injected as a `<script>` tag.
153
153
154
154
`HtmlContent.init_script` runs last — it's the final `<script>` tag in the document. By the time it executes, everything else is available: `window.pywry`, `window.json_data`, all CSS applied, all libraries loaded.
0 commit comments