jupyterpack 0.2.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/lib/document/commands.d.ts +8 -0
- package/lib/document/commands.js +76 -0
- package/lib/document/iframePanel.d.ts +4 -1
- package/lib/document/plugin.d.ts +2 -1
- package/lib/document/plugin.js +22 -4
- package/lib/document/toolbar.d.ts +9 -0
- package/lib/document/toolbar.js +20 -0
- package/lib/document/widgetFactory.d.ts +2 -1
- package/lib/document/widgetFactory.js +15 -6
- package/lib/index.d.ts +1 -1
- package/lib/pythonServer/dash/dashServer.d.ts +22 -0
- package/lib/pythonServer/dash/dashServer.js +47 -0
- package/lib/pythonServer/index.d.ts +5 -0
- package/lib/pythonServer/index.js +9 -0
- package/lib/pythonServer/kernelExecutor.d.ts +71 -0
- package/lib/pythonServer/kernelExecutor.js +140 -0
- package/lib/pythonServer/streamlit/streamlitServer.d.ts +14 -0
- package/lib/pythonServer/streamlit/streamlitServer.js +51 -0
- package/lib/pythonServer/tornado/tornadoServer.d.ts +34 -0
- package/lib/pythonServer/tornado/tornadoServer.js +68 -0
- package/lib/pythonWidget/comm.d.ts +11 -0
- package/lib/pythonWidget/comm.js +52 -0
- package/lib/pythonWidget/pythonWidget.d.ts +6 -0
- package/lib/pythonWidget/pythonWidget.js +28 -3
- package/lib/pythonWidget/pythonWidgetModel.d.ts +27 -6
- package/lib/pythonWidget/pythonWidgetModel.js +101 -15
- package/lib/sandpackWidget/sandpackFilesModel.d.ts +6 -2
- package/lib/sandpackWidget/sandpackFilesModel.js +13 -2
- package/lib/sandpackWidget/sandpackPanel.d.ts +10 -1
- package/lib/sandpackWidget/sandpackPanel.js +38 -3
- package/lib/swConnection/index.js +2 -2
- package/lib/{pythonWidget/connectionManager.d.ts → swConnection/mainConnectionManager.d.ts} +10 -0
- package/lib/swConnection/mainConnectionManager.js +93 -0
- package/lib/swConnection/sw.js +1 -1
- package/lib/swConnection/swCommManager.d.ts +11 -0
- package/lib/swConnection/{comm_manager.js → swCommManager.js} +5 -0
- package/lib/token.d.ts +2 -1
- package/lib/token.js +1 -0
- package/lib/tools.d.ts +9 -0
- package/lib/tools.js +75 -0
- package/lib/type.d.ts +64 -3
- package/lib/type.js +2 -0
- package/lib/websocket/websocket.d.ts +0 -0
- package/lib/websocket/websocket.js +152 -0
- package/package.json +8 -5
- package/src/document/commands.ts +91 -0
- package/src/document/iframePanel.ts +4 -1
- package/src/document/plugin.ts +28 -7
- package/src/document/toolbar.ts +39 -0
- package/src/document/widgetFactory.ts +17 -6
- package/src/global.d.ts +9 -0
- package/src/pythonServer/dash/dashServer.ts +66 -0
- package/src/pythonServer/index.ts +18 -0
- package/src/pythonServer/kernelExecutor.ts +243 -0
- package/src/pythonServer/streamlit/streamlitServer.ts +67 -0
- package/src/pythonServer/tornado/tornadoServer.ts +97 -0
- package/src/pythonWidget/comm.ts +65 -0
- package/src/pythonWidget/pythonWidget.ts +38 -3
- package/src/pythonWidget/pythonWidgetModel.ts +155 -34
- package/src/sandpackWidget/sandpackFilesModel.ts +17 -3
- package/src/sandpackWidget/sandpackPanel.ts +45 -4
- package/src/swConnection/index.ts +5 -2
- package/src/swConnection/mainConnectionManager.ts +121 -0
- package/src/swConnection/sw.ts +1 -1
- package/src/swConnection/{comm_manager.ts → swCommManager.ts} +6 -0
- package/src/token.ts +5 -1
- package/src/tools.ts +91 -0
- package/src/type.ts +76 -4
- package/src/websocket/websocket.ts +216 -0
- package/style/base.css +7 -0
- package/style/icons/autoreload.svg +16 -0
- package/style/icons/box.svg +12 -0
- package/style/icons/externallink.svg +10 -0
- package/lib/pythonWidget/connectionManager.js +0 -27
- package/lib/pythonWidget/kernelExecutor.d.ts +0 -27
- package/lib/pythonWidget/kernelExecutor.js +0 -104
- package/lib/swConnection/comm_manager.d.ts +0 -6
- package/lib/swConnection/connection_manager.d.ts +0 -18
- package/lib/swConnection/connection_manager.js +0 -27
- package/src/pythonWidget/connectionManager.ts +0 -43
- package/src/pythonWidget/kernelExecutor.ts +0 -140
- package/src/swConnection/connection_manager.ts +0 -43
package/README.md
CHANGED
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
- **Python Web Apps**: Serve Python web applications directly in the browser using JupyterLite's in-browser Python kernel. `jupyterpack` currently supports Dash.
|
|
11
11
|
- **JavaScript Web Apps**: Bundle and serve JavaScript web applications using in-browser bundlers.
|
|
12
12
|
|
|
13
|
+

|
|
14
|
+
|
|
13
15
|
## Installation
|
|
14
16
|
|
|
15
17
|
You can install `jupyterpack` using `pip` or `conda`
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { CommandRegistry } from '@lumino/commands';
|
|
2
|
+
import { IJupyterpackDocTracker } from '../type';
|
|
3
|
+
export declare const CommandIDs: {
|
|
4
|
+
RELOAD: string;
|
|
5
|
+
TOGGLE_AUTORELOAD: string;
|
|
6
|
+
OPEN_SPECTA: string;
|
|
7
|
+
};
|
|
8
|
+
export declare function addCommands(commands: CommandRegistry, tracker: IJupyterpackDocTracker): void;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { refreshIcon } from '@jupyterlab/ui-components';
|
|
2
|
+
import { autoReloadIcon, linkIcon } from '../tools';
|
|
3
|
+
import { PageConfig, URLExt } from '@jupyterlab/coreutils';
|
|
4
|
+
export const CommandIDs = {
|
|
5
|
+
RELOAD: 'jupyterpack:reload',
|
|
6
|
+
TOGGLE_AUTORELOAD: 'jupyterpack:toggleAutoreload',
|
|
7
|
+
OPEN_SPECTA: 'jupyterpack:openInSpecta'
|
|
8
|
+
};
|
|
9
|
+
const labBaseUrl = PageConfig.getOption('baseUrl');
|
|
10
|
+
function getCurrentIframPanel(tracker) {
|
|
11
|
+
var _a;
|
|
12
|
+
const current = (_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.content;
|
|
13
|
+
if (!current) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const widget = current.widgets[0];
|
|
17
|
+
if (!widget) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
return widget;
|
|
21
|
+
}
|
|
22
|
+
export function addCommands(commands, tracker) {
|
|
23
|
+
commands.addCommand(CommandIDs.RELOAD, {
|
|
24
|
+
caption: 'Reload',
|
|
25
|
+
isEnabled: () => {
|
|
26
|
+
return tracker.currentWidget !== null;
|
|
27
|
+
},
|
|
28
|
+
icon: refreshIcon,
|
|
29
|
+
execute: async () => {
|
|
30
|
+
const widget = getCurrentIframPanel(tracker);
|
|
31
|
+
if (widget) {
|
|
32
|
+
await widget.reload();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
const commandState = { toggled: false };
|
|
37
|
+
commands.addCommand(CommandIDs.TOGGLE_AUTORELOAD, {
|
|
38
|
+
isEnabled: () => {
|
|
39
|
+
return tracker.currentWidget !== null;
|
|
40
|
+
},
|
|
41
|
+
isToggled: () => {
|
|
42
|
+
const widget = getCurrentIframPanel(tracker);
|
|
43
|
+
return Boolean(widget === null || widget === void 0 ? void 0 : widget.autoreload);
|
|
44
|
+
},
|
|
45
|
+
icon: autoReloadIcon,
|
|
46
|
+
caption: e => {
|
|
47
|
+
return commandState.toggled
|
|
48
|
+
? 'Auto-reload enabled'
|
|
49
|
+
: 'Auto-reload disabled';
|
|
50
|
+
},
|
|
51
|
+
execute: async () => {
|
|
52
|
+
const widget = getCurrentIframPanel(tracker);
|
|
53
|
+
if (widget) {
|
|
54
|
+
widget.autoreload = !(widget === null || widget === void 0 ? void 0 : widget.autoreload);
|
|
55
|
+
commands.notifyCommandChanged(CommandIDs.TOGGLE_AUTORELOAD);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
commands.addCommand(CommandIDs.OPEN_SPECTA, {
|
|
60
|
+
caption: 'Open in Specta',
|
|
61
|
+
isEnabled: () => {
|
|
62
|
+
return tracker.currentWidget !== null;
|
|
63
|
+
},
|
|
64
|
+
icon: linkIcon,
|
|
65
|
+
execute: async () => {
|
|
66
|
+
var _a;
|
|
67
|
+
const context = (_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.context;
|
|
68
|
+
if (!context) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const spectaUrl = new URL(URLExt.join(labBaseUrl, 'specta'), window.location.origin);
|
|
72
|
+
spectaUrl.searchParams.set('path', context.path);
|
|
73
|
+
window.open(spectaUrl.toString(), '_blank');
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { Widget } from '@lumino/widgets';
|
|
2
|
-
export declare class IFramePanel extends Widget {
|
|
2
|
+
export declare abstract class IFramePanel extends Widget {
|
|
3
3
|
constructor();
|
|
4
4
|
toggleSpinner(show: boolean): void;
|
|
5
|
+
abstract reload(): Promise<void>;
|
|
6
|
+
abstract autoreload: boolean;
|
|
7
|
+
abstract isReady: Promise<void>;
|
|
5
8
|
protected _iframe: HTMLIFrameElement;
|
|
6
9
|
protected _spinner: HTMLDivElement;
|
|
7
10
|
}
|
package/lib/document/plugin.d.ts
CHANGED
package/lib/document/plugin.js
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import { JupyterPackWidgetFactory } from './widgetFactory';
|
|
2
|
-
import { IConnectionManagerToken } from '../token';
|
|
2
|
+
import { IConnectionManagerToken, IJupyterpackDocTrackerToken } from '../token';
|
|
3
|
+
import { WidgetTracker } from '@jupyterlab/apputils';
|
|
4
|
+
import { logoIcon } from '../tools';
|
|
5
|
+
import { addCommands } from './commands';
|
|
3
6
|
const FACTORY = 'jupyterpack';
|
|
4
7
|
const CONTENT_TYPE = 'jupyterpack';
|
|
5
8
|
export const spkPlugin = {
|
|
6
9
|
id: 'jupyterpack:spkplugin',
|
|
7
10
|
requires: [IConnectionManagerToken],
|
|
8
11
|
autoStart: true,
|
|
12
|
+
provides: IJupyterpackDocTrackerToken,
|
|
9
13
|
activate: (app, connectionManager) => {
|
|
14
|
+
const tracker = new WidgetTracker({
|
|
15
|
+
namespace: FACTORY
|
|
16
|
+
});
|
|
17
|
+
addCommands(app.commands, tracker);
|
|
10
18
|
const widgetFactory = new JupyterPackWidgetFactory({
|
|
11
19
|
name: FACTORY,
|
|
12
20
|
modelName: 'text',
|
|
@@ -14,7 +22,8 @@ export const spkPlugin = {
|
|
|
14
22
|
defaultFor: [CONTENT_TYPE],
|
|
15
23
|
commands: app.commands,
|
|
16
24
|
manager: app.serviceManager,
|
|
17
|
-
connectionManager
|
|
25
|
+
connectionManager,
|
|
26
|
+
tracker
|
|
18
27
|
});
|
|
19
28
|
// Registering the widget factory
|
|
20
29
|
app.docRegistry.addWidgetFactory(widgetFactory);
|
|
@@ -22,10 +31,19 @@ export const spkPlugin = {
|
|
|
22
31
|
app.docRegistry.addFileType({
|
|
23
32
|
name: CONTENT_TYPE,
|
|
24
33
|
displayName: 'SPK',
|
|
25
|
-
mimeTypes: ['
|
|
34
|
+
mimeTypes: ['application/json'],
|
|
26
35
|
extensions: ['.spk', '.SPK'],
|
|
27
36
|
fileFormat: 'json',
|
|
28
|
-
contentType: CONTENT_TYPE
|
|
37
|
+
contentType: CONTENT_TYPE,
|
|
38
|
+
icon: logoIcon
|
|
39
|
+
});
|
|
40
|
+
widgetFactory.widgetCreated.connect((_, widget) => {
|
|
41
|
+
widget.title.icon = logoIcon;
|
|
42
|
+
widget.context.pathChanged.connect(() => {
|
|
43
|
+
tracker.save(widget);
|
|
44
|
+
});
|
|
45
|
+
tracker.add(widget);
|
|
29
46
|
});
|
|
47
|
+
return tracker;
|
|
30
48
|
}
|
|
31
49
|
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ReactiveToolbar } from '@jupyterlab/ui-components';
|
|
2
|
+
import { CommandRegistry } from '@lumino/commands';
|
|
3
|
+
import { IJupyterpackDocTracker } from '../type';
|
|
4
|
+
export declare class ToolbarWidget extends ReactiveToolbar {
|
|
5
|
+
constructor(options: {
|
|
6
|
+
tracker: IJupyterpackDocTracker;
|
|
7
|
+
commands: CommandRegistry;
|
|
8
|
+
});
|
|
9
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { CommandToolbarButton, ReactiveToolbar } from '@jupyterlab/ui-components';
|
|
2
|
+
import { CommandIDs } from './commands';
|
|
3
|
+
export class ToolbarWidget extends ReactiveToolbar {
|
|
4
|
+
constructor(options) {
|
|
5
|
+
super();
|
|
6
|
+
this.addClass('jupyterpack-toolbar');
|
|
7
|
+
this.addItem('Reload', new CommandToolbarButton({
|
|
8
|
+
commands: options.commands,
|
|
9
|
+
id: CommandIDs.RELOAD
|
|
10
|
+
}));
|
|
11
|
+
this.addItem('Toggle Auto Reload', new CommandToolbarButton({
|
|
12
|
+
id: CommandIDs.TOGGLE_AUTORELOAD,
|
|
13
|
+
commands: options.commands
|
|
14
|
+
}));
|
|
15
|
+
this.addItem('Open Specta', new CommandToolbarButton({
|
|
16
|
+
id: CommandIDs.OPEN_SPECTA,
|
|
17
|
+
commands: options.commands
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { ABCWidgetFactory, DocumentRegistry } from '@jupyterlab/docregistry';
|
|
2
2
|
import { ServiceManager } from '@jupyterlab/services';
|
|
3
3
|
import { CommandRegistry } from '@lumino/commands';
|
|
4
|
-
import { IConnectionManager } from '../type';
|
|
4
|
+
import { IConnectionManager, IJupyterpackDocTracker } from '../type';
|
|
5
5
|
import { JupyterPackDocWidget } from './jupyterpackDocWidget';
|
|
6
6
|
interface IOptions extends DocumentRegistry.IWidgetFactoryOptions {
|
|
7
7
|
commands: CommandRegistry;
|
|
8
8
|
manager: ServiceManager.IManager;
|
|
9
9
|
connectionManager: IConnectionManager;
|
|
10
|
+
tracker: IJupyterpackDocTracker;
|
|
10
11
|
}
|
|
11
12
|
export declare class JupyterPackWidgetFactory extends ABCWidgetFactory<JupyterPackDocWidget> {
|
|
12
13
|
private options;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { ABCWidgetFactory } from '@jupyterlab/docregistry';
|
|
2
|
+
import { UUID } from '@lumino/coreutils';
|
|
2
3
|
import { Panel } from '@lumino/widgets';
|
|
3
|
-
import {
|
|
4
|
+
import { PythonWidget } from '../pythonWidget/pythonWidget';
|
|
5
|
+
import { PythonWidgetModel } from '../pythonWidget/pythonWidgetModel';
|
|
4
6
|
import { SandpackPanel } from '../sandpackWidget/sandpackPanel';
|
|
7
|
+
import { JupyterPackFramework } from '../type';
|
|
5
8
|
import { JupyterPackDocWidget } from './jupyterpackDocWidget';
|
|
6
|
-
import {
|
|
7
|
-
import { UUID } from '@lumino/coreutils';
|
|
8
|
-
import { PythonWidget } from '../pythonWidget/pythonWidget';
|
|
9
|
+
import { ToolbarWidget } from './toolbar';
|
|
9
10
|
export class JupyterPackWidgetFactory extends ABCWidgetFactory {
|
|
10
11
|
constructor(options) {
|
|
11
12
|
super(options);
|
|
@@ -32,8 +33,11 @@ export class JupyterPackWidgetFactory extends ABCWidgetFactory {
|
|
|
32
33
|
content.addWidget(jpContent);
|
|
33
34
|
break;
|
|
34
35
|
}
|
|
35
|
-
case JupyterPackFramework.DASH:
|
|
36
|
+
case JupyterPackFramework.DASH:
|
|
37
|
+
case JupyterPackFramework.STREAMLIT:
|
|
38
|
+
case JupyterPackFramework.TORNADO: {
|
|
36
39
|
const model = new PythonWidgetModel({
|
|
40
|
+
jpackModel,
|
|
37
41
|
context,
|
|
38
42
|
manager: this.options.manager,
|
|
39
43
|
contentsManager: this._contentsManager,
|
|
@@ -52,9 +56,14 @@ export class JupyterPackWidgetFactory extends ABCWidgetFactory {
|
|
|
52
56
|
}
|
|
53
57
|
}
|
|
54
58
|
});
|
|
59
|
+
const toolbar = new ToolbarWidget({
|
|
60
|
+
tracker: this.options.tracker,
|
|
61
|
+
commands: this.options.commands
|
|
62
|
+
});
|
|
55
63
|
return new JupyterPackDocWidget({
|
|
56
64
|
context,
|
|
57
|
-
content
|
|
65
|
+
content,
|
|
66
|
+
toolbar
|
|
58
67
|
});
|
|
59
68
|
}
|
|
60
69
|
}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: (import("@jupyterlab/application").JupyterFrontEndPlugin<
|
|
1
|
+
declare const _default: (import("@jupyterlab/application").JupyterFrontEndPlugin<import("./type").IJupyterpackDocTracker> | import("@jupyterlab/application").JupyterFrontEndPlugin<import("./type").IConnectionManager>)[];
|
|
2
2
|
export default _default;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { IDict } from '../../type';
|
|
2
|
+
import { KernelExecutor } from '../kernelExecutor';
|
|
3
|
+
export declare class DashServer extends KernelExecutor {
|
|
4
|
+
init(options: {
|
|
5
|
+
initCode?: string;
|
|
6
|
+
instanceId: string;
|
|
7
|
+
kernelClientId: string;
|
|
8
|
+
}): Promise<void>;
|
|
9
|
+
getResponseFunctionFactory(options: {
|
|
10
|
+
urlPath: string;
|
|
11
|
+
method: string;
|
|
12
|
+
headers: IDict;
|
|
13
|
+
params?: string;
|
|
14
|
+
content?: string;
|
|
15
|
+
}): string;
|
|
16
|
+
disposePythonServer(): Promise<void>;
|
|
17
|
+
reloadPythonServer(options: {
|
|
18
|
+
entryPath?: string;
|
|
19
|
+
initCode?: string;
|
|
20
|
+
}): Promise<void>;
|
|
21
|
+
private _DASH_SERVER_VAR;
|
|
22
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { stringOrNone } from '../../tools';
|
|
2
|
+
import { JupyterPackFramework } from '../../type';
|
|
3
|
+
import { KernelExecutor } from '../kernelExecutor';
|
|
4
|
+
export class DashServer extends KernelExecutor {
|
|
5
|
+
constructor() {
|
|
6
|
+
super(...arguments);
|
|
7
|
+
this._DASH_SERVER_VAR = '__jupyterpack_dash_server';
|
|
8
|
+
}
|
|
9
|
+
async init(options) {
|
|
10
|
+
await super.init(options);
|
|
11
|
+
const { initCode, instanceId, kernelClientId } = options;
|
|
12
|
+
const baseURL = this.buildBaseURL({
|
|
13
|
+
instanceId,
|
|
14
|
+
kernelClientId,
|
|
15
|
+
framework: JupyterPackFramework.DASH
|
|
16
|
+
});
|
|
17
|
+
await this.executeCode({
|
|
18
|
+
code: `
|
|
19
|
+
import os
|
|
20
|
+
os.environ["DASH_URL_BASE_PATHNAME"] = "${baseURL}"
|
|
21
|
+
`
|
|
22
|
+
});
|
|
23
|
+
if (initCode) {
|
|
24
|
+
await this.executeCode({ code: initCode });
|
|
25
|
+
}
|
|
26
|
+
const loaderCode = `
|
|
27
|
+
from jupyterpack.dash import DashServer
|
|
28
|
+
${this._DASH_SERVER_VAR} = DashServer(app, "${baseURL}")
|
|
29
|
+
`;
|
|
30
|
+
await this.executeCode({ code: loaderCode });
|
|
31
|
+
}
|
|
32
|
+
getResponseFunctionFactory(options) {
|
|
33
|
+
const { method, urlPath, headers, params, content } = options;
|
|
34
|
+
const code = `${this._DASH_SERVER_VAR}.get_response("${method}", "${urlPath}", headers=${JSON.stringify(headers)} , content=${stringOrNone(content)}, params=${stringOrNone(params)})`;
|
|
35
|
+
return code;
|
|
36
|
+
}
|
|
37
|
+
async disposePythonServer() {
|
|
38
|
+
await this.executeCode({ code: `${this._DASH_SERVER_VAR}.dispose()` });
|
|
39
|
+
}
|
|
40
|
+
async reloadPythonServer(options) {
|
|
41
|
+
const { initCode } = options;
|
|
42
|
+
if (initCode) {
|
|
43
|
+
await this.executeCode({ code: initCode });
|
|
44
|
+
}
|
|
45
|
+
await this.executeCode({ code: `${this._DASH_SERVER_VAR}.reload(app)` }, true);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { IKernelExecutor, JupyterPackFramework } from '../type';
|
|
2
|
+
import { KernelExecutor } from './kernelExecutor';
|
|
3
|
+
type KernelExecutorConstructor = new (options: KernelExecutor.IOptions) => IKernelExecutor;
|
|
4
|
+
export declare const PYTHON_SERVER: Map<JupyterPackFramework, KernelExecutorConstructor>;
|
|
5
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { JupyterPackFramework } from '../type';
|
|
2
|
+
import { DashServer } from './dash/dashServer';
|
|
3
|
+
import { StreamlitServer } from './streamlit/streamlitServer';
|
|
4
|
+
import { TornadoServer } from './tornado/tornadoServer';
|
|
5
|
+
export const PYTHON_SERVER = new Map([
|
|
6
|
+
[JupyterPackFramework.DASH, DashServer],
|
|
7
|
+
[JupyterPackFramework.STREAMLIT, StreamlitServer],
|
|
8
|
+
[JupyterPackFramework.TORNADO, TornadoServer]
|
|
9
|
+
]);
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { KernelMessage, Session } from '@jupyterlab/services';
|
|
2
|
+
import { IDict, IKernelExecutor, JupyterPackFramework } from '../type';
|
|
3
|
+
export declare abstract class KernelExecutor implements IKernelExecutor {
|
|
4
|
+
constructor(options: KernelExecutor.IOptions);
|
|
5
|
+
get isDisposed(): boolean;
|
|
6
|
+
abstract disposePythonServer(): Promise<void>;
|
|
7
|
+
abstract reloadPythonServer(options: {
|
|
8
|
+
entryPath?: string;
|
|
9
|
+
initCode?: string;
|
|
10
|
+
}): Promise<void>;
|
|
11
|
+
abstract getResponseFunctionFactory(options: {
|
|
12
|
+
urlPath: string;
|
|
13
|
+
method: string;
|
|
14
|
+
headers: IDict;
|
|
15
|
+
params?: string;
|
|
16
|
+
content?: string;
|
|
17
|
+
}): string;
|
|
18
|
+
init(options: {
|
|
19
|
+
entryPath?: string;
|
|
20
|
+
initCode?: string;
|
|
21
|
+
instanceId: string;
|
|
22
|
+
kernelClientId: string;
|
|
23
|
+
}): Promise<void>;
|
|
24
|
+
openWebsocketFunctionFactory(options: {
|
|
25
|
+
instanceId: string;
|
|
26
|
+
kernelId: string;
|
|
27
|
+
wsUrl: string;
|
|
28
|
+
protocol?: string;
|
|
29
|
+
}): string | undefined;
|
|
30
|
+
sendWebsocketMessageFunctionFactory(options: {
|
|
31
|
+
instanceId: string;
|
|
32
|
+
kernelId: string;
|
|
33
|
+
wsUrl: string;
|
|
34
|
+
message: string;
|
|
35
|
+
}): string | undefined;
|
|
36
|
+
openWebsocket(options: {
|
|
37
|
+
instanceId: string;
|
|
38
|
+
kernelId: string;
|
|
39
|
+
wsUrl: string;
|
|
40
|
+
protocol?: string;
|
|
41
|
+
}): Promise<void>;
|
|
42
|
+
sendWebsocketMessage(options: {
|
|
43
|
+
instanceId: string;
|
|
44
|
+
kernelId: string;
|
|
45
|
+
wsUrl: string;
|
|
46
|
+
message: string;
|
|
47
|
+
}): Promise<void>;
|
|
48
|
+
getResponse(options: {
|
|
49
|
+
method: string;
|
|
50
|
+
urlPath: string;
|
|
51
|
+
headers: IDict;
|
|
52
|
+
requestBody?: ArrayBuffer;
|
|
53
|
+
params?: string;
|
|
54
|
+
}): Promise<IDict>;
|
|
55
|
+
executeCode(code: KernelMessage.IExecuteRequestMsg['content'], waitForResult?: boolean): Promise<string | null>;
|
|
56
|
+
dispose(): void;
|
|
57
|
+
protected buildBaseURL(options: {
|
|
58
|
+
instanceId: string;
|
|
59
|
+
kernelClientId: string;
|
|
60
|
+
framework: JupyterPackFramework;
|
|
61
|
+
}): string;
|
|
62
|
+
protected _baseUrl: string | undefined;
|
|
63
|
+
private _isDisposed;
|
|
64
|
+
private _sessionConnection;
|
|
65
|
+
private _wsPatch;
|
|
66
|
+
}
|
|
67
|
+
export declare namespace KernelExecutor {
|
|
68
|
+
interface IOptions {
|
|
69
|
+
sessionConnection: Session.ISessionConnection;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { PageConfig, URLExt } from '@jupyterlab/coreutils';
|
|
2
|
+
import stripAnsi from 'strip-ansi';
|
|
3
|
+
import { arrayBufferToBase64, base64ToArrayBuffer, base64ToString, isBinaryContentType } from '../tools';
|
|
4
|
+
import websocketPatch from '../websocket/websocket.js?raw';
|
|
5
|
+
export class KernelExecutor {
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this._isDisposed = false;
|
|
8
|
+
this._sessionConnection = options.sessionConnection;
|
|
9
|
+
this._wsPatch = websocketPatch.replaceAll('"use strict";', '');
|
|
10
|
+
}
|
|
11
|
+
get isDisposed() {
|
|
12
|
+
return this._isDisposed;
|
|
13
|
+
}
|
|
14
|
+
async init(options) {
|
|
15
|
+
const patchCode = `
|
|
16
|
+
from jupyterpack.common import patch_all
|
|
17
|
+
patch_all()
|
|
18
|
+
`;
|
|
19
|
+
await this.executeCode({ code: patchCode });
|
|
20
|
+
}
|
|
21
|
+
openWebsocketFunctionFactory(options) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
sendWebsocketMessageFunctionFactory(options) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
async openWebsocket(options) {
|
|
28
|
+
const code = this.openWebsocketFunctionFactory(options);
|
|
29
|
+
if (code) {
|
|
30
|
+
await this.executeCode({ code });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async sendWebsocketMessage(options) {
|
|
34
|
+
const code = this.sendWebsocketMessageFunctionFactory(options);
|
|
35
|
+
if (code) {
|
|
36
|
+
await this.executeCode({ code });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async getResponse(options) {
|
|
40
|
+
var _a;
|
|
41
|
+
const { method, urlPath, requestBody, params, headers } = options;
|
|
42
|
+
const content = requestBody ? arrayBufferToBase64(requestBody) : undefined;
|
|
43
|
+
const code = this.getResponseFunctionFactory({
|
|
44
|
+
method,
|
|
45
|
+
urlPath,
|
|
46
|
+
headers,
|
|
47
|
+
params,
|
|
48
|
+
content
|
|
49
|
+
});
|
|
50
|
+
const raw = await this.executeCode({ code }, true);
|
|
51
|
+
if (!raw) {
|
|
52
|
+
throw new Error(`Missing response for ${urlPath}`);
|
|
53
|
+
}
|
|
54
|
+
const jsonStr = raw.replaceAll("'", '');
|
|
55
|
+
const obj = JSON.parse(jsonStr);
|
|
56
|
+
const responseHeaders = JSON.parse(atob(obj.headers));
|
|
57
|
+
const contentType = (_a = responseHeaders === null || responseHeaders === void 0 ? void 0 : responseHeaders['Content-Type']) !== null && _a !== void 0 ? _a : responseHeaders === null || responseHeaders === void 0 ? void 0 : responseHeaders['content-type'];
|
|
58
|
+
let responseContent;
|
|
59
|
+
if (isBinaryContentType(contentType)) {
|
|
60
|
+
responseContent = base64ToArrayBuffer(obj.content);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
responseContent = base64ToString(obj.content);
|
|
64
|
+
}
|
|
65
|
+
if (contentType && contentType.toLowerCase() === 'text/html') {
|
|
66
|
+
responseContent = responseContent.replace('<head>', `<head>\n<script>\n${this._wsPatch}\n</script>\n`);
|
|
67
|
+
}
|
|
68
|
+
const decodedObj = {
|
|
69
|
+
status_code: obj.status_code,
|
|
70
|
+
headers: responseHeaders,
|
|
71
|
+
content: responseContent
|
|
72
|
+
};
|
|
73
|
+
return decodedObj;
|
|
74
|
+
}
|
|
75
|
+
async executeCode(code, waitForResult) {
|
|
76
|
+
var _a;
|
|
77
|
+
const kernel = (_a = this._sessionConnection) === null || _a === void 0 ? void 0 : _a.kernel;
|
|
78
|
+
if (!kernel) {
|
|
79
|
+
throw new Error('Session has no kernel.');
|
|
80
|
+
}
|
|
81
|
+
return new Promise((resolve, reject) => {
|
|
82
|
+
const future = kernel.requestExecute(code, false, undefined);
|
|
83
|
+
let executeResult = '';
|
|
84
|
+
future.onIOPub = (msg) => {
|
|
85
|
+
const msgType = msg.header.msg_type;
|
|
86
|
+
switch (msgType) {
|
|
87
|
+
case 'execute_result': {
|
|
88
|
+
if (waitForResult) {
|
|
89
|
+
const content = msg.content
|
|
90
|
+
.data['text/plain'];
|
|
91
|
+
executeResult += content;
|
|
92
|
+
resolve(executeResult);
|
|
93
|
+
}
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
case 'stream': {
|
|
97
|
+
const content = msg.content;
|
|
98
|
+
if (content.text.length === 0) {
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
if (content.name === 'stderr') {
|
|
102
|
+
console.error('Kernel stream:', content.text);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
console.log('Kernel stream:', content.text);
|
|
106
|
+
}
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
case 'error': {
|
|
110
|
+
console.error('Kernel operation failed', code.code, msg.content.traceback
|
|
111
|
+
.map((it) => stripAnsi(it))
|
|
112
|
+
.join('\n'));
|
|
113
|
+
reject(msg.content);
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
default:
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
if (!waitForResult) {
|
|
121
|
+
resolve(null);
|
|
122
|
+
// future.dispose() # TODO
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
dispose() {
|
|
127
|
+
if (this._isDisposed) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
this._isDisposed = true;
|
|
131
|
+
this._sessionConnection.dispose();
|
|
132
|
+
}
|
|
133
|
+
buildBaseURL(options) {
|
|
134
|
+
const { instanceId, kernelClientId, framework } = options;
|
|
135
|
+
const fullLabextensionsUrl = PageConfig.getOption('fullLabextensionsUrl');
|
|
136
|
+
const baseURL = URLExt.join(fullLabextensionsUrl, 'jupyterpack/static', instanceId, framework, kernelClientId, '/');
|
|
137
|
+
this._baseUrl = baseURL;
|
|
138
|
+
return baseURL;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { TornadoServer } from '../tornado/tornadoServer';
|
|
2
|
+
export declare class StreamlitServer extends TornadoServer {
|
|
3
|
+
init(options: {
|
|
4
|
+
entryPath?: string;
|
|
5
|
+
initCode?: string;
|
|
6
|
+
instanceId: string;
|
|
7
|
+
kernelClientId: string;
|
|
8
|
+
}): Promise<void>;
|
|
9
|
+
reloadPythonServer(options: {
|
|
10
|
+
entryPath?: string;
|
|
11
|
+
initCode?: string;
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
protected _SERVER_VAR: string;
|
|
14
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { JupyterPackFramework } from '../../type';
|
|
2
|
+
import { TornadoServer } from '../tornado/tornadoServer';
|
|
3
|
+
export class StreamlitServer extends TornadoServer {
|
|
4
|
+
constructor() {
|
|
5
|
+
super(...arguments);
|
|
6
|
+
this._SERVER_VAR = '__jupyterpack_streamlit_server';
|
|
7
|
+
}
|
|
8
|
+
async init(options) {
|
|
9
|
+
const { instanceId, kernelClientId, entryPath } = options;
|
|
10
|
+
if (!entryPath) {
|
|
11
|
+
throw new Error('Missing streamlit entry path, please check your SPK file');
|
|
12
|
+
}
|
|
13
|
+
const baseURL = this.buildBaseURL({
|
|
14
|
+
instanceId,
|
|
15
|
+
kernelClientId,
|
|
16
|
+
framework: JupyterPackFramework.STREAMLIT
|
|
17
|
+
});
|
|
18
|
+
const patchCode = `
|
|
19
|
+
from jupyterpack.common import set_base_url_env, patch_tornado, patch_all
|
|
20
|
+
patch_all()
|
|
21
|
+
patch_tornado()
|
|
22
|
+
set_base_url_env("${baseURL}")
|
|
23
|
+
`;
|
|
24
|
+
await this.executeCode({ code: patchCode });
|
|
25
|
+
const bootstrapCode = `
|
|
26
|
+
from jupyterpack.streamlit import patch_streamlit
|
|
27
|
+
patch_streamlit()
|
|
28
|
+
`;
|
|
29
|
+
await this.executeCode({ code: bootstrapCode });
|
|
30
|
+
const stCode = `
|
|
31
|
+
from jupyterpack.streamlit import StreamlitServer, create_streamlit_app
|
|
32
|
+
__jupyterpack_st_server, __jupyterpack_tor_app = await create_streamlit_app("${entryPath}", "${baseURL}")
|
|
33
|
+
${this._SERVER_VAR} = StreamlitServer(__jupyterpack_tor_app, "${baseURL}", __jupyterpack_st_server)
|
|
34
|
+
`;
|
|
35
|
+
await this.executeCode({ code: stCode });
|
|
36
|
+
}
|
|
37
|
+
async reloadPythonServer(options) {
|
|
38
|
+
const { entryPath } = options;
|
|
39
|
+
if (!entryPath || !this._baseUrl) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const reloadCode = `
|
|
43
|
+
${this._SERVER_VAR}.dispose()
|
|
44
|
+
__jupyterpack_st_server, __jupyterpack_tor_app = await create_streamlit_app("${entryPath}", "${this._baseUrl}")
|
|
45
|
+
${this._SERVER_VAR}.reload(__jupyterpack_tor_app, __jupyterpack_st_server)
|
|
46
|
+
`;
|
|
47
|
+
await this.executeCode({
|
|
48
|
+
code: reloadCode
|
|
49
|
+
}, true);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { IDict } from '../../type';
|
|
2
|
+
import { KernelExecutor } from '../kernelExecutor';
|
|
3
|
+
export declare class TornadoServer extends KernelExecutor {
|
|
4
|
+
init(options: {
|
|
5
|
+
initCode?: string;
|
|
6
|
+
instanceId: string;
|
|
7
|
+
kernelClientId: string;
|
|
8
|
+
}): Promise<void>;
|
|
9
|
+
getResponseFunctionFactory(options: {
|
|
10
|
+
urlPath: string;
|
|
11
|
+
method: string;
|
|
12
|
+
headers: IDict;
|
|
13
|
+
params?: string;
|
|
14
|
+
content?: string;
|
|
15
|
+
}): string;
|
|
16
|
+
openWebsocketFunctionFactory(options: {
|
|
17
|
+
instanceId: string;
|
|
18
|
+
kernelId: string;
|
|
19
|
+
wsUrl: string;
|
|
20
|
+
protocol?: string;
|
|
21
|
+
}): string;
|
|
22
|
+
sendWebsocketMessageFunctionFactory(options: {
|
|
23
|
+
instanceId: string;
|
|
24
|
+
kernelId: string;
|
|
25
|
+
wsUrl: string;
|
|
26
|
+
message: string;
|
|
27
|
+
}): string;
|
|
28
|
+
disposePythonServer(): Promise<void>;
|
|
29
|
+
reloadPythonServer(options: {
|
|
30
|
+
entryPath?: string;
|
|
31
|
+
initCode?: string;
|
|
32
|
+
}): Promise<void>;
|
|
33
|
+
protected _SERVER_VAR: string;
|
|
34
|
+
}
|