Before you begin, it is highly recommended that you download a release and run the interactive
tour.py that ships with the release to get a feel for what Wave programs look like in practice.
What has changed?
From an app-development perspective, the most important change is that Wave is more of a library rather than a framework.
With the previous framework, the only way to execute an app was via the Q server. This limitation has been removed. The script/app you author is just a regular Python program in which you
import h2o_wave and execute via:
- The command line:
- In the Python REPL.
- In a Jupyter notebook.
- In your favorite IDE (PyCharm, VSCode, etc.).
This also means that you can apply breakpoints and debug or step-through your program in your debugger of choice.
From an information architecture perspective, control has been inverted: instead of your app being an extension to Wave's data/prep/search features, Wave's features are now optional additions to your app, and your app takes center stage. Implementation-wise, instead of your app running in a sidebar inside of Wave's UI, your app now occupies the entire UI.
Instead, define a
async request-handling function, say
main(), and pass that function to
listen(), like this:
The above four methods were the primary mechanism to make changes to your app's UI. They have all been replaced with a single
The new technique is:
- Access the page or card you want to modify.
- Modify the page or card.
h2o_wave.core.Page.save()to save your changes and update the browser page.
Note that the After example requires a
box that specifies where to draw your form. This is because you are not limited to using a sidebar, and can use the entire width/length of the page.
The same technique can be used to update the UI again (or display intermediate results):
Removed: callback functions for request-handling.
Wave apps are 100% push-based, using duplex communication instead of a request/reply paradigm. There is no need to have a tangled mess of callbacks to handle UI events.
Instead, all requests are routed to a single function, and you can decide how to organize your application logic by branching on
Every page in Wave is a dashboard page. Instead of creating a separate dashboard or notebook, simply add cards to a page and arrange it the way you want. Cards can be created by using one of the several
ui.*_card() APIs. Also see the dashboard, layout and sizing examples to learn how to lay out several cards on a page.
If you want to display a notebook-style vertical stack of markdown, html or other content, use
h2o_wave.ui.frame() contained inside a
h2o_wave.ui.form_card(), like this:
After: Note the parameter name change
ui.tabs() accept a
list of items instead of var args
q.upload() changed to
upload() method has been moved to the
h2o_wave.core.Site instance, since each
h2o_wave.core.Site represents a distinct server, and makes it possible to control multiple sites from a single Python script.
q.args.foo= changed to
Setting attributes on
q.args.foo = 'bar') is no longer preserved between requests. This was the primary mechanism employed previously to preserve data between requests.
Instead, Wave provides 4 mechanisms for preserving data between requests:
- Process-level: Use global variables.
- App-level: Use
q.app.foo = 'bar'to save; access
q.app.footo read it back again.
- User-level: Use
q.user.foo = 'bar'to save; access
q.user.footo read it back again.
- Client-level: Use
q.client.foo = 'bar'to save; access
q.client.footo read it back again.
Here, Client refers to a distinct tab in a browser.
If you want to rely on the old behavior of preserving
q.args for the lifetime of the application, copy
q.client like this:
Changed: No need to JSON-serialize values to preserve them between requests.
q.args.foo= only supported JSON-serialized values. No such restrictions exist for the
q.client containers. You could, for example, load a Pandas dataframe and set
q.user.df = my_df, and the dataframe will be accessible across requests for the lifetime of the app.