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.
Files changed (83) hide show
  1. package/README.md +2 -0
  2. package/lib/document/commands.d.ts +8 -0
  3. package/lib/document/commands.js +76 -0
  4. package/lib/document/iframePanel.d.ts +4 -1
  5. package/lib/document/plugin.d.ts +2 -1
  6. package/lib/document/plugin.js +22 -4
  7. package/lib/document/toolbar.d.ts +9 -0
  8. package/lib/document/toolbar.js +20 -0
  9. package/lib/document/widgetFactory.d.ts +2 -1
  10. package/lib/document/widgetFactory.js +15 -6
  11. package/lib/index.d.ts +1 -1
  12. package/lib/pythonServer/dash/dashServer.d.ts +22 -0
  13. package/lib/pythonServer/dash/dashServer.js +47 -0
  14. package/lib/pythonServer/index.d.ts +5 -0
  15. package/lib/pythonServer/index.js +9 -0
  16. package/lib/pythonServer/kernelExecutor.d.ts +71 -0
  17. package/lib/pythonServer/kernelExecutor.js +140 -0
  18. package/lib/pythonServer/streamlit/streamlitServer.d.ts +14 -0
  19. package/lib/pythonServer/streamlit/streamlitServer.js +51 -0
  20. package/lib/pythonServer/tornado/tornadoServer.d.ts +34 -0
  21. package/lib/pythonServer/tornado/tornadoServer.js +68 -0
  22. package/lib/pythonWidget/comm.d.ts +11 -0
  23. package/lib/pythonWidget/comm.js +52 -0
  24. package/lib/pythonWidget/pythonWidget.d.ts +6 -0
  25. package/lib/pythonWidget/pythonWidget.js +28 -3
  26. package/lib/pythonWidget/pythonWidgetModel.d.ts +27 -6
  27. package/lib/pythonWidget/pythonWidgetModel.js +101 -15
  28. package/lib/sandpackWidget/sandpackFilesModel.d.ts +6 -2
  29. package/lib/sandpackWidget/sandpackFilesModel.js +13 -2
  30. package/lib/sandpackWidget/sandpackPanel.d.ts +10 -1
  31. package/lib/sandpackWidget/sandpackPanel.js +38 -3
  32. package/lib/swConnection/index.js +2 -2
  33. package/lib/{pythonWidget/connectionManager.d.ts → swConnection/mainConnectionManager.d.ts} +10 -0
  34. package/lib/swConnection/mainConnectionManager.js +93 -0
  35. package/lib/swConnection/sw.js +1 -1
  36. package/lib/swConnection/swCommManager.d.ts +11 -0
  37. package/lib/swConnection/{comm_manager.js → swCommManager.js} +5 -0
  38. package/lib/token.d.ts +2 -1
  39. package/lib/token.js +1 -0
  40. package/lib/tools.d.ts +9 -0
  41. package/lib/tools.js +75 -0
  42. package/lib/type.d.ts +64 -3
  43. package/lib/type.js +2 -0
  44. package/lib/websocket/websocket.d.ts +0 -0
  45. package/lib/websocket/websocket.js +152 -0
  46. package/package.json +8 -5
  47. package/src/document/commands.ts +91 -0
  48. package/src/document/iframePanel.ts +4 -1
  49. package/src/document/plugin.ts +28 -7
  50. package/src/document/toolbar.ts +39 -0
  51. package/src/document/widgetFactory.ts +17 -6
  52. package/src/global.d.ts +9 -0
  53. package/src/pythonServer/dash/dashServer.ts +66 -0
  54. package/src/pythonServer/index.ts +18 -0
  55. package/src/pythonServer/kernelExecutor.ts +243 -0
  56. package/src/pythonServer/streamlit/streamlitServer.ts +67 -0
  57. package/src/pythonServer/tornado/tornadoServer.ts +97 -0
  58. package/src/pythonWidget/comm.ts +65 -0
  59. package/src/pythonWidget/pythonWidget.ts +38 -3
  60. package/src/pythonWidget/pythonWidgetModel.ts +155 -34
  61. package/src/sandpackWidget/sandpackFilesModel.ts +17 -3
  62. package/src/sandpackWidget/sandpackPanel.ts +45 -4
  63. package/src/swConnection/index.ts +5 -2
  64. package/src/swConnection/mainConnectionManager.ts +121 -0
  65. package/src/swConnection/sw.ts +1 -1
  66. package/src/swConnection/{comm_manager.ts → swCommManager.ts} +6 -0
  67. package/src/token.ts +5 -1
  68. package/src/tools.ts +91 -0
  69. package/src/type.ts +76 -4
  70. package/src/websocket/websocket.ts +216 -0
  71. package/style/base.css +7 -0
  72. package/style/icons/autoreload.svg +16 -0
  73. package/style/icons/box.svg +12 -0
  74. package/style/icons/externallink.svg +10 -0
  75. package/lib/pythonWidget/connectionManager.js +0 -27
  76. package/lib/pythonWidget/kernelExecutor.d.ts +0 -27
  77. package/lib/pythonWidget/kernelExecutor.js +0 -104
  78. package/lib/swConnection/comm_manager.d.ts +0 -6
  79. package/lib/swConnection/connection_manager.d.ts +0 -18
  80. package/lib/swConnection/connection_manager.js +0 -27
  81. package/src/pythonWidget/connectionManager.ts +0 -43
  82. package/src/pythonWidget/kernelExecutor.ts +0 -140
  83. package/src/swConnection/connection_manager.ts +0 -43
@@ -4,20 +4,29 @@ import {
4
4
  } from '@jupyterlab/application';
5
5
 
6
6
  import { JupyterPackWidgetFactory } from './widgetFactory';
7
- import { IConnectionManager } from '../type';
8
- import { IConnectionManagerToken } from '../token';
7
+ import { IConnectionManager, IJupyterpackDocTracker } from '../type';
8
+ import { IConnectionManagerToken, IJupyterpackDocTrackerToken } from '../token';
9
+ import { WidgetTracker } from '@jupyterlab/apputils';
10
+ import { DocumentWidget } from '@jupyterlab/docregistry';
11
+ import { logoIcon } from '../tools';
12
+ import { addCommands } from './commands';
9
13
 
10
14
  const FACTORY = 'jupyterpack';
11
15
  const CONTENT_TYPE = 'jupyterpack';
12
16
 
13
- export const spkPlugin: JupyterFrontEndPlugin<void> = {
17
+ export const spkPlugin: JupyterFrontEndPlugin<IJupyterpackDocTracker> = {
14
18
  id: 'jupyterpack:spkplugin',
15
19
  requires: [IConnectionManagerToken],
16
20
  autoStart: true,
21
+ provides: IJupyterpackDocTrackerToken,
17
22
  activate: (
18
23
  app: JupyterFrontEnd,
19
24
  connectionManager: IConnectionManager
20
- ): void => {
25
+ ): IJupyterpackDocTracker => {
26
+ const tracker = new WidgetTracker<DocumentWidget>({
27
+ namespace: FACTORY
28
+ });
29
+ addCommands(app.commands, tracker);
21
30
  const widgetFactory = new JupyterPackWidgetFactory({
22
31
  name: FACTORY,
23
32
  modelName: 'text',
@@ -25,7 +34,8 @@ export const spkPlugin: JupyterFrontEndPlugin<void> = {
25
34
  defaultFor: [CONTENT_TYPE],
26
35
  commands: app.commands,
27
36
  manager: app.serviceManager,
28
- connectionManager
37
+ connectionManager,
38
+ tracker
29
39
  });
30
40
 
31
41
  // Registering the widget factory
@@ -35,10 +45,21 @@ export const spkPlugin: JupyterFrontEndPlugin<void> = {
35
45
  app.docRegistry.addFileType({
36
46
  name: CONTENT_TYPE,
37
47
  displayName: 'SPK',
38
- mimeTypes: ['text/json'],
48
+ mimeTypes: ['application/json'],
39
49
  extensions: ['.spk', '.SPK'],
40
50
  fileFormat: 'json',
41
- contentType: CONTENT_TYPE
51
+ contentType: CONTENT_TYPE,
52
+ icon: logoIcon
53
+ });
54
+
55
+ widgetFactory.widgetCreated.connect((_, widget) => {
56
+ widget.title.icon = logoIcon;
57
+ widget.context.pathChanged.connect(() => {
58
+ tracker.save(widget);
59
+ });
60
+ tracker.add(widget);
42
61
  });
62
+
63
+ return tracker;
43
64
  }
44
65
  };
@@ -0,0 +1,39 @@
1
+ import {
2
+ CommandToolbarButton,
3
+ ReactiveToolbar
4
+ } from '@jupyterlab/ui-components';
5
+ import { CommandRegistry } from '@lumino/commands';
6
+
7
+ import { IJupyterpackDocTracker } from '../type';
8
+ import { CommandIDs } from './commands';
9
+
10
+ export class ToolbarWidget extends ReactiveToolbar {
11
+ constructor(options: {
12
+ tracker: IJupyterpackDocTracker;
13
+ commands: CommandRegistry;
14
+ }) {
15
+ super();
16
+ this.addClass('jupyterpack-toolbar');
17
+ this.addItem(
18
+ 'Reload',
19
+ new CommandToolbarButton({
20
+ commands: options.commands,
21
+ id: CommandIDs.RELOAD
22
+ })
23
+ );
24
+ this.addItem(
25
+ 'Toggle Auto Reload',
26
+ new CommandToolbarButton({
27
+ id: CommandIDs.TOGGLE_AUTORELOAD,
28
+ commands: options.commands
29
+ })
30
+ );
31
+ this.addItem(
32
+ 'Open Specta',
33
+ new CommandToolbarButton({
34
+ id: CommandIDs.OPEN_SPECTA,
35
+ commands: options.commands
36
+ })
37
+ );
38
+ }
39
+ }
@@ -1,23 +1,26 @@
1
1
  import { ABCWidgetFactory, DocumentRegistry } from '@jupyterlab/docregistry';
2
2
  import { Contents, ServiceManager } from '@jupyterlab/services';
3
3
  import { CommandRegistry } from '@lumino/commands';
4
+ import { UUID } from '@lumino/coreutils';
4
5
  import { Panel } from '@lumino/widgets';
5
6
 
7
+ import { PythonWidget } from '../pythonWidget/pythonWidget';
8
+ import { PythonWidgetModel } from '../pythonWidget/pythonWidgetModel';
9
+ import { SandpackPanel } from '../sandpackWidget/sandpackPanel';
6
10
  import {
7
11
  IConnectionManager,
12
+ IJupyterpackDocTracker,
8
13
  IJupyterPackFileFormat,
9
14
  JupyterPackFramework
10
15
  } from '../type';
11
- import { SandpackPanel } from '../sandpackWidget/sandpackPanel';
12
16
  import { JupyterPackDocWidget } from './jupyterpackDocWidget';
13
- import { PythonWidgetModel } from '../pythonWidget/pythonWidgetModel';
14
- import { UUID } from '@lumino/coreutils';
15
- import { PythonWidget } from '../pythonWidget/pythonWidget';
17
+ import { ToolbarWidget } from './toolbar';
16
18
 
17
19
  interface IOptions extends DocumentRegistry.IWidgetFactoryOptions {
18
20
  commands: CommandRegistry;
19
21
  manager: ServiceManager.IManager;
20
22
  connectionManager: IConnectionManager;
23
+ tracker: IJupyterpackDocTracker;
21
24
  }
22
25
 
23
26
  export class JupyterPackWidgetFactory extends ABCWidgetFactory<JupyterPackDocWidget> {
@@ -49,8 +52,11 @@ export class JupyterPackWidgetFactory extends ABCWidgetFactory<JupyterPackDocWid
49
52
  content.addWidget(jpContent);
50
53
  break;
51
54
  }
52
- case JupyterPackFramework.DASH: {
55
+ case JupyterPackFramework.DASH:
56
+ case JupyterPackFramework.STREAMLIT:
57
+ case JupyterPackFramework.TORNADO: {
53
58
  const model = new PythonWidgetModel({
59
+ jpackModel,
54
60
  context,
55
61
  manager: this.options.manager,
56
62
  contentsManager: this._contentsManager,
@@ -69,9 +75,14 @@ export class JupyterPackWidgetFactory extends ABCWidgetFactory<JupyterPackDocWid
69
75
  }
70
76
  }
71
77
  });
78
+ const toolbar = new ToolbarWidget({
79
+ tracker: this.options.tracker,
80
+ commands: this.options.commands
81
+ });
72
82
  return new JupyterPackDocWidget({
73
83
  context,
74
- content
84
+ content,
85
+ toolbar
75
86
  });
76
87
  }
77
88
 
@@ -0,0 +1,9 @@
1
+ declare module '*?raw' {
2
+ const content: string;
3
+ export default content;
4
+ }
5
+
6
+ declare module '*.svg' {
7
+ const value: string;
8
+ export default value;
9
+ }
@@ -0,0 +1,66 @@
1
+ import { stringOrNone } from '../../tools';
2
+ import { IDict, JupyterPackFramework } from '../../type';
3
+ import { KernelExecutor } from '../kernelExecutor';
4
+
5
+ export class DashServer extends KernelExecutor {
6
+ async init(options: {
7
+ initCode?: string;
8
+ instanceId: string;
9
+ kernelClientId: string;
10
+ }) {
11
+ await super.init(options);
12
+ const { initCode, instanceId, kernelClientId } = options;
13
+
14
+ const baseURL = this.buildBaseURL({
15
+ instanceId,
16
+ kernelClientId,
17
+ framework: JupyterPackFramework.DASH
18
+ });
19
+ await this.executeCode({
20
+ code: `
21
+ import os
22
+ os.environ["DASH_URL_BASE_PATHNAME"] = "${baseURL}"
23
+ `
24
+ });
25
+ if (initCode) {
26
+ await this.executeCode({ code: initCode });
27
+ }
28
+ const loaderCode = `
29
+ from jupyterpack.dash import DashServer
30
+ ${this._DASH_SERVER_VAR} = DashServer(app, "${baseURL}")
31
+ `;
32
+ await this.executeCode({ code: loaderCode });
33
+ }
34
+
35
+ getResponseFunctionFactory(options: {
36
+ urlPath: string;
37
+ method: string;
38
+ headers: IDict;
39
+ params?: string;
40
+ content?: string;
41
+ }) {
42
+ const { method, urlPath, headers, params, content } = options;
43
+ const code = `${this._DASH_SERVER_VAR}.get_response("${method}", "${urlPath}", headers=${JSON.stringify(headers)} , content=${stringOrNone(content)}, params=${stringOrNone(params)})`;
44
+ return code;
45
+ }
46
+
47
+ async disposePythonServer(): Promise<void> {
48
+ await this.executeCode({ code: `${this._DASH_SERVER_VAR}.dispose()` });
49
+ }
50
+
51
+ async reloadPythonServer(options: {
52
+ entryPath?: string;
53
+ initCode?: string;
54
+ }): Promise<void> {
55
+ const { initCode } = options;
56
+ if (initCode) {
57
+ await this.executeCode({ code: initCode });
58
+ }
59
+ await this.executeCode(
60
+ { code: `${this._DASH_SERVER_VAR}.reload(app)` },
61
+ true
62
+ );
63
+ }
64
+
65
+ private _DASH_SERVER_VAR = '__jupyterpack_dash_server';
66
+ }
@@ -0,0 +1,18 @@
1
+ import { IKernelExecutor, JupyterPackFramework } from '../type';
2
+ import { DashServer } from './dash/dashServer';
3
+ import { KernelExecutor } from './kernelExecutor';
4
+ import { StreamlitServer } from './streamlit/streamlitServer';
5
+ import { TornadoServer } from './tornado/tornadoServer';
6
+
7
+ type KernelExecutorConstructor = new (
8
+ options: KernelExecutor.IOptions
9
+ ) => IKernelExecutor;
10
+
11
+ export const PYTHON_SERVER = new Map<
12
+ JupyterPackFramework,
13
+ KernelExecutorConstructor
14
+ >([
15
+ [JupyterPackFramework.DASH, DashServer],
16
+ [JupyterPackFramework.STREAMLIT, StreamlitServer],
17
+ [JupyterPackFramework.TORNADO, TornadoServer]
18
+ ]);
@@ -0,0 +1,243 @@
1
+ import { PageConfig, URLExt } from '@jupyterlab/coreutils';
2
+ import { KernelMessage, Session } from '@jupyterlab/services';
3
+ import stripAnsi from 'strip-ansi';
4
+ import {
5
+ arrayBufferToBase64,
6
+ base64ToArrayBuffer,
7
+ base64ToString,
8
+ isBinaryContentType
9
+ } from '../tools';
10
+ import { IDict, IKernelExecutor, JupyterPackFramework } from '../type';
11
+ import websocketPatch from '../websocket/websocket.js?raw';
12
+
13
+ export abstract class KernelExecutor implements IKernelExecutor {
14
+ constructor(options: KernelExecutor.IOptions) {
15
+ this._sessionConnection = options.sessionConnection;
16
+ this._wsPatch = websocketPatch.replaceAll('"use strict";', '');
17
+ }
18
+
19
+ get isDisposed(): boolean {
20
+ return this._isDisposed;
21
+ }
22
+
23
+ abstract disposePythonServer(): Promise<void>;
24
+ abstract reloadPythonServer(options: {
25
+ entryPath?: string;
26
+ initCode?: string;
27
+ }): Promise<void>;
28
+
29
+ abstract getResponseFunctionFactory(options: {
30
+ urlPath: string;
31
+ method: string;
32
+ headers: IDict;
33
+ params?: string;
34
+ content?: string;
35
+ }): string;
36
+
37
+ async init(options: {
38
+ entryPath?: string;
39
+ initCode?: string;
40
+ instanceId: string;
41
+ kernelClientId: string;
42
+ }): Promise<void> {
43
+ const patchCode = `
44
+ from jupyterpack.common import patch_all
45
+ patch_all()
46
+ `;
47
+ await this.executeCode({ code: patchCode });
48
+ }
49
+
50
+ openWebsocketFunctionFactory(options: {
51
+ instanceId: string;
52
+ kernelId: string;
53
+ wsUrl: string;
54
+ protocol?: string;
55
+ }): string | undefined {
56
+ return undefined;
57
+ }
58
+
59
+ sendWebsocketMessageFunctionFactory(options: {
60
+ instanceId: string;
61
+ kernelId: string;
62
+ wsUrl: string;
63
+ message: string;
64
+ }): string | undefined {
65
+ return undefined;
66
+ }
67
+
68
+ async openWebsocket(options: {
69
+ instanceId: string;
70
+ kernelId: string;
71
+ wsUrl: string;
72
+ protocol?: string;
73
+ }): Promise<void> {
74
+ const code = this.openWebsocketFunctionFactory(options);
75
+ if (code) {
76
+ await this.executeCode({ code });
77
+ }
78
+ }
79
+
80
+ async sendWebsocketMessage(options: {
81
+ instanceId: string;
82
+ kernelId: string;
83
+ wsUrl: string;
84
+ message: string;
85
+ }): Promise<void> {
86
+ const code = this.sendWebsocketMessageFunctionFactory(options);
87
+ if (code) {
88
+ await this.executeCode({ code });
89
+ }
90
+ }
91
+
92
+ async getResponse(options: {
93
+ method: string;
94
+ urlPath: string;
95
+ headers: IDict;
96
+ requestBody?: ArrayBuffer;
97
+ params?: string;
98
+ }): Promise<IDict> {
99
+ const { method, urlPath, requestBody, params, headers } = options;
100
+ const content = requestBody ? arrayBufferToBase64(requestBody) : undefined;
101
+ const code = this.getResponseFunctionFactory({
102
+ method,
103
+ urlPath,
104
+ headers,
105
+ params,
106
+ content
107
+ });
108
+ const raw = await this.executeCode({ code }, true);
109
+ if (!raw) {
110
+ throw new Error(`Missing response for ${urlPath}`);
111
+ }
112
+ const jsonStr = raw.replaceAll("'", '');
113
+ const obj: {
114
+ headers: string;
115
+ status_code: number;
116
+ content: string;
117
+ } = JSON.parse(jsonStr);
118
+ const responseHeaders: IDict<string> = JSON.parse(atob(obj.headers));
119
+ const contentType: string | undefined =
120
+ responseHeaders?.['Content-Type'] ?? responseHeaders?.['content-type'];
121
+ let responseContent: string | Uint8Array;
122
+
123
+ if (isBinaryContentType(contentType)) {
124
+ responseContent = base64ToArrayBuffer(obj.content);
125
+ } else {
126
+ responseContent = base64ToString(obj.content);
127
+ }
128
+
129
+ if (contentType && contentType.toLowerCase() === 'text/html') {
130
+ responseContent = (responseContent as string).replace(
131
+ '<head>',
132
+ `<head>\n<script>\n${this._wsPatch}\n</script>\n`
133
+ );
134
+ }
135
+
136
+ const decodedObj = {
137
+ status_code: obj.status_code,
138
+ headers: responseHeaders,
139
+ content: responseContent
140
+ };
141
+
142
+ return decodedObj;
143
+ }
144
+ async executeCode(
145
+ code: KernelMessage.IExecuteRequestMsg['content'],
146
+ waitForResult?: boolean
147
+ ): Promise<string | null> {
148
+ const kernel = this._sessionConnection?.kernel;
149
+ if (!kernel) {
150
+ throw new Error('Session has no kernel.');
151
+ }
152
+ return new Promise<string | null>((resolve, reject) => {
153
+ const future = kernel.requestExecute(code, false, undefined);
154
+ let executeResult = '';
155
+ future.onIOPub = (msg: KernelMessage.IIOPubMessage): void => {
156
+ const msgType = msg.header.msg_type;
157
+
158
+ switch (msgType) {
159
+ case 'execute_result': {
160
+ if (waitForResult) {
161
+ const content = (msg as KernelMessage.IExecuteResultMsg).content
162
+ .data['text/plain'] as string;
163
+ executeResult += content;
164
+ resolve(executeResult);
165
+ }
166
+ break;
167
+ }
168
+ case 'stream': {
169
+ const content = (msg as KernelMessage.IStreamMsg).content;
170
+ if (content.text.length === 0) {
171
+ break;
172
+ }
173
+ if (content.name === 'stderr') {
174
+ console.error('Kernel stream:', content.text);
175
+ } else {
176
+ console.log('Kernel stream:', content.text);
177
+ }
178
+ break;
179
+ }
180
+ case 'error': {
181
+ console.error(
182
+ 'Kernel operation failed',
183
+ code.code,
184
+ (msg.content as any).traceback
185
+ .map((it: string) => stripAnsi(it))
186
+ .join('\n')
187
+ );
188
+
189
+ reject(msg.content);
190
+ break;
191
+ }
192
+ default:
193
+ break;
194
+ }
195
+ };
196
+ if (!waitForResult) {
197
+ resolve(null);
198
+ // future.dispose() # TODO
199
+ }
200
+ });
201
+ }
202
+
203
+ dispose(): void {
204
+ if (this._isDisposed) {
205
+ return;
206
+ }
207
+ this._isDisposed = true;
208
+ this._sessionConnection.dispose();
209
+ }
210
+
211
+ protected buildBaseURL(options: {
212
+ instanceId: string;
213
+ kernelClientId: string;
214
+ framework: JupyterPackFramework;
215
+ }) {
216
+ const { instanceId, kernelClientId, framework } = options;
217
+ const fullLabextensionsUrl = PageConfig.getOption('fullLabextensionsUrl');
218
+
219
+ const baseURL = URLExt.join(
220
+ fullLabextensionsUrl,
221
+ 'jupyterpack/static',
222
+ instanceId,
223
+ framework,
224
+ kernelClientId,
225
+ '/'
226
+ );
227
+ this._baseUrl = baseURL;
228
+
229
+ return baseURL;
230
+ }
231
+
232
+ protected _baseUrl: string | undefined;
233
+
234
+ private _isDisposed: boolean = false;
235
+ private _sessionConnection: Session.ISessionConnection;
236
+ private _wsPatch: string;
237
+ }
238
+
239
+ export namespace KernelExecutor {
240
+ export interface IOptions {
241
+ sessionConnection: Session.ISessionConnection;
242
+ }
243
+ }
@@ -0,0 +1,67 @@
1
+ import { JupyterPackFramework } from '../../type';
2
+ import { TornadoServer } from '../tornado/tornadoServer';
3
+
4
+ export class StreamlitServer extends TornadoServer {
5
+ async init(options: {
6
+ entryPath?: string;
7
+ initCode?: string;
8
+ instanceId: string;
9
+ kernelClientId: string;
10
+ }) {
11
+ const { instanceId, kernelClientId, entryPath } = options;
12
+ if (!entryPath) {
13
+ throw new Error(
14
+ 'Missing streamlit entry path, please check your SPK file'
15
+ );
16
+ }
17
+ const baseURL = this.buildBaseURL({
18
+ instanceId,
19
+ kernelClientId,
20
+ framework: JupyterPackFramework.STREAMLIT
21
+ });
22
+
23
+ const patchCode = `
24
+ from jupyterpack.common import set_base_url_env, patch_tornado, patch_all
25
+ patch_all()
26
+ patch_tornado()
27
+ set_base_url_env("${baseURL}")
28
+ `;
29
+ await this.executeCode({ code: patchCode });
30
+
31
+ const bootstrapCode = `
32
+ from jupyterpack.streamlit import patch_streamlit
33
+ patch_streamlit()
34
+ `;
35
+ await this.executeCode({ code: bootstrapCode });
36
+
37
+ const stCode = `
38
+ from jupyterpack.streamlit import StreamlitServer, create_streamlit_app
39
+ __jupyterpack_st_server, __jupyterpack_tor_app = await create_streamlit_app("${entryPath}", "${baseURL}")
40
+ ${this._SERVER_VAR} = StreamlitServer(__jupyterpack_tor_app, "${baseURL}", __jupyterpack_st_server)
41
+ `;
42
+ await this.executeCode({ code: stCode });
43
+ }
44
+
45
+ async reloadPythonServer(options: {
46
+ entryPath?: string;
47
+ initCode?: string;
48
+ }): Promise<void> {
49
+ const { entryPath } = options;
50
+ if (!entryPath || !this._baseUrl) {
51
+ return;
52
+ }
53
+ const reloadCode = `
54
+ ${this._SERVER_VAR}.dispose()
55
+ __jupyterpack_st_server, __jupyterpack_tor_app = await create_streamlit_app("${entryPath}", "${this._baseUrl}")
56
+ ${this._SERVER_VAR}.reload(__jupyterpack_tor_app, __jupyterpack_st_server)
57
+ `;
58
+ await this.executeCode(
59
+ {
60
+ code: reloadCode
61
+ },
62
+ true
63
+ );
64
+ }
65
+
66
+ protected _SERVER_VAR = '__jupyterpack_streamlit_server';
67
+ }
@@ -0,0 +1,97 @@
1
+ import { stringOrNone } from '../../tools';
2
+ import { IDict, JupyterPackFramework } from '../../type';
3
+ import { KernelExecutor } from '../kernelExecutor';
4
+
5
+ export class TornadoServer extends KernelExecutor {
6
+ async init(options: {
7
+ initCode?: string;
8
+ instanceId: string;
9
+ kernelClientId: string;
10
+ }) {
11
+ await super.init(options);
12
+ const { initCode, instanceId, kernelClientId } = options;
13
+
14
+ const baseURL = this.buildBaseURL({
15
+ instanceId,
16
+ kernelClientId,
17
+ framework: JupyterPackFramework.TORNADO
18
+ });
19
+ const bootstrapCode = `
20
+ from jupyterpack.common import set_base_url_env, patch_tornado
21
+ set_base_url_env("${baseURL}")
22
+ patch_tornado()
23
+
24
+ `;
25
+ await this.executeCode({ code: bootstrapCode });
26
+ if (initCode) {
27
+ const initCodeWithUrl = initCode.replaceAll('{{base_url}}', baseURL);
28
+ await this.executeCode({ code: initCodeWithUrl });
29
+ const loaderCode = `
30
+ from jupyterpack.tornado import TornadoServer
31
+ ${this._SERVER_VAR} = TornadoServer(app, "${baseURL}")
32
+ `;
33
+
34
+ await this.executeCode({ code: loaderCode });
35
+ }
36
+ }
37
+
38
+ getResponseFunctionFactory(options: {
39
+ urlPath: string;
40
+ method: string;
41
+ headers: IDict;
42
+ params?: string;
43
+ content?: string;
44
+ }) {
45
+ const { method, urlPath, headers, params, content } = options;
46
+ const code = `await ${this._SERVER_VAR}.get_response("${method}", "${urlPath}", headers=${JSON.stringify(headers)} , content=${stringOrNone(content)}, params=${stringOrNone(params)})`;
47
+ return code;
48
+ }
49
+
50
+ openWebsocketFunctionFactory(options: {
51
+ instanceId: string;
52
+ kernelId: string;
53
+ wsUrl: string;
54
+ protocol?: string;
55
+ }): string {
56
+ const { instanceId, kernelId, wsUrl, protocol } = options;
57
+
58
+ const code = `await ${this._SERVER_VAR}.open_ws("${instanceId}", "${kernelId}", "${wsUrl}", ${stringOrNone(protocol)})`;
59
+ return code;
60
+ }
61
+
62
+ sendWebsocketMessageFunctionFactory(options: {
63
+ instanceId: string;
64
+ kernelId: string;
65
+ wsUrl: string;
66
+ message: string;
67
+ }): string {
68
+ const { instanceId, kernelId, wsUrl, message } = options;
69
+ const code = `await ${this._SERVER_VAR}.receive_ws_message("${instanceId}", "${kernelId}", "${wsUrl}", '''${message}''')`;
70
+ return code;
71
+ }
72
+
73
+ async disposePythonServer(): Promise<void> {
74
+ await this.executeCode({
75
+ code: `${this._SERVER_VAR}.dispose()`
76
+ });
77
+ }
78
+
79
+ async reloadPythonServer(options: {
80
+ entryPath?: string;
81
+ initCode?: string;
82
+ }): Promise<void> {
83
+ const { initCode } = options;
84
+ if (initCode) {
85
+ await this.executeCode({
86
+ code: initCode.replaceAll('{{base_url}}', this._baseUrl ?? '')
87
+ });
88
+ const reloadCode = `
89
+ ${this._SERVER_VAR}.dispose()
90
+ ${this._SERVER_VAR}.reload(app)
91
+ `;
92
+ await this.executeCode({ code: reloadCode }, true);
93
+ }
94
+ }
95
+
96
+ protected _SERVER_VAR = '__jupyterpack_tornado_server';
97
+ }