Skip to content

Commit

Permalink
Base off KernelWidgetManager from latest alpha packages
Browse files Browse the repository at this point in the history
  • Loading branch information
jtpio committed Mar 19, 2021
1 parent aab45b8 commit b40ece1
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 184 deletions.
6 changes: 3 additions & 3 deletions packages/voila/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
"main": "lib/index.js",
"browserslist": ">0.8%, not ie 11, not op_mini all, not dead",
"dependencies": {
"@jupyter-widgets/base": "^4.0.0",
"@jupyter-widgets/controls": "^3.0.0",
"@jupyter-widgets/jupyterlab-manager": "^3.0.0",
"@jupyter-widgets/base": "^5.0.0-alpha.2",
"@jupyter-widgets/controls": "^4.0.0-alpha.2",
"@jupyter-widgets/jupyterlab-manager": "^4.0.0-alpha.1",
"@jupyterlab/json-extension": "^3.0.0",
"@jupyterlab/markdownviewer-extension": "^3.0.0",
"@jupyterlab/mathjax2-extension": "^3.0.0",
Expand Down
105 changes: 15 additions & 90 deletions packages/voila/src/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,14 @@
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

import {
WidgetManager as JupyterLabManager,
WidgetRenderer
} from '@jupyter-widgets/jupyterlab-manager';
import { WidgetRenderer, output } from '@jupyter-widgets/jupyterlab-manager';

import { output } from '@jupyter-widgets/jupyterlab-manager';
import { KernelWidgetManager } from '@jupyter-widgets/jupyterlab-manager/lib/manager';

import * as base from '@jupyter-widgets/base';

import * as controls from '@jupyter-widgets/controls';

import { DocumentRegistry } from '@jupyterlab/docregistry';

import { INotebookModel } from '@jupyterlab/notebook';

import { IRenderMimeRegistry } from '@jupyterlab/rendermime';

import * as LuminoWidget from '@lumino/widgets';
Expand All @@ -30,33 +23,31 @@ import { MessageLoop } from '@lumino/messaging';

import { Widget } from '@lumino/widgets';

import { batchRateMap } from './utils';
import { Kernel } from '@jupyterlab/services';

const WIDGET_MIMETYPE = 'application/vnd.jupyter.widget-view+json';

/**
* A custom widget manager to render widgets with Voila
*/
export class WidgetManager extends JupyterLabManager {
export class WidgetManager extends KernelWidgetManager {
constructor(
context: DocumentRegistry.IContext<INotebookModel>,
rendermime: IRenderMimeRegistry,
settings: JupyterLabManager.Settings
kernel: Kernel.IKernelConnection,
rendermime: IRenderMimeRegistry
) {
super(context, rendermime, settings);
super(kernel, rendermime);
rendermime.addFactory(
{
safe: false,
mimeTypes: [WIDGET_MIMETYPE],
createRenderer: options => new WidgetRenderer(options, this)
createRenderer: options => new WidgetRenderer(options)
},
1
);
this._registerWidgets();
}

async build_widgets(): Promise<void> {
const models = await this._build_models();
const tags = document.body.querySelectorAll(
'script[type="application/vnd.jupyter.widget-view+json"]'
);
Expand All @@ -67,13 +58,11 @@ export class WidgetManager extends JupyterLabManager {
try {
const widgetViewObject = JSON.parse(viewtag.innerHTML);
const { model_id } = widgetViewObject;
const model = models[model_id];
const model = await this.get_model(model_id);
const widgetel = document.createElement('div');
viewtag.parentElement.insertBefore(widgetel, viewtag);
// TODO: fix typing
await this.display_model(undefined as any, model, {
el: widgetel
});
const view = await this.create_view(model);
this.display_view(view, widgetel);
} catch (error) {
// Each widget view tag rendering is wrapped with a try-catch statement.
//
Expand All @@ -84,13 +73,14 @@ export class WidgetManager extends JupyterLabManager {
//
// This workaround may not be necessary anymore with templates that make use
// of progressive rendering.
console.error(error);
}
});
}

async display_view(msg: any, view: any, options: any): Promise<Widget> {
if (options.el) {
LuminoWidget.Widget.attach(view.pWidget, options.el);
async display_view(view: any, el: HTMLElement): Promise<Widget> {
if (el) {
LuminoWidget.Widget.attach(view.pWidget, el);
}
if (view.el) {
view.el.setAttribute('data-voila-jupyter-widget', '');
Expand All @@ -104,10 +94,6 @@ export class WidgetManager extends JupyterLabManager {
return view.pWidget;
}

restoreWidgets(notebook: INotebookModel): Promise<void> {
return Promise.resolve();
}

private _registerWidgets(): void {
this.register({
name: '@jupyter-widgets/base',
Expand All @@ -125,65 +111,4 @@ export class WidgetManager extends JupyterLabManager {
exports: output as any
});
}

async _build_models(): Promise<{ [key: string]: base.WidgetModel }> {
const comm_ids = await this._get_comm_info();
const models: { [key: string]: base.WidgetModel } = {};
/**
* For the classical notebook, iopub_msg_rate_limit=1000 (default)
* And for zmq, we are affected by the default ZMQ_SNDHWM setting of 1000
* See https://github.com/voila-dashboards/voila/issues/534 for a discussion
*/
const maxMessagesInTransit = 100; // really save limit compared to ZMQ_SNDHWM
const maxMessagesPerSecond = 500; // lets be on the save side, in case the kernel sends more msg'es
const widgets_info = await Promise.all(
batchRateMap(
Object.keys(comm_ids),
async comm_id => {
const comm = await this._create_comm(this.comm_target_name, comm_id);
return this._update_comm(comm);
},
{ room: maxMessagesInTransit, rate: maxMessagesPerSecond }
)
);

await Promise.all(
widgets_info.map(async widget_info => {
const state = (widget_info as any).msg.content.data.state;
const modelPromise = this.new_model(
{
model_name: state._model_name,
model_module: state._model_module,
model_module_version: state._model_module_version,
comm: (widget_info as any).comm
},
state
);
const model = await modelPromise;
models[model.model_id] = model;
return modelPromise;
})
);
return models;
}

async _update_comm(
comm: base.IClassicComm
): Promise<{ comm: base.IClassicComm; msg: any }> {
return new Promise((resolve, reject) => {
comm.on_msg(async msg => {
if (msg.content.data.buffer_paths) {
base.put_buffers(
msg.content.data.state,
msg.content.data.buffer_paths,
msg.buffers
);
}
if (msg.content.data.method === 'update') {
resolve({ comm: comm, msg: msg });
}
});
comm.send({ method: 'request_state' }, {});
});
}
}
48 changes: 4 additions & 44 deletions packages/voila/src/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@ import {

import { PageConfig } from '@jupyterlab/coreutils';

import { DocumentRegistry } from '@jupyterlab/docregistry';

import { INotebookModel } from '@jupyterlab/notebook';

import { IRenderMimeRegistry } from '@jupyterlab/rendermime';

import { KernelAPI, ServerConnection } from '@jupyterlab/services';
Expand Down Expand Up @@ -99,47 +95,11 @@ const widgetManager: JupyterFrontEndPlugin<IJupyterWidgetRegistry> = {
};
}
const kernel = new KernelConnection({ model, serverSettings });
const manager = new VoilaWidgetManager(kernel, rendermime);

// TODO: switch to using a real SessionContext and a session context widget manager
const context = {
sessionContext: {
session: {
kernel,
kernelChanged: {
// eslint-disable-next-line @typescript-eslint/no-empty-function
connect: () => {}
}
},
statusChanged: {
// eslint-disable-next-line @typescript-eslint/no-empty-function
connect: () => {}
},
kernelChanged: {
// eslint-disable-next-line @typescript-eslint/no-empty-function
connect: () => {}
},
connectionStatusChanged: {
// eslint-disable-next-line @typescript-eslint/no-empty-function
connect: () => {}
}
},
saveState: {
// eslint-disable-next-line @typescript-eslint/no-empty-function
connect: () => {}
}
};

const settings = {
saveState: false
};

const manager = new VoilaWidgetManager(
(context as unknown) as DocumentRegistry.IContext<INotebookModel>,
rendermime,
settings
);

void manager.build_widgets();
manager.restored.connect(() => {
void manager.build_widgets();
});

console.log('Voila manager activated');

Expand Down
Loading

0 comments on commit b40ece1

Please sign in to comment.