Create your own plugin
This guide walks you through creating a plugin in Deephaven. Specifically, it covers creating a bidirectional plugin that extends the capabilities of Deephaven's Python client API. Bidirectional plugins allow users to create custom RPC methods that enable clients to interact with and return objects on a running server.
Plugins in Deephaven are just Python packages that extend the server's functionality, the UI, a client API, or a combination of these. They can be as simple as a single Python file or as complex as a multi-file package with dependencies. Plugins are packaged like any other Python package.
All plugins have both a server-side and a client-side component. Server-side plugin code is implemented with the deephaven.plugin module, and client-side plugin code is implemented with the pydeephaven.experimental.plugin_client module.
The plugin example used in this guide can also be found here.
Plugin structure
This example creates a plugin called ExampleService. You can call your plugin whatever you'd like, but be aware that the name must be consistent across both the server and client. If you change the name as you follow along, update it in both the server and client code.
Note
The directory name does not need to match the plugin name. This guide uses ExampleServicePlugin for the directory name, but the plugin itself is called ExampleService.
The plugin is broken into server- and client-side components. Create the following directory and file structure in your project folder:
Note
This guide assumes the use of the pyproject.toml configuration for packaging. You can also use setup.cfg or setup.py if you prefer.
Server-side plugin
All server-side plugin code will live in the server folder. This folder contains a TOML file for packaging and a subfolder containing the actual plugin implementation.
Plugin implementation
This example plugin can be broken into three parts, all of which go in server/example_plugin_server/__init__.py:
- The plugin implementation
- The object(s) it manages
- The message stream handler
Let's start with the plugin implementation itself, which contains all of the required methods for any bidirectional plugins. This example manages only a single object, however, more complex plugins can manage an arbitrary number of objects. In such a case, those objects would be added to the relevant methods.
Now, create the object the plugin manages. In this case, the service will have two methods.
Lastly, define the message stream handler to pass messages between the client and the server.
Plugin registration
The registration code is simpler than the implementation.
Altogether, the __init__.py should look like this:
init.py
Packaging
As mentioned previously, this project uses pyproject.toml to package the server-side code, which goes in server/pyproject.toml:
Note
The server-side pyproject.toml file must register an entry point for the plugin.
Testing
You can test the plugin with only the server-side wiring implemented to make sure it registers with the server on startup. To see how, refer to the Server-side testing section.
Client-side plugin
The client-side code and packaging live in the client folder of the project.
Plugin implementation
Like with the server-side code, the client-side code will be housed in a single file, client/example_plugin_client/__init__.py. The client-side implementation will mirror the server-side implementation to call the methods on the server-side object.
Packaging
Like with the server-side plugin, the client-side plugin is packaged with a TOML file, client/pyproject.toml:
Note
The client-side plugin for this example requires no registration.
Use the plugin
Once you have completed all of the client—and server-side wiring, you can test the plugin. The following subsections cover testing the server using different launch methods.
Installation
To test the plugin, you must first install it, along with Deephaven and any other required packages.
pip-installed Deephaven
If starting the server with pip-installed Deephaven, it is highly recommended to do so in a virtual environment. The following commands create a virtual environment and install the necessary packages, including the plugin.
Docker
If starting the server with Docker, it's recommended to use Docker Compose to manage the server and any other services. The following Dockerfile builds a Docker image based on Deephaven's base server image, and installs the plugin:
The following Docker Compose file runs Deephaven using the image built by the above Dockerfile:
Important
The Dockerfile below sets the pre-shared key to YOUR_PASSWORD_HERE for demonstration purposes. The client needs this key when connecting to the server. It is recommended that this key be changed to something more secure.
With those two files in hand, docker compose up installs the plugin and starts the server.
Server-side testing
pip-installed Deephaven
If running Deephaven from Python, the following Python script will start a Deephaven server, create an instance of ExampleService, and keep the server running until ctrl+C is pressed:
Docker
When running from Docker, you need only create an instance of ExampleService so that a client may interact with it:
Client-side testing
Then, to test the client-side plugin, run the following commands from the root of the project to create another virtual environment and install the necessary packages:
With that said and done, the following Python script will use the client-side plugin:
Important
Replace YOUR_PASSWORD_HERE with the pre-shared key set when starting the server if you changed it.