Skip to content

Commit 3eedc21

Browse files
authored
Get ipywidgets working everywhere (#10653)
1 parent fd8fab2 commit 3eedc21

11 files changed

Lines changed: 461 additions & 244 deletions

File tree

src/client/datascience/interactive-ipynb/nativeEditor.ts

Lines changed: 0 additions & 225 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ import {
3333
GLOBAL_MEMENTO,
3434
IAsyncDisposableRegistry,
3535
IConfigurationService,
36-
IDisposable,
3736
IDisposableRegistry,
3837
IExperimentsManager,
3938
IMemento,
@@ -56,14 +55,11 @@ import { InteractiveBase } from '../interactive-common/interactiveBase';
5655
import {
5756
INativeCommand,
5857
InteractiveWindowMessages,
59-
IPyWidgetMessages,
6058
IReExecuteCells,
6159
ISubmitNewCell,
6260
NotebookModelChange,
6361
SysInfoReason
6462
} from '../interactive-common/interactiveWindowTypes';
65-
import { JupyterNotebookBase } from '../jupyter/jupyterNotebook';
66-
import { JupyterSession } from '../jupyter/jupyterSession';
6763
import {
6864
CellState,
6965
ICell,
@@ -82,15 +78,13 @@ import {
8278
INotebookImporter,
8379
INotebookModel,
8480
INotebookProvider,
85-
INotebookServer,
8681
IStatusProvider,
8782
IThemeFinder,
8883
WebViewViewChangeEventArgs
8984
} from '../types';
9085
import { NativeEditorSynchronizer } from './nativeEditorSynchronizer';
9186

9287
import { nbformat } from '@jupyterlab/coreutils';
93-
import { KernelMessage } from '@jupyterlab/services';
9488
// tslint:disable-next-line: no-require-imports
9589
import cloneDeep = require('lodash/cloneDeep');
9690
import { concatMultilineStringInput } from '../../../datascience-ui/common';
@@ -153,8 +147,6 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor {
153147
private loadedAllCells: boolean = false;
154148
private executeCancelTokens = new Set<CancellationTokenSource>();
155149

156-
private commtargetRegistered: boolean = false;
157-
private readonly targetNames: string[] = [];
158150
constructor(
159151
@multiInject(IInteractiveWindowListener) listeners: IInteractiveWindowListener[],
160152
@inject(ILiveShareApi) liveShare: ILiveShareApi,
@@ -295,14 +287,6 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor {
295287
this.interruptExecution();
296288
break;
297289

298-
case IPyWidgetMessages.IPyWidgets_ShellSend:
299-
this.handleMessage(message, payload, this.sendIPythonShellMsg);
300-
break;
301-
302-
case IPyWidgetMessages.IPyWidgets_registerCommTarget:
303-
this.handleMessage(message, payload, this.registerCommTarget);
304-
break;
305-
306290
default:
307291
break;
308292
}
@@ -373,215 +357,6 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor {
373357
.submitCode(code, file, line, id, data, debug, cancelToken)
374358
.finally(() => this.sendPerceivedCellExecute(stopWatch));
375359
}
376-
protected handleOnIOPub(data: { msg: KernelMessage.IIOPubMessage; requestId: string }) {
377-
if (KernelMessage.isDisplayDataMsg(data.msg)) {
378-
this.postMessage(IPyWidgetMessages.IPyWidgets_display_data_msg, data.msg).catch(ex =>
379-
// tslint:disable-next-line: no-console
380-
console.error('Failed to post oniopub message', ex)
381-
);
382-
} else if (KernelMessage.isStatusMsg(data.msg)) {
383-
// Do nothing.
384-
} else if (KernelMessage.isCommOpenMsg(data.msg)) {
385-
// Do nothing, handled in the place we have registered for a target.
386-
} else if (KernelMessage.isCommMsgMsg(data.msg)) {
387-
// tslint:disable-next-line: no-any
388-
this.serializeDataViews(data.msg as any);
389-
this.postMessage(IPyWidgetMessages.IPyWidgets_comm_msg, data.msg as KernelMessage.ICommMsgMsg).catch(ex =>
390-
// tslint:disable-next-line: no-console
391-
console.error('Failed to post oniopub message for handler', ex)
392-
);
393-
}
394-
}
395-
// tslint:disable-next-line: member-ordering
396-
private disposable?: IDisposable;
397-
protected async ensureNotebook(server: INotebookServer): Promise<void> {
398-
await super.ensureNotebook(server);
399-
if (this.disposable) {
400-
this.disposable.dispose();
401-
}
402-
if (!this.notebook) {
403-
return;
404-
}
405-
this.disposable = (this.notebook as JupyterNotebookBase).onIOPub(this.handleOnIOPub.bind(this));
406-
// tslint:disable-next-line: no-console
407-
// console.log('Event handler added');
408-
// (this.notebook as JupyterNotebookBase).onIOPub((data: {msg: KernelMessage.IIOPubMessage; requestId: string}) => {
409-
// if (KernelMessage.isDisplayDataMsg(data.msg)) {
410-
// this.postMessage(InteractiveWindowMessages.IPyWidgets_display_data_msg, data.msg).catch(ex => console.error('Failed to post oniopub message', ex));
411-
// }
412-
// });
413-
// tslint:disable-next-line: no-any
414-
if (!((this.notebook as JupyterNotebookBase).session as JupyterSession).session) {
415-
return;
416-
}
417-
418-
const kernel = ((this.notebook as JupyterNotebookBase).session as JupyterSession).session!.kernel;
419-
if (!this.commtargetRegistered) {
420-
this.commtargetRegistered = true;
421-
this.targetNames.forEach(targetName => {
422-
// kernel.registerCommTarget('jupyter.widget', (_comm, msg) => {
423-
kernel.registerCommTarget(targetName, (_comm, msg) => {
424-
// tslint:disable-next-line: no-any
425-
this.serializeDataViews(msg as any);
426-
this.postMessage(IPyWidgetMessages.IPyWidgets_comm_open, msg).catch(ex =>
427-
// tslint:disable-next-line: no-console
428-
console.error('Failed to post oniopub message', ex)
429-
);
430-
});
431-
});
432-
}
433-
}
434-
protected registerCommTarget(targetName: string) {
435-
if (!this.commtargetRegistered) {
436-
this.targetNames.push(targetName);
437-
return;
438-
}
439-
const kernel = ((this.notebook as JupyterNotebookBase).session as JupyterSession).session!.kernel;
440-
kernel.registerCommTarget(targetName, (_comm, msg) => {
441-
// tslint:disable-next-line: no-any
442-
this.serializeDataViews(msg as any);
443-
this.postMessage(IPyWidgetMessages.IPyWidgets_comm_open, msg).catch(ex =>
444-
// tslint:disable-next-line: no-console
445-
console.error('Failed to post oniopub message', ex)
446-
);
447-
});
448-
}
449-
protected serializeDataViews(msg: KernelMessage.IIOPubMessage) {
450-
if (!Array.isArray(msg.buffers) || msg.buffers.length === 0) {
451-
return;
452-
}
453-
// tslint:disable-next-line: no-any
454-
const newBufferView: any[] = [];
455-
// tslint:disable-next-line: prefer-for-of
456-
for (let i = 0; i < msg.buffers.length; i += 1) {
457-
const item = msg.buffers[i];
458-
if ('buffer' in item && 'byteOffset' in item) {
459-
// It is an ArrayBufferView
460-
// tslint:disable-next-line: no-any
461-
const buffer = Array.apply(null, new Uint8Array(item.buffer as any) as any);
462-
newBufferView.push({
463-
...item,
464-
byteLength: item.byteLength,
465-
byteOffset: item.byteOffset,
466-
buffer
467-
// tslint:disable-next-line: no-any
468-
} as any);
469-
} else {
470-
// tslint:disable-next-line: no-any
471-
newBufferView.push(Array.apply(null, new Uint8Array(item as any) as any) as any);
472-
}
473-
}
474-
475-
// tslint:disable-next-line: no-any
476-
// msg.buffers = JSON.stringify(newBufferView) as any;
477-
msg.buffers = newBufferView;
478-
}
479-
protected restoreBuffers(buffers?: (ArrayBuffer | ArrayBufferView)[] | undefined) {
480-
if (!buffers || !Array.isArray(buffers) || buffers.length === 0) {
481-
return buffers || [];
482-
}
483-
// tslint:disable-next-line: prefer-for-of no-any
484-
const newBuffers: any[] = [];
485-
// tslint:disable-next-line: prefer-for-of no-any
486-
for (let i = 0; i < buffers.length; i += 1) {
487-
const item = buffers[i];
488-
if ('buffer' in item && 'byteOffset' in item) {
489-
const buffer = new Uint8Array(item.buffer).buffer;
490-
// It is an ArrayBufferView
491-
// tslint:disable-next-line: no-any
492-
const bufferView = new DataView(buffer, item.byteOffset, item.byteLength);
493-
newBuffers.push(bufferView);
494-
} else {
495-
const buffer = new Uint8Array(item).buffer;
496-
// tslint:disable-next-line: no-any
497-
newBuffers.push(buffer);
498-
}
499-
}
500-
return newBuffers;
501-
}
502-
// tslint:disable: no-any
503-
protected async sendIPythonShellMsg(payload: {
504-
data: any;
505-
metadata: any;
506-
commId: string;
507-
requestId: string;
508-
buffers?: any;
509-
msgType: string;
510-
targetName?: string;
511-
}) {
512-
const kernel = ((this.notebook as JupyterNotebookBase).session as JupyterSession).session!.kernel;
513-
const shellMessage = KernelMessage.createMessage<KernelMessage.ICommMsgMsg<'shell'>>({
514-
// tslint:disable-next-line: no-any
515-
msgType: payload.msgType as any,
516-
channel: 'shell',
517-
buffers: this.restoreBuffers(payload.buffers),
518-
content: {
519-
data: payload.data,
520-
comm_id: payload.commId
521-
},
522-
metadata: payload.metadata,
523-
// tslint:disable-next-line: no-any
524-
msgId: payload.requestId as any,
525-
session: kernel.clientId,
526-
username: kernel.username
527-
});
528-
// Note defined in type definition.
529-
// tslint:disable-next-line: no-any
530-
(shellMessage.content as any).target_name = payload.targetName;
531-
532-
// const shellMessage: KernelMessage.IShellMessage = KernelMessage.createMessage(
533-
// {
534-
// msgType: 'comm_msg',
535-
// channel: 'shell',
536-
// username: kernel.username,
537-
// session: kernel.clientId
538-
// },
539-
// {
540-
// data: payload.data,
541-
// comm_id: payload.commId,
542-
// target_name: 'jupyter.widget'
543-
// },
544-
// payload.metadata,
545-
// []
546-
// // tslint:disable-next-line: no-any
547-
// ) as any;
548-
// tslint:disable-next-line: no-any
549-
const requestId = (shellMessage.header.msg_id = payload.requestId as any);
550-
const future = kernel.sendShellMessage(shellMessage, false, true);
551-
future.done
552-
.then(reply => {
553-
this.postMessage(IPyWidgetMessages.IPyWidgets_ShellSend_resolve, { requestId, msg: reply }).catch(ex =>
554-
// tslint:disable-next-line: no-console
555-
console.error('Failed to post oniopub message for handler', ex)
556-
);
557-
})
558-
.catch(ex => {
559-
this.postMessage(IPyWidgetMessages.IPyWidgets_ShellSend_reject, { requestId, msg: ex }).catch(ex2 =>
560-
// tslint:disable-next-line: no-console
561-
console.error('Failed to post oniopub message for handler', ex2)
562-
);
563-
});
564-
future.onIOPub = (msg: KernelMessage.IIOPubMessage) => {
565-
this.serializeDataViews(msg);
566-
this.postMessage(IPyWidgetMessages.IPyWidgets_ShellSend_onIOPub, { requestId, msg }).catch(ex =>
567-
// tslint:disable-next-line: no-console
568-
console.error('Failed to post oniopub message for handler', ex)
569-
);
570-
571-
if (KernelMessage.isCommMsgMsg(msg)) {
572-
this.postMessage(IPyWidgetMessages.IPyWidgets_comm_msg, msg as KernelMessage.ICommMsgMsg).catch(ex =>
573-
// tslint:disable-next-line: no-console
574-
console.error('Failed to post oniopub message for handler', ex)
575-
);
576-
}
577-
};
578-
future.onReply = (reply: KernelMessage.IShellMessage) => {
579-
this.postMessage(IPyWidgetMessages.IPyWidgets_ShellSend_reply, { requestId, msg: reply }).catch(ex =>
580-
// tslint:disable-next-line: no-console
581-
console.error('Failed to post oniopub message for handler', ex)
582-
);
583-
};
584-
}
585360

586361
@captureTelemetry(Telemetry.SubmitCellThroughInput, undefined, false)
587362
// tslint:disable-next-line:no-any

src/client/datascience/interactive-window/interactiveWindow.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ export class InteractiveWindow extends InteractiveBase implements IInteractiveWi
132132
globalStorage,
133133
historyReactDir,
134134
[
135+
path.join(historyReactDir, 'require.js'),
136+
path.join(historyReactDir, 'ipywidgets.js'),
135137
path.join(historyReactDir, 'monaco.bundle.js'),
136138
path.join(historyReactDir, 'commons.initial.bundle.js'),
137139
path.join(historyReactDir, 'interactiveWindow.js')

0 commit comments

Comments
 (0)