jupyterpack 0.3.0 → 0.5.1

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 (87) hide show
  1. package/README.md +1 -1
  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 +14 -6
  11. package/lib/index.d.ts +1 -1
  12. package/lib/pythonServer/baseServer.d.ts +82 -0
  13. package/lib/pythonServer/baseServer.js +141 -0
  14. package/lib/pythonServer/dash/dashServer.d.ts +5 -17
  15. package/lib/pythonServer/dash/dashServer.js +19 -24
  16. package/lib/pythonServer/index.d.ts +3 -3
  17. package/lib/pythonServer/index.js +5 -1
  18. package/lib/pythonServer/kernelExecutor.d.ts +2 -53
  19. package/lib/pythonServer/kernelExecutor.js +5 -70
  20. package/lib/pythonServer/shiny/shinyServer.d.ts +14 -0
  21. package/lib/pythonServer/shiny/shinyServer.js +49 -0
  22. package/lib/pythonServer/starlette/starletteServer.d.ts +13 -0
  23. package/lib/pythonServer/starlette/starletteServer.js +49 -0
  24. package/lib/pythonServer/streamlit/streamlitServer.d.ts +6 -26
  25. package/lib/pythonServer/streamlit/streamlitServer.js +33 -41
  26. package/lib/pythonServer/tornado/tornadoServer.d.ts +6 -26
  27. package/lib/pythonServer/tornado/tornadoServer.js +28 -36
  28. package/lib/pythonWidget/comm.d.ts +11 -0
  29. package/lib/pythonWidget/comm.js +52 -0
  30. package/lib/pythonWidget/pythonWidget.d.ts +5 -0
  31. package/lib/pythonWidget/pythonWidget.js +19 -0
  32. package/lib/pythonWidget/pythonWidgetModel.d.ts +16 -4
  33. package/lib/pythonWidget/pythonWidgetModel.js +77 -13
  34. package/lib/sandpackWidget/sandpackFilesModel.d.ts +6 -2
  35. package/lib/sandpackWidget/sandpackFilesModel.js +13 -2
  36. package/lib/sandpackWidget/sandpackPanel.d.ts +10 -1
  37. package/lib/sandpackWidget/sandpackPanel.js +38 -3
  38. package/lib/swConnection/mainConnectionManager.d.ts +4 -4
  39. package/lib/swConnection/mainConnectionManager.js +23 -12
  40. package/lib/token.d.ts +2 -1
  41. package/lib/token.js +1 -0
  42. package/lib/tools.d.ts +6 -0
  43. package/lib/tools.js +25 -0
  44. package/lib/type.d.ts +39 -4
  45. package/lib/type.js +2 -0
  46. package/lib/websocket/websocket.js +5 -1
  47. package/package.json +6 -6
  48. package/src/document/commands.ts +91 -0
  49. package/src/document/iframePanel.ts +4 -1
  50. package/src/document/plugin.ts +28 -7
  51. package/src/document/toolbar.ts +39 -0
  52. package/src/document/widgetFactory.ts +16 -6
  53. package/src/global.d.ts +5 -0
  54. package/src/pythonServer/baseServer.ts +245 -0
  55. package/src/pythonServer/dash/dashServer.ts +25 -35
  56. package/src/pythonServer/index.ts +9 -5
  57. package/src/pythonServer/kernelExecutor.ts +8 -147
  58. package/src/pythonServer/shiny/shinyServer.ts +62 -0
  59. package/src/pythonServer/starlette/starletteServer.ts +59 -0
  60. package/src/pythonServer/streamlit/streamlitServer.ts +40 -62
  61. package/src/pythonServer/tornado/tornadoServer.ts +33 -60
  62. package/src/pythonWidget/comm.ts +65 -0
  63. package/src/pythonWidget/pythonWidget.ts +19 -1
  64. package/src/pythonWidget/pythonWidgetModel.ts +107 -20
  65. package/src/sandpackWidget/sandpackFilesModel.ts +17 -3
  66. package/src/sandpackWidget/sandpackPanel.ts +45 -4
  67. package/src/swConnection/mainConnectionManager.ts +28 -20
  68. package/src/token.ts +5 -1
  69. package/src/tools.ts +31 -0
  70. package/src/type.ts +46 -7
  71. package/src/websocket/websocket.ts +9 -1
  72. package/style/base.css +7 -0
  73. package/style/icons/autoreload.svg +16 -0
  74. package/style/icons/box.svg +12 -0
  75. package/style/icons/externallink.svg +10 -0
  76. package/lib/pythonServer/common/generatedPythonFiles.d.ts +0 -2
  77. package/lib/pythonServer/common/generatedPythonFiles.js +0 -72
  78. package/lib/pythonServer/dash/generatedPythonFiles.d.ts +0 -2
  79. package/lib/pythonServer/dash/generatedPythonFiles.js +0 -31
  80. package/lib/pythonServer/streamlit/generatedPythonFiles.d.ts +0 -2
  81. package/lib/pythonServer/streamlit/generatedPythonFiles.js +0 -147
  82. package/lib/pythonServer/tornado/generatedPythonFiles.d.ts +0 -3
  83. package/lib/pythonServer/tornado/generatedPythonFiles.js +0 -456
  84. package/src/pythonServer/common/generatedPythonFiles.ts +0 -73
  85. package/src/pythonServer/dash/generatedPythonFiles.ts +0 -32
  86. package/src/pythonServer/streamlit/generatedPythonFiles.ts +0 -148
  87. package/src/pythonServer/tornado/generatedPythonFiles.ts +0 -457
@@ -0,0 +1,91 @@
1
+ import { refreshIcon } from '@jupyterlab/ui-components';
2
+ import { CommandRegistry } from '@lumino/commands';
3
+ import { Panel } from '@lumino/widgets';
4
+
5
+ import { autoReloadIcon, linkIcon } from '../tools';
6
+ import { IJupyterpackDocTracker } from '../type';
7
+ import { IFramePanel } from './iframePanel';
8
+ import { PageConfig, URLExt } from '@jupyterlab/coreutils';
9
+
10
+ export const CommandIDs = {
11
+ RELOAD: 'jupyterpack:reload',
12
+ TOGGLE_AUTORELOAD: 'jupyterpack:toggleAutoreload',
13
+ OPEN_SPECTA: 'jupyterpack:openInSpecta'
14
+ };
15
+
16
+ const labBaseUrl = PageConfig.getOption('baseUrl');
17
+
18
+ function getCurrentIframPanel(
19
+ tracker: IJupyterpackDocTracker
20
+ ): IFramePanel | undefined {
21
+ const current = tracker.currentWidget?.content as Panel | undefined;
22
+ if (!current) {
23
+ return;
24
+ }
25
+ const widget = current.widgets[0] as IFramePanel | undefined;
26
+ if (!widget) {
27
+ return;
28
+ }
29
+ return widget;
30
+ }
31
+ export function addCommands(
32
+ commands: CommandRegistry,
33
+ tracker: IJupyterpackDocTracker
34
+ ) {
35
+ commands.addCommand(CommandIDs.RELOAD, {
36
+ caption: 'Reload',
37
+ isEnabled: () => {
38
+ return tracker.currentWidget !== null;
39
+ },
40
+ icon: refreshIcon,
41
+ execute: async () => {
42
+ const widget = getCurrentIframPanel(tracker);
43
+ if (widget) {
44
+ await widget.reload();
45
+ }
46
+ }
47
+ });
48
+ const commandState = { toggled: false };
49
+ commands.addCommand(CommandIDs.TOGGLE_AUTORELOAD, {
50
+ isEnabled: () => {
51
+ return tracker.currentWidget !== null;
52
+ },
53
+ isToggled: () => {
54
+ const widget = getCurrentIframPanel(tracker);
55
+ return Boolean(widget?.autoreload);
56
+ },
57
+ icon: autoReloadIcon,
58
+ caption: e => {
59
+ return commandState.toggled
60
+ ? 'Auto-reload enabled'
61
+ : 'Auto-reload disabled';
62
+ },
63
+ execute: async () => {
64
+ const widget = getCurrentIframPanel(tracker);
65
+ if (widget) {
66
+ widget.autoreload = !widget?.autoreload;
67
+
68
+ commands.notifyCommandChanged(CommandIDs.TOGGLE_AUTORELOAD);
69
+ }
70
+ }
71
+ });
72
+ commands.addCommand(CommandIDs.OPEN_SPECTA, {
73
+ caption: 'Open in Specta',
74
+ isEnabled: () => {
75
+ return tracker.currentWidget !== null;
76
+ },
77
+ icon: linkIcon,
78
+ execute: async () => {
79
+ const context = tracker.currentWidget?.context;
80
+ if (!context) {
81
+ return;
82
+ }
83
+ const spectaUrl = new URL(
84
+ URLExt.join(labBaseUrl, 'specta'),
85
+ window.location.origin
86
+ );
87
+ spectaUrl.searchParams.set('path', context.path);
88
+ window.open(spectaUrl.toString(), '_blank');
89
+ }
90
+ });
91
+ }
@@ -1,6 +1,6 @@
1
1
  import { Widget } from '@lumino/widgets';
2
2
 
3
- export class IFramePanel extends Widget {
3
+ export abstract class IFramePanel extends Widget {
4
4
  constructor() {
5
5
  super();
6
6
  this.addClass('jupyterpack-iframe-panel');
@@ -20,6 +20,9 @@ export class IFramePanel extends Widget {
20
20
  }
21
21
  }
22
22
 
23
+ abstract reload(): Promise<void>;
24
+ abstract autoreload: boolean;
25
+ abstract isReady: Promise<void>;
23
26
  protected _iframe: HTMLIFrameElement;
24
27
  protected _spinner: HTMLDivElement;
25
28
  }
@@ -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> {
@@ -51,7 +54,9 @@ export class JupyterPackWidgetFactory extends ABCWidgetFactory<JupyterPackDocWid
51
54
  }
52
55
  case JupyterPackFramework.DASH:
53
56
  case JupyterPackFramework.STREAMLIT:
54
- case JupyterPackFramework.TORNADO: {
57
+ case JupyterPackFramework.TORNADO:
58
+ case JupyterPackFramework.STARLETTE:
59
+ case JupyterPackFramework.SHINY: {
55
60
  const model = new PythonWidgetModel({
56
61
  jpackModel,
57
62
  context,
@@ -72,9 +77,14 @@ export class JupyterPackWidgetFactory extends ABCWidgetFactory<JupyterPackDocWid
72
77
  }
73
78
  }
74
79
  });
80
+ const toolbar = new ToolbarWidget({
81
+ tracker: this.options.tracker,
82
+ commands: this.options.commands
83
+ });
75
84
  return new JupyterPackDocWidget({
76
85
  context,
77
- content
86
+ content,
87
+ toolbar
78
88
  });
79
89
  }
80
90
 
package/src/global.d.ts CHANGED
@@ -2,3 +2,8 @@ declare module '*?raw' {
2
2
  const content: string;
3
3
  export default content;
4
4
  }
5
+
6
+ declare module '*.svg' {
7
+ const value: string;
8
+ export default value;
9
+ }
@@ -0,0 +1,245 @@
1
+ import { KernelExecutor } from './kernelExecutor';
2
+ import websocketPatch from '../websocket/websocket.js?raw';
3
+ import {
4
+ IDict,
5
+ IBasePythonServer,
6
+ IKernelExecutor,
7
+ JupyterPackFramework
8
+ } from '../type';
9
+ import { PageConfig, URLExt } from '@jupyterlab/coreutils';
10
+ import {
11
+ arrayBufferToBase64,
12
+ base64ToArrayBuffer,
13
+ base64ToString,
14
+ isBinaryContentType,
15
+ stringOrNone
16
+ } from '../tools';
17
+
18
+ export abstract class BasePythonServer implements IBasePythonServer {
19
+ constructor(options: KernelExecutor.IOptions) {
20
+ this._kernelExecutor = new KernelExecutor(options);
21
+ this._wsPatch = websocketPatch.replaceAll('"use strict";', '');
22
+ }
23
+
24
+ abstract reloadPythonServer(options: {
25
+ entryPath?: string;
26
+ initCode?: string;
27
+ }): Promise<void>;
28
+
29
+ get isDisposed(): boolean {
30
+ return this._isDisposed;
31
+ }
32
+
33
+ get kernelExecutor() {
34
+ return this._kernelExecutor;
35
+ }
36
+
37
+ dispose(): void {
38
+ if (this._isDisposed) {
39
+ return;
40
+ }
41
+ this._isDisposed = true;
42
+ this.disposePythonServer()
43
+ .then(() => {
44
+ this._kernelExecutor.dispose();
45
+ })
46
+ .catch(console.error);
47
+ }
48
+ async init(options: {
49
+ entryPath?: string;
50
+ initCode?: string;
51
+ instanceId: string;
52
+ kernelClientId: string;
53
+ }): Promise<void> {
54
+ const patchCode = `
55
+ from jupyterpack.common import patch_all
56
+ patch_all()
57
+ `;
58
+ await this._kernelExecutor.executeCode({ code: patchCode });
59
+ }
60
+
61
+ async disposePythonServer(): Promise<void> {
62
+ await this.kernelExecutor.executeCode({
63
+ code: `${this._server_var}.dispose()`
64
+ });
65
+ for (const element of this._openedWebsockets) {
66
+ await this.closeWebsocket(element);
67
+ }
68
+ }
69
+
70
+ getResponseFunctionFactory(options: {
71
+ urlPath: string;
72
+ method: string;
73
+ headers: IDict;
74
+ params?: string;
75
+ content?: string;
76
+ }) {
77
+ const { method, urlPath, headers, params, content } = options;
78
+ const code = `await ${this._server_var}.get_response("${method}", "${urlPath}", headers=${JSON.stringify(headers)} , content=${stringOrNone(content)}, params=${stringOrNone(params)})`;
79
+ return code;
80
+ }
81
+
82
+ openWebsocketFunctionFactory(options: {
83
+ instanceId: string;
84
+ kernelId: string;
85
+ wsUrl: string;
86
+ protocol?: string;
87
+ }): string {
88
+ const { instanceId, kernelId, wsUrl, protocol } = options;
89
+ const code = `await ${this._server_var}.open_ws("${instanceId}", "${kernelId}", "${wsUrl}", ${stringOrNone(protocol)})`;
90
+ return code;
91
+ }
92
+
93
+ closeWebsocketFunctionFactory(options: {
94
+ instanceId: string;
95
+ kernelId: string;
96
+ wsUrl: string;
97
+ }): string {
98
+ const { instanceId, kernelId, wsUrl } = options;
99
+ const code = `await ${this._server_var}.close_ws("${instanceId}", "${kernelId}", "${wsUrl}")`;
100
+ return code;
101
+ }
102
+
103
+ sendWebsocketMessageFunctionFactory(options: {
104
+ instanceId: string;
105
+ kernelId: string;
106
+ wsUrl: string;
107
+ message: string;
108
+ }): string {
109
+ const { instanceId, kernelId, wsUrl, message } = options;
110
+ const code = `await ${this._server_var}.receive_ws_message("${instanceId}", "${kernelId}", "${wsUrl}", '''${message}''')`;
111
+ return code;
112
+ }
113
+
114
+ async openWebsocket(options: {
115
+ instanceId: string;
116
+ kernelId: string;
117
+ wsUrl: string;
118
+ protocol?: string;
119
+ }): Promise<void> {
120
+ const code = this.openWebsocketFunctionFactory(options);
121
+ if (code) {
122
+ try {
123
+ await this._kernelExecutor.executeCode({ code });
124
+ this._openedWebsockets.push(options);
125
+ } catch (e) {
126
+ console.error('Failed to open websocket', e);
127
+ }
128
+ } else {
129
+ throw new Error('Missing websocket open code');
130
+ }
131
+ }
132
+
133
+ async closeWebsocket(options: {
134
+ instanceId: string;
135
+ kernelId: string;
136
+ wsUrl: string;
137
+ }): Promise<void> {
138
+ const code = this.closeWebsocketFunctionFactory(options);
139
+ if (code) {
140
+ await this._kernelExecutor.executeCode({ code });
141
+ } else {
142
+ throw new Error('Missing websocket close code');
143
+ }
144
+ }
145
+
146
+ async sendWebsocketMessage(options: {
147
+ instanceId: string;
148
+ kernelId: string;
149
+ wsUrl: string;
150
+ message: string;
151
+ }): Promise<void> {
152
+ const code = this.sendWebsocketMessageFunctionFactory(options);
153
+ if (code) {
154
+ await this._kernelExecutor.executeCode({ code });
155
+ } else {
156
+ throw new Error('Missing websocket send code');
157
+ }
158
+ }
159
+
160
+ async getResponse(options: {
161
+ method: string;
162
+ urlPath: string;
163
+ headers: IDict;
164
+ requestBody?: ArrayBuffer;
165
+ params?: string;
166
+ }): Promise<IDict> {
167
+ const { method, urlPath, requestBody, params, headers } = options;
168
+ const content = requestBody ? arrayBufferToBase64(requestBody) : undefined;
169
+ const code = this.getResponseFunctionFactory({
170
+ method,
171
+ urlPath,
172
+ headers,
173
+ params,
174
+ content
175
+ });
176
+ const raw = await this._kernelExecutor.executeCode({ code }, true);
177
+ if (!raw) {
178
+ throw new Error(`Missing response for ${urlPath}`);
179
+ }
180
+ const jsonStr = raw.replaceAll("'", '');
181
+ const obj: {
182
+ headers: string;
183
+ status_code: number;
184
+ content: string;
185
+ } = JSON.parse(jsonStr);
186
+ const responseHeaders: IDict<string> = JSON.parse(atob(obj.headers));
187
+ const contentType: string | undefined =
188
+ responseHeaders?.['Content-Type'] ?? responseHeaders?.['content-type'];
189
+ let responseContent: string | Uint8Array;
190
+
191
+ if (isBinaryContentType(contentType)) {
192
+ responseContent = base64ToArrayBuffer(obj.content);
193
+ } else {
194
+ responseContent = base64ToString(obj.content);
195
+ }
196
+
197
+ if (contentType && contentType.toLowerCase().includes('text/html')) {
198
+ responseContent = (responseContent as string).replace(
199
+ '<head>',
200
+ `<head>\n<script>\n${this._wsPatch}\n</script>\n`
201
+ );
202
+ }
203
+
204
+ const decodedObj = {
205
+ status_code: obj.status_code,
206
+ headers: responseHeaders,
207
+ content: responseContent
208
+ };
209
+
210
+ return decodedObj;
211
+ }
212
+
213
+ protected buildBaseURL(options: {
214
+ instanceId: string;
215
+ kernelClientId: string;
216
+ framework: JupyterPackFramework;
217
+ }) {
218
+ const { instanceId, kernelClientId, framework } = options;
219
+ const fullLabextensionsUrl = PageConfig.getOption('fullLabextensionsUrl');
220
+
221
+ const baseURL = URLExt.join(
222
+ fullLabextensionsUrl,
223
+ 'jupyterpack/static',
224
+ instanceId,
225
+ framework,
226
+ kernelClientId,
227
+ '/'
228
+ );
229
+ this._baseUrl = baseURL;
230
+
231
+ return baseURL;
232
+ }
233
+
234
+ protected _baseUrl: string | undefined;
235
+ protected readonly _openedWebsockets: {
236
+ instanceId: string;
237
+ kernelId: string;
238
+ wsUrl: string;
239
+ }[] = [];
240
+ protected readonly _server_var = '__jupyterpack_python_server';
241
+
242
+ private _kernelExecutor: IKernelExecutor;
243
+ private _isDisposed: boolean = false;
244
+ private _wsPatch: string;
245
+ }
@@ -1,10 +1,7 @@
1
- import { stringOrNone } from '../../tools';
2
- import { IDict, JupyterPackFramework } from '../../type';
3
- import { patch } from '../common/generatedPythonFiles';
4
- import { KernelExecutor } from '../kernelExecutor';
5
- import { bootstrap, dashLoader } from './generatedPythonFiles';
1
+ import { JupyterPackFramework } from '../../type';
2
+ import { BasePythonServer } from '../baseServer';
6
3
 
7
- export class DashServer extends KernelExecutor {
4
+ export class DashServer extends BasePythonServer {
8
5
  async init(options: {
9
6
  initCode?: string;
10
7
  instanceId: string;
@@ -18,40 +15,33 @@ export class DashServer extends KernelExecutor {
18
15
  kernelClientId,
19
16
  framework: JupyterPackFramework.DASH
20
17
  });
21
- await this.executeCode({ code: patch });
22
- await this.executeCode({
23
- code: bootstrap.replaceAll('{{base_url}}', baseURL)
18
+ await this.kernelExecutor.executeCode({
19
+ code: `
20
+ import os
21
+ os.environ["DASH_URL_BASE_PATHNAME"] = "${baseURL}"
22
+ `
24
23
  });
25
24
  if (initCode) {
26
- await this.executeCode({ code: initCode });
25
+ await this.kernelExecutor.executeCode({ code: initCode });
27
26
  }
28
- await this.executeCode({ code: dashLoader });
27
+ const loaderCode = `
28
+ from jupyterpack.dash import DashServer
29
+ ${this._server_var} = DashServer(app, "${baseURL}")
30
+ `;
31
+ await this.kernelExecutor.executeCode({ code: loaderCode });
29
32
  }
30
33
 
31
- getResponseFunctionFactory(options: {
32
- urlPath: string;
33
- method: string;
34
- headers: IDict;
35
- params?: string;
36
- content?: string;
37
- }) {
38
- const { method, urlPath, headers, params, content } = options;
39
- const code = `${this.DASH_GET_RESPONSE_FUNCTION}("${method}", "${urlPath}", headers=${JSON.stringify(headers)} , content=${stringOrNone(content)}, params=${stringOrNone(params)})`;
40
- return code;
41
- }
42
-
43
- async disposePythonServer(): Promise<void> {
44
- //no-op
45
- }
46
-
47
- async openWebsocket(options: {
48
- instanceId: string;
49
- kernelId: string;
50
- wsUrl: string;
51
- protocol?: string;
34
+ async reloadPythonServer(options: {
35
+ entryPath?: string;
36
+ initCode?: string;
52
37
  }): Promise<void> {
53
- //no-op
38
+ const { initCode } = options;
39
+ if (initCode) {
40
+ await this.kernelExecutor.executeCode({ code: initCode });
41
+ }
42
+ await this.kernelExecutor.executeCode(
43
+ { code: `${this._server_var}.reload(app)` },
44
+ true
45
+ );
54
46
  }
55
-
56
- private DASH_GET_RESPONSE_FUNCTION = '__jupyterpack_dash_get_response';
57
47
  }
@@ -1,18 +1,22 @@
1
- import { IKernelExecutor, JupyterPackFramework } from '../type';
1
+ import { IBasePythonServer, JupyterPackFramework } from '../type';
2
2
  import { DashServer } from './dash/dashServer';
3
3
  import { KernelExecutor } from './kernelExecutor';
4
+ import { ShinyServer } from './shiny/shinyServer';
5
+ import { StarletteServer } from './starlette/starletteServer';
4
6
  import { StreamlitServer } from './streamlit/streamlitServer';
5
7
  import { TornadoServer } from './tornado/tornadoServer';
6
8
 
7
- type KernelExecutorConstructor = new (
9
+ type BasePythonServerConstructor = new (
8
10
  options: KernelExecutor.IOptions
9
- ) => IKernelExecutor;
11
+ ) => IBasePythonServer;
10
12
 
11
13
  export const PYTHON_SERVER = new Map<
12
14
  JupyterPackFramework,
13
- KernelExecutorConstructor
15
+ BasePythonServerConstructor
14
16
  >([
15
17
  [JupyterPackFramework.DASH, DashServer],
16
18
  [JupyterPackFramework.STREAMLIT, StreamlitServer],
17
- [JupyterPackFramework.TORNADO, TornadoServer]
19
+ [JupyterPackFramework.TORNADO, TornadoServer],
20
+ [JupyterPackFramework.SHINY, ShinyServer],
21
+ [JupyterPackFramework.STARLETTE, StarletteServer]
18
22
  ]);