jupyterpack 0.3.0 → 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 (68) hide show
  1. package/lib/document/commands.d.ts +8 -0
  2. package/lib/document/commands.js +76 -0
  3. package/lib/document/iframePanel.d.ts +4 -1
  4. package/lib/document/plugin.d.ts +2 -1
  5. package/lib/document/plugin.js +22 -4
  6. package/lib/document/toolbar.d.ts +9 -0
  7. package/lib/document/toolbar.js +20 -0
  8. package/lib/document/widgetFactory.d.ts +2 -1
  9. package/lib/document/widgetFactory.js +11 -5
  10. package/lib/index.d.ts +1 -1
  11. package/lib/pythonServer/dash/dashServer.d.ts +4 -6
  12. package/lib/pythonServer/dash/dashServer.js +18 -10
  13. package/lib/pythonServer/kernelExecutor.d.ts +5 -0
  14. package/lib/pythonServer/kernelExecutor.js +13 -6
  15. package/lib/pythonServer/streamlit/streamlitServer.d.ts +7 -26
  16. package/lib/pythonServer/streamlit/streamlitServer.js +32 -36
  17. package/lib/pythonServer/tornado/tornadoServer.d.ts +5 -3
  18. package/lib/pythonServer/tornado/tornadoServer.js +31 -14
  19. package/lib/pythonWidget/comm.d.ts +11 -0
  20. package/lib/pythonWidget/comm.js +52 -0
  21. package/lib/pythonWidget/pythonWidget.d.ts +5 -0
  22. package/lib/pythonWidget/pythonWidget.js +19 -0
  23. package/lib/pythonWidget/pythonWidgetModel.d.ts +16 -4
  24. package/lib/pythonWidget/pythonWidgetModel.js +77 -13
  25. package/lib/sandpackWidget/sandpackFilesModel.d.ts +6 -2
  26. package/lib/sandpackWidget/sandpackFilesModel.js +13 -2
  27. package/lib/sandpackWidget/sandpackPanel.d.ts +10 -1
  28. package/lib/sandpackWidget/sandpackPanel.js +38 -3
  29. package/lib/token.d.ts +2 -1
  30. package/lib/token.js +1 -0
  31. package/lib/tools.d.ts +5 -0
  32. package/lib/tools.js +17 -0
  33. package/lib/type.d.ts +27 -1
  34. package/package.json +6 -6
  35. package/src/document/commands.ts +91 -0
  36. package/src/document/iframePanel.ts +4 -1
  37. package/src/document/plugin.ts +28 -7
  38. package/src/document/toolbar.ts +39 -0
  39. package/src/document/widgetFactory.ts +13 -5
  40. package/src/global.d.ts +5 -0
  41. package/src/pythonServer/dash/dashServer.ts +23 -14
  42. package/src/pythonServer/kernelExecutor.ts +21 -7
  43. package/src/pythonServer/streamlit/streamlitServer.ts +41 -61
  44. package/src/pythonServer/tornado/tornadoServer.ts +35 -18
  45. package/src/pythonWidget/comm.ts +65 -0
  46. package/src/pythonWidget/pythonWidget.ts +19 -1
  47. package/src/pythonWidget/pythonWidgetModel.ts +105 -18
  48. package/src/sandpackWidget/sandpackFilesModel.ts +17 -3
  49. package/src/sandpackWidget/sandpackPanel.ts +45 -4
  50. package/src/token.ts +5 -1
  51. package/src/tools.ts +22 -0
  52. package/src/type.ts +29 -1
  53. package/style/base.css +7 -0
  54. package/style/icons/autoreload.svg +16 -0
  55. package/style/icons/box.svg +12 -0
  56. package/style/icons/externallink.svg +10 -0
  57. package/lib/pythonServer/common/generatedPythonFiles.d.ts +0 -2
  58. package/lib/pythonServer/common/generatedPythonFiles.js +0 -72
  59. package/lib/pythonServer/dash/generatedPythonFiles.d.ts +0 -2
  60. package/lib/pythonServer/dash/generatedPythonFiles.js +0 -31
  61. package/lib/pythonServer/streamlit/generatedPythonFiles.d.ts +0 -2
  62. package/lib/pythonServer/streamlit/generatedPythonFiles.js +0 -147
  63. package/lib/pythonServer/tornado/generatedPythonFiles.d.ts +0 -3
  64. package/lib/pythonServer/tornado/generatedPythonFiles.js +0 -456
  65. package/src/pythonServer/common/generatedPythonFiles.ts +0 -73
  66. package/src/pythonServer/dash/generatedPythonFiles.ts +0 -32
  67. package/src/pythonServer/streamlit/generatedPythonFiles.ts +0 -148
  68. 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> {
@@ -72,9 +75,14 @@ export class JupyterPackWidgetFactory extends ABCWidgetFactory<JupyterPackDocWid
72
75
  }
73
76
  }
74
77
  });
78
+ const toolbar = new ToolbarWidget({
79
+ tracker: this.options.tracker,
80
+ commands: this.options.commands
81
+ });
75
82
  return new JupyterPackDocWidget({
76
83
  context,
77
- content
84
+ content,
85
+ toolbar
78
86
  });
79
87
  }
80
88
 
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
+ }
@@ -1,8 +1,6 @@
1
1
  import { stringOrNone } from '../../tools';
2
2
  import { IDict, JupyterPackFramework } from '../../type';
3
- import { patch } from '../common/generatedPythonFiles';
4
3
  import { KernelExecutor } from '../kernelExecutor';
5
- import { bootstrap, dashLoader } from './generatedPythonFiles';
6
4
 
7
5
  export class DashServer extends KernelExecutor {
8
6
  async init(options: {
@@ -18,14 +16,20 @@ export class DashServer extends KernelExecutor {
18
16
  kernelClientId,
19
17
  framework: JupyterPackFramework.DASH
20
18
  });
21
- await this.executeCode({ code: patch });
22
19
  await this.executeCode({
23
- code: bootstrap.replaceAll('{{base_url}}', baseURL)
20
+ code: `
21
+ import os
22
+ os.environ["DASH_URL_BASE_PATHNAME"] = "${baseURL}"
23
+ `
24
24
  });
25
25
  if (initCode) {
26
26
  await this.executeCode({ code: initCode });
27
27
  }
28
- await this.executeCode({ code: dashLoader });
28
+ const loaderCode = `
29
+ from jupyterpack.dash import DashServer
30
+ ${this._DASH_SERVER_VAR} = DashServer(app, "${baseURL}")
31
+ `;
32
+ await this.executeCode({ code: loaderCode });
29
33
  }
30
34
 
31
35
  getResponseFunctionFactory(options: {
@@ -36,22 +40,27 @@ export class DashServer extends KernelExecutor {
36
40
  content?: string;
37
41
  }) {
38
42
  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)})`;
43
+ const code = `${this._DASH_SERVER_VAR}.get_response("${method}", "${urlPath}", headers=${JSON.stringify(headers)} , content=${stringOrNone(content)}, params=${stringOrNone(params)})`;
40
44
  return code;
41
45
  }
42
46
 
43
47
  async disposePythonServer(): Promise<void> {
44
- //no-op
48
+ await this.executeCode({ code: `${this._DASH_SERVER_VAR}.dispose()` });
45
49
  }
46
50
 
47
- async openWebsocket(options: {
48
- instanceId: string;
49
- kernelId: string;
50
- wsUrl: string;
51
- protocol?: string;
51
+ async reloadPythonServer(options: {
52
+ entryPath?: string;
53
+ initCode?: string;
52
54
  }): Promise<void> {
53
- //no-op
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
+ );
54
63
  }
55
64
 
56
- private DASH_GET_RESPONSE_FUNCTION = '__jupyterpack_dash_get_response';
65
+ private _DASH_SERVER_VAR = '__jupyterpack_dash_server';
57
66
  }
@@ -9,7 +9,6 @@ import {
9
9
  } from '../tools';
10
10
  import { IDict, IKernelExecutor, JupyterPackFramework } from '../type';
11
11
  import websocketPatch from '../websocket/websocket.js?raw';
12
- import { patch } from './common/generatedPythonFiles';
13
12
 
14
13
  export abstract class KernelExecutor implements IKernelExecutor {
15
14
  constructor(options: KernelExecutor.IOptions) {
@@ -22,6 +21,10 @@ export abstract class KernelExecutor implements IKernelExecutor {
22
21
  }
23
22
 
24
23
  abstract disposePythonServer(): Promise<void>;
24
+ abstract reloadPythonServer(options: {
25
+ entryPath?: string;
26
+ initCode?: string;
27
+ }): Promise<void>;
25
28
 
26
29
  abstract getResponseFunctionFactory(options: {
27
30
  urlPath: string;
@@ -37,7 +40,11 @@ export abstract class KernelExecutor implements IKernelExecutor {
37
40
  instanceId: string;
38
41
  kernelClientId: string;
39
42
  }): Promise<void> {
40
- await this.executeCode({ code: patch });
43
+ const patchCode = `
44
+ from jupyterpack.common import patch_all
45
+ patch_all()
46
+ `;
47
+ await this.executeCode({ code: patchCode });
41
48
  }
42
49
 
43
50
  openWebsocketFunctionFactory(options: {
@@ -160,10 +167,13 @@ export abstract class KernelExecutor implements IKernelExecutor {
160
167
  }
161
168
  case 'stream': {
162
169
  const content = (msg as KernelMessage.IStreamMsg).content;
170
+ if (content.text.length === 0) {
171
+ break;
172
+ }
163
173
  if (content.name === 'stderr') {
164
- console.error('Kernel stream', content.text);
174
+ console.error('Kernel stream:', content.text);
165
175
  } else {
166
- console.log('Kernel stream', content.text);
176
+ console.log('Kernel stream:', content.text);
167
177
  }
168
178
  break;
169
179
  }
@@ -204,19 +214,23 @@ export abstract class KernelExecutor implements IKernelExecutor {
204
214
  framework: JupyterPackFramework;
205
215
  }) {
206
216
  const { instanceId, kernelClientId, framework } = options;
207
- const labBaseUrl = PageConfig.getOption('baseUrl');
217
+ const fullLabextensionsUrl = PageConfig.getOption('fullLabextensionsUrl');
218
+
208
219
  const baseURL = URLExt.join(
209
- labBaseUrl,
210
- 'extensions/jupyterpack/static',
220
+ fullLabextensionsUrl,
221
+ 'jupyterpack/static',
211
222
  instanceId,
212
223
  framework,
213
224
  kernelClientId,
214
225
  '/'
215
226
  );
227
+ this._baseUrl = baseURL;
216
228
 
217
229
  return baseURL;
218
230
  }
219
231
 
232
+ protected _baseUrl: string | undefined;
233
+
220
234
  private _isDisposed: boolean = false;
221
235
  private _sessionConnection: Session.ISessionConnection;
222
236
  private _wsPatch: string;
@@ -1,21 +1,13 @@
1
- import { stringOrNone } from '../../tools';
2
- import { IDict, JupyterPackFramework } from '../../type';
3
- import { patch, tools } from '../common/generatedPythonFiles';
4
- import { KernelExecutor } from '../kernelExecutor';
5
- import {
6
- bootstrap as tornadoBootstrap,
7
- tornadoBridge
8
- } from '../tornado/generatedPythonFiles';
9
- import { bootstrap, streamlitLoader } from './generatedPythonFiles';
1
+ import { JupyterPackFramework } from '../../type';
2
+ import { TornadoServer } from '../tornado/tornadoServer';
10
3
 
11
- export class StreamlitServer extends KernelExecutor {
4
+ export class StreamlitServer extends TornadoServer {
12
5
  async init(options: {
13
6
  entryPath?: string;
14
7
  initCode?: string;
15
8
  instanceId: string;
16
9
  kernelClientId: string;
17
10
  }) {
18
- await super.init(options);
19
11
  const { instanceId, kernelClientId, entryPath } = options;
20
12
  if (!entryPath) {
21
13
  throw new Error(
@@ -27,61 +19,49 @@ export class StreamlitServer extends KernelExecutor {
27
19
  kernelClientId,
28
20
  framework: JupyterPackFramework.STREAMLIT
29
21
  });
30
- await this.executeCode({ code: patch });
31
- await this.executeCode({ code: tools.replaceAll('{{base_url}}', baseURL) });
32
- await this.executeCode({ code: tornadoBootstrap });
33
- await this.executeCode({ code: tornadoBridge });
34
- await this.executeCode({ code: bootstrap });
35
22
 
36
- const stCode = streamlitLoader
37
- .replaceAll('{{base_url}}', baseURL)
38
- .replaceAll('{{script_path}}', entryPath);
39
- await this.executeCode({ code: stCode });
40
- }
41
-
42
- getResponseFunctionFactory(options: {
43
- urlPath: string;
44
- method: string;
45
- headers: IDict;
46
- params?: string;
47
- content?: string;
48
- }) {
49
- const { method, urlPath, headers, params, content } = options;
50
- const code = `await ${this._GET_RESPONSE_FUNCTION}("${method}", "${urlPath}", headers=${JSON.stringify(headers)} , content=${stringOrNone(content)}, params=${stringOrNone(params)})`;
51
- return code;
52
- }
53
-
54
- openWebsocketFunctionFactory(options: {
55
- instanceId: string;
56
- kernelId: string;
57
- wsUrl: string;
58
- protocol?: string;
59
- }): string {
60
- const { instanceId, kernelId, wsUrl, protocol } = options;
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 });
61
30
 
62
- const code = `await ${this._OPEN_WEBSOCKET_FUNCTION}("${instanceId}", "${kernelId}", "${wsUrl}", ${stringOrNone(protocol)})`;
63
- return code;
64
- }
31
+ const bootstrapCode = `
32
+ from jupyterpack.streamlit import patch_streamlit
33
+ patch_streamlit()
34
+ `;
35
+ await this.executeCode({ code: bootstrapCode });
65
36
 
66
- sendWebsocketMessageFunctionFactory(options: {
67
- instanceId: string;
68
- kernelId: string;
69
- wsUrl: string;
70
- message: string;
71
- }): string {
72
- const { instanceId, kernelId, wsUrl, message } = options;
73
- const code = `await ${this._SEND_WEBSOCKET_FUNCTION}("${instanceId}", "${kernelId}", "${wsUrl}", '''${message}''')`;
74
- return code;
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 });
75
43
  }
76
44
 
77
- async disposePythonServer(): Promise<void> {
78
- await this.executeCode({
79
- code: '__jupyterpack_streamlit_dispose()'
80
- });
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
+ );
81
64
  }
82
65
 
83
- private _GET_RESPONSE_FUNCTION = '__jupyterpack_streamlit_get_response';
84
- private _OPEN_WEBSOCKET_FUNCTION = '__jupyterpack_streamlit_open_ws';
85
- private _SEND_WEBSOCKET_FUNCTION =
86
- '__jupyterpack_streamlit_receive_ws_message';
66
+ protected _SERVER_VAR = '__jupyterpack_streamlit_server';
87
67
  }
@@ -1,12 +1,7 @@
1
1
  import { stringOrNone } from '../../tools';
2
2
  import { IDict, JupyterPackFramework } from '../../type';
3
- import { tools } from '../common/generatedPythonFiles';
4
3
  import { KernelExecutor } from '../kernelExecutor';
5
- import {
6
- bootstrap,
7
- tornadoBridge,
8
- tornadoLoader
9
- } from './generatedPythonFiles';
4
+
10
5
  export class TornadoServer extends KernelExecutor {
11
6
  async init(options: {
12
7
  initCode?: string;
@@ -21,14 +16,22 @@ export class TornadoServer extends KernelExecutor {
21
16
  kernelClientId,
22
17
  framework: JupyterPackFramework.TORNADO
23
18
  });
24
- await this.executeCode({ code: tools.replaceAll('{{base_url}}', baseURL) });
25
- await this.executeCode({ code: bootstrap });
26
- await this.executeCode({ code: tornadoBridge });
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 });
27
26
  if (initCode) {
28
27
  const initCodeWithUrl = initCode.replaceAll('{{base_url}}', baseURL);
29
28
  await this.executeCode({ code: initCodeWithUrl });
30
- const torCode = tornadoLoader.replaceAll('{{base_url}}', baseURL);
31
- await this.executeCode({ code: torCode });
29
+ const loaderCode = `
30
+ from jupyterpack.tornado import TornadoServer
31
+ ${this._SERVER_VAR} = TornadoServer(app, "${baseURL}")
32
+ `;
33
+
34
+ await this.executeCode({ code: loaderCode });
32
35
  }
33
36
  }
34
37
 
@@ -40,7 +43,7 @@ export class TornadoServer extends KernelExecutor {
40
43
  content?: string;
41
44
  }) {
42
45
  const { method, urlPath, headers, params, content } = options;
43
- const code = `await ${this._GET_RESPONSE_FUNCTION}("${method}", "${urlPath}", headers=${JSON.stringify(headers)} , content=${stringOrNone(content)}, params=${stringOrNone(params)})`;
46
+ const code = `await ${this._SERVER_VAR}.get_response("${method}", "${urlPath}", headers=${JSON.stringify(headers)} , content=${stringOrNone(content)}, params=${stringOrNone(params)})`;
44
47
  return code;
45
48
  }
46
49
 
@@ -52,7 +55,7 @@ export class TornadoServer extends KernelExecutor {
52
55
  }): string {
53
56
  const { instanceId, kernelId, wsUrl, protocol } = options;
54
57
 
55
- const code = `await ${this._OPEN_WEBSOCKET_FUNCTION}("${instanceId}", "${kernelId}", "${wsUrl}", ${stringOrNone(protocol)})`;
58
+ const code = `await ${this._SERVER_VAR}.open_ws("${instanceId}", "${kernelId}", "${wsUrl}", ${stringOrNone(protocol)})`;
56
59
  return code;
57
60
  }
58
61
 
@@ -63,18 +66,32 @@ export class TornadoServer extends KernelExecutor {
63
66
  message: string;
64
67
  }): string {
65
68
  const { instanceId, kernelId, wsUrl, message } = options;
66
- const code = `await ${this._SEND_WEBSOCKET_FUNCTION}("${instanceId}", "${kernelId}", "${wsUrl}", '''${message}''')`;
69
+ const code = `await ${this._SERVER_VAR}.receive_ws_message("${instanceId}", "${kernelId}", "${wsUrl}", '''${message}''')`;
67
70
  return code;
68
71
  }
69
72
 
70
73
  async disposePythonServer(): Promise<void> {
71
74
  await this.executeCode({
72
- code: '__jupyterpack_tornado_dispose()'
75
+ code: `${this._SERVER_VAR}.dispose()`
73
76
  });
74
77
  }
75
78
 
76
- private _GET_RESPONSE_FUNCTION = '__jupyterpack_tornado_get_response';
77
- private _OPEN_WEBSOCKET_FUNCTION = '__jupyterpack_tornado_open_ws';
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
+ }
78
95
 
79
- private _SEND_WEBSOCKET_FUNCTION = '__jupyterpack_tornado_receive_ws_message';
96
+ protected _SERVER_VAR = '__jupyterpack_tornado_server';
80
97
  }