Skip to content

Commit

Permalink
docs: Add proper readme. #1796
Browse files Browse the repository at this point in the history
  • Loading branch information
mturoci committed Feb 24, 2023
1 parent 5831602 commit 1eb69e0
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 172 deletions.
91 changes: 40 additions & 51 deletions py/examples/wizard.py
Original file line number Diff line number Diff line change
@@ -1,60 +1,49 @@
# Wizard
# Create a multi-step #wizard using #form cards.
# ---
from h2o_wave import Q, ui, main, app, cypress, Cypress
import uvicorn
from starlette.applications import Starlette
from starlette.routing import Mount, WebSocketRoute
from starlette.staticfiles import StaticFiles
from starlette.websockets import WebSocketDisconnect
from h2o_wavelite import wave_serve, ui, Q
from h2o_wavelite_web import web_directory


@app('/demo')
async def serve(q: Q):
if not q.client.initialized: # First visit, create an empty form card for our wizard
q.page['wizard'] = ui.form_card(box='1 1 2 4', items=[])
# 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

wizard = q.page['wizard'] # Get a reference to the wizard form
if q.args.step1:
wizard.items = [
ui.text_xl('Wizard - Step 1'),
ui.text('What is your name?', name='text'),
ui.textbox(name='nickname', label='My name is...', value='Gandalf'),
ui.buttons([ui.button(name='step2', label='Next', primary=True)]),
]
elif q.args.step2:
q.client.nickname = q.args.nickname
wizard.items = [
ui.text_xl('Wizard - Step 2'),
ui.text(f'Hi {q.args.nickname}! How do you feel right now?', name='text'),
ui.textbox(name='feeling', label='I feel...', value='magical'),
ui.buttons([ui.button(name='step3', label='Next', primary=True)]),
]
elif q.args.step3:
wizard.items = [
ui.text_xl('Wizard - Done'),
ui.text(
f'What a coincidence, {q.client.nickname}! I feel {q.args.feeling} too!',
name='text',
),
ui.buttons([ui.button(name='step1', label='Try Again', primary=True)]),
]
else:
wizard.items = [
ui.text_xl('Wizard Example'),
ui.text("Let's have a conversation, shall we?"),
ui.buttons([ui.button(name='step1', label='Of course!', primary=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()


@cypress('Walk through the wizard')
def try_walk_through(cy: Cypress):
cy.visit('/demo')
cy.locate('step1').click()
cy.locate('text').should('contain.text', 'What is your name?')
cy.locate('nickname').clear().type('Fred')
cy.locate('step2').click()
cy.locate('text').should('contain.text', 'Hi Fred! How do you feel right now?')
cy.locate('feeling').clear().type('quirky')
cy.locate('step3').click()
cy.locate('text').should(
'contain.text', 'What a coincidence, Fred! I feel quirky too!'
)
async def socket(ws):
try:
await ws.accept()
await wave_serve(serve, ws.send_text, ws.receive_text)
await ws.close()
except WebSocketDisconnect:
print('Client disconnected')


startlette_app = Starlette(routes=[
WebSocketRoute('/_s/', socket),
Mount("/", app=StaticFiles(directory=web_directory, html=True), name="/")
])

if __name__ == '__main__':
uvicorn.run(startlette_app, host='0.0.0.0', port=5000)

116 changes: 73 additions & 43 deletions py/h2o_wavelite/README.md
Original file line number Diff line number Diff line change
@@ -1,59 +1,89 @@
H2O Wave
========
# H2O Wavelite

H2O Wave is a lightweight software stack for programming interactive web applications
entirely in Python (no HTML/Javascript/CSS required).
H2O Wavelite is a lighter version of [H2O Wave](https://wave.h2o.ai/), capable of seamless integration into popular existing python web frameworks like Django, Flask, FastAPI, Starlette etc.

It is designed to make it fast, fun and easy to build low-latency, realtime,
collaborative, web-based applications. It ships batteries-included with
a suite of form and data visualization components for rapidly prototyping
analytical and decision-support applications.
The integration consists of 2 steps:

Wave's components work in conjunction with the Wave relay server that facilitates
realtime state synchronization between Python and web browsers.
* Serve Wavelite's static web dir at the route of your choice.
* Set up a WebSocket connection and hook `wave_serve` callback function to control the UI.

Installing
----------
Done. You can render UI elements with nothing but Python. Wavelite aims to be as simplistic as possible and only provides:

Install and update using conda
* A simple way to render your UI.
* A simple way of getting the UI inputs (like button clicks, dropdown values etc.)
* Minimal state management.

```bash
conda config --append channels conda-forge
conda install -c h2oai h2o-wave
```
Nothing more, nothing less.

Hello world
-----------
## Installation

`hello.py`:
----------

```bash
from h2o_wave import site, ui

# Access the web page at http://localhost:10101/demo
page = site['/demo']

# Add some content.
page['example'] = ui.markdown_card(
box='1 1 2 2',
title='Hello World!',
content='And now for something completely different.',
)

# Save the page
page.save()
pip install "h2o-wavelite[web]"
```

Run `hello.py`:
## Starlette Hello world

```py
import uvicorn
from starlette.applications import Starlette
from starlette.routing import Mount, WebSocketRoute
from starlette.staticfiles import StaticFiles
from starlette.websockets import WebSocketDisconnect
from h2o_wavelite import wave_serve, ui, Q
from h2o_wavelite_web import web_directory


# Wavelite 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()


# Starlette boilerplate.
async def socket(ws):
try:
await ws.accept()
await wave_serve(serve, ws.send_text, ws.receive_text)
await ws.close()
except WebSocketDisconnect:
print('Client disconnected')


startlette_app = Starlette(routes=[
# Register a websocket.
WebSocketRoute('/_s/', socket),
# Serve static assets.
Mount("/", app=StaticFiles(directory=web_directory, html=True), name="/")
])

if __name__ == '__main__':
uvicorn.run(startlette_app, host='0.0.0.0', port=5000)

```bash
python hello.py
```

Links
-----
## 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)
* 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)
64 changes: 0 additions & 64 deletions py/h2o_wavelite/README.rst

This file was deleted.

3 changes: 2 additions & 1 deletion py/h2o_wavelite/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import setuptools
import os

with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'README.rst'), 'r') as readme:
with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'README.md'), 'r') as readme:
long_description = readme.read()

version = os.getenv('VERSION', 'DEV')
Expand All @@ -26,6 +26,7 @@
author_email='martin.turoci@h2o.ai',
description='H2O Wave Python driver for integration with arbitrary python web frameworks.',
long_description=long_description,
long_description_content_type="text/markdown",
url='https://h2o.ai/products/h2o-wave',
packages=['h2o_wavelite'],
extras_require=dict(web=[f"h2o_wavelite_web=={version}"]),
Expand Down
14 changes: 1 addition & 13 deletions py/h2o_wavelite_web/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1 @@
Create apps 10x quicker, without Javascript, HTML, or CSS.

[Documentation](https://nitro.h2o.ai) | [Source](https://github.com/h2oai/nitro)

Integrates with [Django](https://www.djangoproject.com/)
, [Flask](https://flask.palletsprojects.com/), [Starlette](https://www.starlette.io/)
, [Tornado](https://www.tornadoweb.org/), [Uvicorn](https://www.uvicorn.org/) and other popular frameworks. Can be
integrated into your existing applications.





Web assets for H2O Wavelite.

0 comments on commit 1eb69e0

Please sign in to comment.