# H2O Lightwave
H2O Lightwave is a lightweight, pure-Python version of [H2O Wave](https://wave.h2o.ai/) that can be embedded in popular async web frameworks like FastAPI, Starlette, etc.
In other words, H2O Lightwave works without the Wave server.
The integration consists of 2 steps:
* Add Wave's web assets directory to your framework's static file handler.
* Add a webSocket handler, and use `wave_serve()` to connect Wave to your web UI.
That's it. You can now render UI elements using pure Python. Lightwave aims to be as minimal as possible and only provides:
* A simple way to render your UI.
* A simple way of capturing the user interactions (like button clicks, dropdown values etc.).
* Minimal state management.
Nothing more, nothing less.
Example FastAPI integration:
```py
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.staticfiles import StaticFiles
from h2o_lightwave import Q, ui, wave_serve
from h2o_lightwave_web import web_directory
# Lightwave callback function.
async def serve(q: Q):
# Paint our UI on the first page visit.
if not q.client.initialized:
# Create a local state.
q.client.count = 0
# Add a "card" with a text and a button
q.page['hello'] = ui.form_card(box='1 1 2 2', items=[
ui.text_xl('Hello world'),
ui.button(name='counter', label=f'Current count: {q.client.count}'),
])
q.client.initialized = True
# Handle counter button click.
if q.args.counter:
# Increment the counter.
q.client.count += 1
# Update the counter button.
q.page['hello'].items[1].button.label = f'Current count: {q.client.count}'
# Send the UI changes to the browser.
await q.page.save()
# Run: uvicorn hello_fastapi:app.
# FastAPI boilerplate.
app = FastAPI()
# FastAPI: WebSocket must be registered before index.html handler.
@app.websocket("/_s/")
async def ws(ws: WebSocket):
try:
await ws.accept()
await wave_serve(serve, ws.send_text, ws.receive_text)
await ws.close()
except WebSocketDisconnect:
print('Client disconnected')
app.mount("/", StaticFiles(directory=web_directory, html=True), name="/")
```
We also recommend reading the [blog post](https://medium.com/@unusualcode/h2o-lightwave-building-web-uis-with-fastapi-and-python-88a915383490) and other [integration examples](https://github.com/h2oai/wave/tree/main/py/h2o_lightwave/examples).
## Installation
```bash
pip install "h2o-lightwave[web]"
```
Lightwave requires websockets to function properly. Not all libraries come with them out of the box so you might need to install them additionally. For example, Starlette & FastAPI requires
```bash
pip install websockets
```
to be able to expose websocket handlers. This might differ from framework to framework.
## Widgets
All available widgets can be found [here](https://wave.h2o.ai/docs/widgets/overview). We are working on separate docs for Lightwave.
## Custom HTML page
Lightwave can also be used only for certain parts of your HTML pages, e.g. for charts. In addition to the integration steps above:
* Use the `get_web_files` function which HTML links to scripts and styles for you to inject into your existing HTML.
* Render a `div` with an id `wave-root` (`<div id='wave-root'></div>`) into which you want Lightwave to render.
* Render a parent container for `wave-root` that has `position: relative` and has some dimensions attached.
```html
{# index_template.html #}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- Scripts and stylesheets required for Wave to work properly. -->
{{ wave_files }}
</head>
<style>
/* Must have position: relative and some size specified (e.g. height, flexbox, absolute positioning etc.). */
.wave-container {
position: relative;
height: 800px;
}
</style>
<!-- Websocket URL can be changed if needed. Defaults to "/_s/". -->
<body data-wave-socket-url="/custom_socket/">
<noscript>You need to enable JavaScript to run this app.</noscript>
<div class="wave-container">
<!-- Wave renders here. -->
<div id="wave-root"></div>
</div>
</body>
</html>
```
### Configuration
By default, Lightwave tries to connect to websocket route at `/_s/`. This can be configured by adding a `data-wave-socket-url` attribute on the HTML body element (`<body data-wave-socket-url='/my_socket_url/'>`).
## Links
* Website: [https://wave.h2o.ai/](https://wave.h2o.ai/)
* Releases: [https://pypi.org/project/h2o-wave/](https://pypi.org/project/h2o-wave/)
* Code: [https://github.com/h2oai/wave](https://github.com/h2oai/wave)
* Issue tracker: [https://github.com/h2oai/wave/issues](https://github.com/h2oai/wave/issues)
Raw data
{
"_id": null,
"home_page": null,
"name": "h2o-lightwave",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "Data Science, Low code, Machine Learning, Realtime, UI",
"author": null,
"author_email": "Martin Turoci <martin.turoci@h2o.ai>",
"download_url": null,
"platform": null,
"description": "# H2O Lightwave\n\nH2O Lightwave is a lightweight, pure-Python version of [H2O Wave](https://wave.h2o.ai/) that can be embedded in popular async web frameworks like FastAPI, Starlette, etc.\n\nIn other words, H2O Lightwave works without the Wave server.\n\nThe integration consists of 2 steps:\n\n* Add Wave's web assets directory to your framework's static file handler.\n* Add a webSocket handler, and use `wave_serve()` to connect Wave to your web UI.\n\nThat's it. You can now render UI elements using pure Python. Lightwave aims to be as minimal as possible and only provides:\n\n* A simple way to render your UI.\n* A simple way of capturing the user interactions (like button clicks, dropdown values etc.).\n* Minimal state management.\n\nNothing more, nothing less.\n\nExample FastAPI integration:\n\n```py\nfrom fastapi import FastAPI, WebSocket, WebSocketDisconnect\nfrom fastapi.staticfiles import StaticFiles\nfrom h2o_lightwave import Q, ui, wave_serve\nfrom h2o_lightwave_web import web_directory\n\n\n# Lightwave callback function.\nasync def serve(q: Q):\n # Paint our UI on the first page visit.\n if not q.client.initialized:\n # Create a local state.\n q.client.count = 0\n # Add a \"card\" with a text and a button\n q.page['hello'] = ui.form_card(box='1 1 2 2', items=[\n ui.text_xl('Hello world'),\n ui.button(name='counter', label=f'Current count: {q.client.count}'),\n ])\n q.client.initialized = True\n\n # Handle counter button click.\n if q.args.counter:\n # Increment the counter.\n q.client.count += 1\n # Update the counter button.\n q.page['hello'].items[1].button.label = f'Current count: {q.client.count}'\n\n # Send the UI changes to the browser.\n await q.page.save()\n\n\n# Run: uvicorn hello_fastapi:app.\n# FastAPI boilerplate.\napp = FastAPI()\n\n\n# FastAPI: WebSocket must be registered before index.html handler.\n@app.websocket(\"/_s/\")\nasync def ws(ws: WebSocket):\n try:\n await ws.accept()\n await wave_serve(serve, ws.send_text, ws.receive_text)\n await ws.close()\n except WebSocketDisconnect:\n print('Client disconnected')\n\napp.mount(\"/\", StaticFiles(directory=web_directory, html=True), name=\"/\")\n```\n\nWe also recommend reading the [blog post](https://medium.com/@unusualcode/h2o-lightwave-building-web-uis-with-fastapi-and-python-88a915383490) and other [integration examples](https://github.com/h2oai/wave/tree/main/py/h2o_lightwave/examples).\n\n## Installation\n\n```bash\npip install \"h2o-lightwave[web]\"\n```\n\nLightwave requires websockets to function properly. Not all libraries come with them out of the box so you might need to install them additionally. For example, Starlette & FastAPI requires\n\n```bash\npip install websockets\n```\n\nto be able to expose websocket handlers. This might differ from framework to framework.\n\n## Widgets\n\nAll available widgets can be found [here](https://wave.h2o.ai/docs/widgets/overview). We are working on separate docs for Lightwave.\n\n## Custom HTML page\n\nLightwave can also be used only for certain parts of your HTML pages, e.g. for charts. In addition to the integration steps above:\n\n* Use the `get_web_files` function which HTML links to scripts and styles for you to inject into your existing HTML.\n* Render a `div` with an id `wave-root` (`<div id='wave-root'></div>`) into which you want Lightwave to render.\n* Render a parent container for `wave-root` that has `position: relative` and has some dimensions attached.\n\n```html\n{# index_template.html #}\n<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n <meta charset=\"UTF-8\">\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Document</title>\n <!-- Scripts and stylesheets required for Wave to work properly. -->\n {{ wave_files }}\n</head>\n<style>\n /* Must have position: relative and some size specified (e.g. height, flexbox, absolute positioning etc.). */\n .wave-container {\n position: relative;\n height: 800px;\n }\n</style>\n\n<!-- Websocket URL can be changed if needed. Defaults to \"/_s/\". -->\n<body data-wave-socket-url=\"/custom_socket/\">\n <noscript>You need to enable JavaScript to run this app.</noscript>\n <div class=\"wave-container\">\n <!-- Wave renders here. -->\n <div id=\"wave-root\"></div>\n </div>\n</body>\n\n</html>\n```\n\n### Configuration\n\nBy default, Lightwave tries to connect to websocket route at `/_s/`. This can be configured by adding a `data-wave-socket-url` attribute on the HTML body element (`<body data-wave-socket-url='/my_socket_url/'>`).\n\n## Links\n\n* Website: [https://wave.h2o.ai/](https://wave.h2o.ai/)\n* Releases: [https://pypi.org/project/h2o-wave/](https://pypi.org/project/h2o-wave/)\n* Code: [https://github.com/h2oai/wave](https://github.com/h2oai/wave)\n* Issue tracker: [https://github.com/h2oai/wave/issues](https://github.com/h2oai/wave/issues)\n",
"bugtrack_url": null,
"license": null,
"summary": "H2O Wave Python driver for integration with arbitrary python web frameworks.",
"version": "1.4.0",
"project_urls": {
"Changelog": "https://github.com/h2oai/wave/releases",
"Documentation": "https://wave.h2o.ai/",
"Homepage": "https://wave.h2o.ai/",
"Repository": "https://github.com/h2oai/wave"
},
"split_keywords": [
"data science",
" low code",
" machine learning",
" realtime",
" ui"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "82fdc6e632c422f94c4c52216df00e17af5786270506c88b0a3a338b1cdf72af",
"md5": "4d98bbc6a681c23f699b3e466e1aaa19",
"sha256": "ae663771b2103d8b982bce1ca78183efa52ec948d2598dc59a26549e6b9d29ef"
},
"downloads": -1,
"filename": "h2o_lightwave-1.4.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "4d98bbc6a681c23f699b3e466e1aaa19",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 124928,
"upload_time": "2024-08-13T09:54:52",
"upload_time_iso_8601": "2024-08-13T09:54:52.505533Z",
"url": "https://files.pythonhosted.org/packages/82/fd/c6e632c422f94c4c52216df00e17af5786270506c88b0a3a338b1cdf72af/h2o_lightwave-1.4.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-08-13 09:54:52",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "h2oai",
"github_project": "wave",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "h2o-lightwave"
}