Skip to content

Commit

Permalink
Provide a custom OutputModel for now
Browse files Browse the repository at this point in the history
  • Loading branch information
jtpio committed Aug 22, 2022
1 parent 4fe63c8 commit 3840999
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 1 deletion.
2 changes: 2 additions & 0 deletions packages/voila/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"dependencies": {
"@jupyter-widgets/base": "^6.0.0",
"@jupyter-widgets/controls": "^5.0.0",
"@jupyter-widgets/output": "^6.0.0",
"@jupyter-widgets/jupyterlab-manager": "^5.0.2",
"@jupyterlab/json-extension": "^3.0.0",
"@jupyterlab/markdownviewer-extension": "^3.0.0",
Expand All @@ -21,6 +22,7 @@
"@jupyterlab/docregistry": "^3.0.0",
"@jupyterlab/logconsole": "^3.0.0",
"@jupyterlab/mainmenu": "^3.0.0",
"@jupyterlab/nbformat": "^3.0.0",
"@jupyterlab/notebook": "^3.0.0",
"@jupyterlab/outputarea": "^3.0.0",
"@jupyterlab/rendermime": "^3.0.0",
Expand Down
7 changes: 6 additions & 1 deletion packages/voila/src/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import { Widget } from '@lumino/widgets';

import { Kernel } from '@jupyterlab/services';

import { OutputModel } from './output';

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

/**
Expand Down Expand Up @@ -112,7 +114,10 @@ export class WidgetManager extends KernelWidgetManager {
this.register({
name: '@jupyter-widgets/output',
version: output.OUTPUT_WIDGET_VERSION,
exports: output as any
exports: {
...(output as any),
OutputModel
}
});
}
}
98 changes: 98 additions & 0 deletions packages/voila/src/output.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { LabWidgetManager } from '@jupyter-widgets/jupyterlab-manager';

import * as outputBase from '@jupyter-widgets/output';

import * as nbformat from '@jupyterlab/nbformat';

import { OutputAreaModel } from '@jupyterlab/outputarea';

import { KernelMessage } from '@jupyterlab/services';

/**
* Adapt the upstream output model to Voila using a KernelWidgetManager:
* https://github.com/jupyter-widgets/ipywidgets/blob/58adde2cfbe2f78a8ec6756d38a7c637f5e599f8/python/jupyterlab_widgets/src/output.ts#L22
*
* TODO: remove when https://github.com/jupyter-widgets/ipywidgets/pull/3561 (or similar) is merged and released in ipywidgets.
*/
export class OutputModel extends outputBase.OutputModel {
defaults(): Backbone.ObjectHash {
return { ...super.defaults(), msg_id: '', outputs: [] };
}

initialize(attributes: any, options: any): void {
super.initialize(attributes, options);
// The output area model is trusted since widgets are only rendered in trusted contexts.
this._outputs = new OutputAreaModel({ trusted: true });
this._msgHook = (msg): boolean => {
this.add(msg);
return false;
};

this.listenTo(this, 'change:msg_id', this.reset_msg_id);
this.listenTo(this, 'change:outputs', this.setOutputs);
this.setOutputs();
}

/**
* Reset the message id.
*/
reset_msg_id(): void {
const kernel = this.widget_manager.kernel;
const msgId = this.get('msg_id');
const oldMsgId = this.previous('msg_id');

// Clear any old handler.
if (oldMsgId && kernel) {
kernel.removeMessageHook(oldMsgId, this._msgHook);
}

// Register any new handler.
if (msgId && kernel) {
kernel.registerMessageHook(msgId, this._msgHook);
}
}

add(msg: KernelMessage.IIOPubMessage): void {
const msgType = msg.header.msg_type;
switch (msgType) {
case 'execute_result':
case 'display_data':
case 'stream':
case 'error': {
const model = msg.content as nbformat.IOutput;
model.output_type = msgType as nbformat.OutputType;
this._outputs.add(model);
break;
}
case 'clear_output':
this.clear_output((msg as KernelMessage.IClearOutputMsg).content.wait);
break;
default:
break;
}
this.set('outputs', this._outputs.toJSON(), { newMessage: true });
this.save_changes();
}

clear_output(wait = false): void {
this._outputs.clear(wait);
}

get outputs(): OutputAreaModel {
return this._outputs;
}

setOutputs(model?: any, value?: any, options?: any): void {
if (!(options && options.newMessage)) {
// fromJSON does not clear the existing output
this.clear_output();
// fromJSON does not copy the message, so we make a deep copy
this._outputs.fromJSON(JSON.parse(JSON.stringify(this.get('outputs'))));
}
}

widget_manager!: LabWidgetManager;

private _msgHook!: (msg: KernelMessage.IIOPubMessage) => boolean;
private _outputs!: OutputAreaModel;
}

0 comments on commit 3840999

Please sign in to comment.