-
Notifications
You must be signed in to change notification settings - Fork 35
Hybrid Elements Message Spec
The comm protocol is used for communicating between the front-end and backend.
The Declarative Widgets contain several 'core' widgets that require backend implementations. The following spec defines the comm message formats that backend implementations will receive from the front-end as input and must send as output.
By adhering to the spec, the backend widgets can be implemented in a new language.
-
The frontend sends a
comm_openmessage on theipython.widgetchannel containing awidget_classfield:{ header: { msg_type: "comm_open", ... }, ... content: { comm_id: "<COMM_ID>", target_name: "ipython.widget", data: { widget_class: "<WIDGET_CLASS_NAME>" } } }
-
The
widget_classin the initialcomm_openwill beurth.widgets.widget_function.Function -
A
sync_datacomm_msgwill be sent from the frontend following thecomm_openwith afunction_namefield whose value is the name of the function to use. Extra options such aslimitare also included in this message:{ header: { msg_type: "comm_msg", ... }, ... content: { data: { method: "backbone", sync_data: { function_name: "<FUNCTION_NAME>", limit: <LIMIT> } }, ... } } -
The backend should then send the function's
signature, a mapping of argument name to properties (e.g. JavaScript type), in the following format:{ header: { msg_type: "comm_msg", ... }, content: { data: { method: "update" state: { argspec: { "<ARG_NAME_1>": { type: "<ARG_1_TYPE>", required: true }, ... "<ARG_NAME_N>": { type: "<ARG_N_TYPE>" } } } } }, ... }
If a type cannot be mapped to a JavaScript type, the language implementation's type should be sent.
The required field is set to true when the argument must be present for function invocation. For instance, the required field is not necessary for a parameter with a default argument.
-
Finally, the backend should send a
statusmessage. See theStatus Messagessection for a full description of the message format.- Send a
status: okmessage if the function name registration succeeded. - Send a
status: errormessage if the function name registration failed, e.g. if no function with the given name has been declared, or if an error occurred while determining thesignature.
- Send a
-
A
customcomm_msgwill be sent from the frontend with anevent: "invoke"field, and anargs: {...}field. Theargsfield contains an object with mappings from argument name to argument value that should be used for the function invocation. The function to be invoked is the function whose name was sent during initialization in thefunction_namefield.{ header: { msg_type: "comm_msg", ... }, ... content: { data: { method: "custom", content: { event: "invoke", args: { "<ARG_NAME_1>": "<ARG_VALUE_1>", ... "<ARG_NAME_N>": "<ARG_VALUE_N>" } } } } }
Note that all argument values are sent as strings. It is up to the language implementation to convert argument values to their proper types if necessary.
-
The function's return value should be sent from the backend as a
customcomm_msgwithmethod: update. The message contains astateobject with aresultfield that holds the function's return value.{ header: { msg_type: "comm_msg", ... }, ... content: { data: { method: "update", state: { "result": <FUNCTION_RETURN_VALUE> } }, ... } }
Note that the language implementation should send a representation of the function return value that can be serialized as JSON.
-
Finally, the backend should send a
statusmessage. See theStatus Messagessection for a full description of the message format.- Send a
status: okmessage if the function invocation succeeded. - Send a
status: errormessage if the function invocation failed.
- Send a
-
The
widget_classin the initialcomm_openwill beurth.widgets.widget_dataframe.DataFrame -
A
sync_datacomm_msgwill be sent from the frontend following thecomm_openwith avariable_namefield whose value is the name of the data variable to use. Extra options such aslimitare also included in this message:{ header: { msg_type: "comm_msg", ... }, ... content: { data: { method: "backbone", sync_data: { variable_name: "<FUNCTION_NAME>", limit: <LIMIT> } }, ... } } -
The backend should then send a
statusmessage. See theStatus Messagessection for a full description of the message format.- Send a
status: okmessage if the DataFrame name registration succeeded. - Send a
status: errormessage if the DataFrame name registration failed, e.g. if no DataFrame with the given name has been declared.
- Send a
-
The frontend will then send a
syncmessage (see below)
-
A
customcomm_msgwill be sent from the frontend with anevent: "sync"field. This signals the backend to send a representation of the current value ofvariable_name.{ header: { msg_type: "comm_msg", ... }, ... content: { data: { method: "custom", content: { event: "sync" } } } } -
A representation of
variable_name's current value should be sent from the backend as acustomcomm_msgwithmethod: update. The message contains astateobject with avaluefield that holdsvariable_name's value representation. By convention, the DataFrame's value is represented bycolumns,index, anddatafields:{ header: { msg_type: "comm_msg", ... }, ... content: { data: { method: "update", state: { "value": { "columns": ["<COLNAME_1>", ..., "<COLNAME_N>"], "index": ["<ROWNAME_1>", ..., "<ROWNAME_M>"], "data": [[<data_11>, ..., <data_1n], ... [<data_m1>, ..., <data_mn]] } } }, ... } }
Declarative widgets use status messages to communicate success or failure. For instance, a Function widget sends an status: ok message following a successful function invocation, and a DataFrame widget sends a status: error message given an invalid DataFrame variable name.
A status message is a custom comm_msg with method: update, and a state object with a status field representing the status:
{
header: {
msg_type: "comm_msg",
...
},
...
content: {
data: {
method: "update",
state: {
"status": {
"status": "ok" | "error",
"msg": success or error message string,
"timestamp": long
}
}
},
...
}
}
Below are some key operations that will inevitably need to be supported by a backend implementation of Declarative Widgets.
- Executing a function with a given name, using a mapping of argument names to argument values as strings. For instance, the Scala widgets contain the function:
def invokeFunction(funcName: String, args: Map[String, String]): Try[Any]- Obtaining the argument names and types of a function with a given name. For instance, the Scala widgets contain the function:
def argTypes(funcName: String): List[(Name, Type)]-
Retrieving the current value of a variable given the variable's name. For instance, the Scala widgets retrieve the value using a function provided by the Spark Kernel's
Interpreter:
kernelInterpreter.read(dataFrameVariableName)