@jupyterlite/pyodide-kernel 0.6.0-alpha.5 → 0.6.0-beta.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/lib/kernel.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { ILogPayload } from '@jupyterlab/logconsole';
1
2
  import { Contents, KernelMessage } from '@jupyterlab/services';
2
3
  import { BaseKernel, IKernel } from '@jupyterlite/kernel';
3
4
  import { IPyodideWorkerKernel } from './tokens';
@@ -37,6 +38,7 @@ export declare class PyodideKernel extends BaseKernel implements IKernel {
37
38
  * A promise that is fulfilled when the kernel is ready.
38
39
  */
39
40
  get ready(): Promise<void>;
41
+ private _processLogMessage;
40
42
  /**
41
43
  * Process a message coming from the pyodide web worker.
42
44
  *
@@ -108,10 +110,12 @@ export declare class PyodideKernel extends BaseKernel implements IKernel {
108
110
  */
109
111
  inputReply(content: KernelMessage.IInputReplyMsg['content']): Promise<void>;
110
112
  private _contentsManager;
113
+ private _logger;
111
114
  private _contentsProcessor;
112
115
  private _worker;
113
116
  private _remoteKernel;
114
117
  private _ready;
118
+ private _inputDelegate;
115
119
  }
116
120
  /**
117
121
  * A namespace for PyodideKernel statics.
@@ -159,5 +163,12 @@ export declare namespace PyodideKernel {
159
163
  * identify the browsing context from which the request originated.
160
164
  */
161
165
  browsingContextId?: string;
166
+ /**
167
+ * The logger function to use for logging messages from the kernel.
168
+ */
169
+ logger?: (options: {
170
+ payload: ILogPayload;
171
+ kernelId: string;
172
+ }) => void;
162
173
  }
163
174
  }
package/lib/kernel.js CHANGED
@@ -17,9 +17,11 @@ export class PyodideKernel extends BaseKernel {
17
17
  constructor(options) {
18
18
  super(options);
19
19
  this._ready = new PromiseDelegate();
20
+ this._inputDelegate = new PromiseDelegate();
20
21
  this._worker = this.initWorker(options);
21
22
  this._remoteKernel = this.initRemote(options);
22
23
  this._contentsManager = options.contentsManager;
24
+ this._logger = options.logger || (() => { });
23
25
  }
24
26
  /**
25
27
  * Load the worker.
@@ -52,6 +54,7 @@ export class PyodideKernel extends BaseKernel {
52
54
  let remote;
53
55
  if (crossOriginIsolated) {
54
56
  remote = coincident(this._worker);
57
+ remote.processLogMessage = this._processLogMessage.bind(this);
55
58
  remote.processWorkerMessage = this._processWorkerMessage.bind(this);
56
59
  // The coincident worker uses its own filesystem API:
57
60
  remote.processDriveRequest = async (data) => {
@@ -65,20 +68,41 @@ export class PyodideKernel extends BaseKernel {
65
68
  }
66
69
  return await this._contentsProcessor.processDriveRequest(data);
67
70
  };
71
+ remote.processStdinRequest =
72
+ async (content) => {
73
+ const msg = {
74
+ type: 'input_request',
75
+ content,
76
+ };
77
+ this._processWorkerMessage(msg);
78
+ this._inputDelegate = new PromiseDelegate();
79
+ return await this._inputDelegate.promise;
80
+ };
68
81
  }
69
82
  else {
70
83
  remote = wrap(this._worker);
71
- // we use the normal postMessage mechanism
84
+ // we use the normal postMessage mechanism in the case of comlink
72
85
  this._worker.addEventListener('message', (ev) => {
73
- var _a;
86
+ var _a, _b;
74
87
  if (typeof ((_a = ev === null || ev === void 0 ? void 0 : ev.data) === null || _a === void 0 ? void 0 : _a._kernelMessage) !== 'undefined') {
75
88
  // only process non comlink messages
76
89
  this._processWorkerMessage(ev.data._kernelMessage);
77
90
  }
91
+ else if (typeof ((_b = ev === null || ev === void 0 ? void 0 : ev.data) === null || _b === void 0 ? void 0 : _b._logMessage) !== 'undefined') {
92
+ this._processLogMessage(ev.data._logMessage);
93
+ }
78
94
  });
79
95
  }
80
96
  const remoteOptions = this.initRemoteOptions(options);
81
- remote.initialize(remoteOptions).then(this._ready.resolve.bind(this._ready));
97
+ remote
98
+ .initialize(remoteOptions)
99
+ .then(this._ready.resolve.bind(this._ready))
100
+ .catch((err) => {
101
+ this._logger({
102
+ payload: { type: 'text', level: 'critical', data: err.message },
103
+ kernelId: this.id,
104
+ });
105
+ });
82
106
  return remote;
83
107
  }
84
108
  initRemoteOptions(options) {
@@ -98,6 +122,7 @@ export class PyodideKernel extends BaseKernel {
98
122
  mountDrive: options.mountDrive,
99
123
  loadPyodideOptions: options.loadPyodideOptions || {},
100
124
  browsingContextId: options.browsingContextId,
125
+ kernelId: this.id,
101
126
  };
102
127
  }
103
128
  /**
@@ -117,6 +142,9 @@ export class PyodideKernel extends BaseKernel {
117
142
  get ready() {
118
143
  return this._ready.promise;
119
144
  }
145
+ _processLogMessage(payload) {
146
+ this._logger({ payload, kernelId: this.id });
147
+ }
120
148
  /**
121
149
  * Process a message coming from the pyodide web worker.
122
150
  *
@@ -285,6 +313,7 @@ export class PyodideKernel extends BaseKernel {
285
313
  * @param content - The content of the reply.
286
314
  */
287
315
  async inputReply(content) {
288
- return await this._remoteKernel.inputReply(content, this.parent);
316
+ const value = 'value' in content ? content.value : undefined;
317
+ this._inputDelegate.resolve(value);
289
318
  }
290
319
  }
package/lib/tokens.d.ts CHANGED
@@ -20,15 +20,44 @@ export interface IPyodideWorkerKernel extends IWorkerKernel {
20
20
  * @param data
21
21
  */
22
22
  processDriveRequest<T extends TDriveMethod>(data: TDriveRequest<T>): TDriveResponse<T>;
23
+ }
24
+ /**
25
+ * An interface for Pyodide workers that use comlink.
26
+ */
27
+ export interface IComlinkPyodideKernel extends IPyodideWorkerKernel {
28
+ /**
29
+ * Register a callback for handling messages from the worker.
30
+ */
31
+ registerWorkerMessageCallback(callback: (msg: any) => void): void;
32
+ /**
33
+ * Register a callback for handling log messages from the worker.
34
+ */
35
+ registerLogMessageCallback(callback: (msg: any) => void): void;
36
+ }
37
+ /**
38
+ * An interface for Coincident Pyodide workers that include extra SharedArrayBuffer
39
+ * functionality.
40
+ */
41
+ export interface ICoincidentPyodideWorkerKernel extends IPyodideWorkerKernel {
42
+ /**
43
+ * Process a log message
44
+ * @param msg
45
+ */
46
+ processLogMessage(msg: any): void;
23
47
  /**
24
48
  * Process worker message
25
49
  * @param msg
26
50
  */
27
51
  processWorkerMessage(msg: any): void;
28
52
  /**
29
- * Register a callback for handling messages from the worker.
53
+ * Process stdin request, blocking until the reply is received.
54
+ * This is sync for the web worker, async for the UI thread.
55
+ * @param inputRequest
30
56
  */
31
- registerCallback(callback: (msg: any) => void): void;
57
+ processStdinRequest(content: {
58
+ prompt: string;
59
+ password: boolean;
60
+ }): string | undefined;
32
61
  }
33
62
  /**
34
63
  * Deprecated.
@@ -84,5 +113,9 @@ export declare namespace IPyodideWorkerKernel {
84
113
  lockFileURL: string;
85
114
  packages: string[];
86
115
  };
116
+ /**
117
+ * The kernel id.
118
+ */
119
+ kernelId?: string;
87
120
  }
88
121
  }
package/lib/worker.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import type Pyodide from 'pyodide';
2
- import type { DriveFS } from '@jupyterlite/contents';
2
+ import type { ILogPayload } from '@jupyterlab/logconsole';
3
3
  import { KernelMessage } from '@jupyterlab/services';
4
+ import type { DriveFS } from '@jupyterlite/contents';
4
5
  import type { IPyodideWorkerKernel } from './tokens';
5
- export declare class PyodideRemoteKernel {
6
+ export declare abstract class PyodideRemoteKernel {
6
7
  constructor();
7
8
  /**
8
9
  * Accept the URLs from the host
@@ -29,9 +30,16 @@ export declare class PyodideRemoteKernel {
29
30
  formatResult(res: any): any;
30
31
  /**
31
32
  * Register the callback function to send messages from the worker back to the main thread.
33
+ *
34
+ * @param callback the callback to register
35
+ */
36
+ registerWorkerMessageCallback(callback: (msg: any) => void): void;
37
+ /**
38
+ * Register the callback function to log messages from the worker back to the main thread.
39
+ *
32
40
  * @param callback the callback to register
33
41
  */
34
- registerCallback(callback: (msg: any) => void): void;
42
+ registerLogMessageCallback(callback: (msg: any) => void): void;
35
43
  /**
36
44
  * Makes sure pyodide is ready before continuing, and cache the parent message.
37
45
  */
@@ -97,14 +105,15 @@ export declare class PyodideRemoteKernel {
97
105
  */
98
106
  inputReply(content: any, parent: any): Promise<void>;
99
107
  /**
100
- * Send a input request to the front-end.
108
+ * Send a input request to the front-end and block until the reply is received.
101
109
  *
102
110
  * @param prompt the text to show at the prompt
103
111
  * @param password Is the request for a password?
112
+ * @returns String value from the input reply message, or undefined if there is none.
104
113
  */
105
- sendInputRequest(prompt: string, password: boolean): Promise<void>;
106
- getpass(prompt: string): Promise<any>;
107
- input(prompt: string): Promise<any>;
114
+ protected abstract sendInputRequest(prompt: string, password: boolean): string | undefined;
115
+ getpass(prompt: string): string | undefined;
116
+ input(prompt: string): string | undefined;
108
117
  /**
109
118
  * Send a comm message to the front-end.
110
119
  *
@@ -133,7 +142,7 @@ export declare class PyodideRemoteKernel {
133
142
  protected _interpreter: any;
134
143
  protected _stdout_stream: any;
135
144
  protected _stderr_stream: any;
136
- protected _resolveInputReply: any;
137
145
  protected _driveFS: DriveFS | null;
138
146
  protected _sendWorkerMessage: (msg: any) => void;
147
+ protected _logMessage: (msg: ILogPayload) => void;
139
148
  }
package/lib/worker.js CHANGED
@@ -13,6 +13,7 @@ export class PyodideRemoteKernel {
13
13
  this._driveName = '';
14
14
  this._driveFS = null;
15
15
  this._sendWorkerMessage = () => { };
16
+ this._logMessage = () => { };
16
17
  this._initialized = new Promise((resolve, reject) => {
17
18
  this._initializer = { resolve, reject };
18
19
  });
@@ -56,6 +57,23 @@ export class PyodideRemoteKernel {
56
57
  indexURL: indexUrl,
57
58
  ...options.loadPyodideOptions,
58
59
  });
60
+ const log = (msg) => {
61
+ this._logMessage({ type: 'text', level: 'info', data: msg });
62
+ };
63
+ const err = (msg) => {
64
+ this._logMessage({ type: 'text', level: 'critical', data: msg });
65
+ };
66
+ // Workaround for being able to get information about packages being loaded by Pyodide
67
+ // See discussion in https://github.com/pyodide/pyodide/discussions/5512
68
+ const origLoadPackage = this._pyodide.loadPackage;
69
+ this._pyodide.loadPackage = (pkgs, options) => origLoadPackage(pkgs, {
70
+ // Use custom callbacks to surface messages from Pyodide
71
+ messageCallback: (msg) => log(msg),
72
+ errorCallback: (msg) => {
73
+ err(msg);
74
+ },
75
+ ...options,
76
+ });
59
77
  }
60
78
  async initPackageManager(options) {
61
79
  if (!this._options) {
@@ -168,11 +186,20 @@ export class PyodideRemoteKernel {
168
186
  }
169
187
  /**
170
188
  * Register the callback function to send messages from the worker back to the main thread.
189
+ *
171
190
  * @param callback the callback to register
172
191
  */
173
- registerCallback(callback) {
192
+ registerWorkerMessageCallback(callback) {
174
193
  this._sendWorkerMessage = callback;
175
194
  }
195
+ /**
196
+ * Register the callback function to log messages from the worker back to the main thread.
197
+ *
198
+ * @param callback the callback to register
199
+ */
200
+ registerLogMessageCallback(callback) {
201
+ this._logMessage = callback;
202
+ }
176
203
  /**
177
204
  * Makes sure pyodide is ready before continuing, and cache the parent message.
178
205
  */
@@ -358,43 +385,16 @@ export class PyodideRemoteKernel {
358
385
  * @param content The incoming message with the reply
359
386
  */
360
387
  async inputReply(content, parent) {
361
- await this.setup(parent);
362
- this._resolveInputReply(content);
388
+ // Should never be called as input_reply messages are returned via service worker
389
+ // or SharedArrayBuffer.
363
390
  }
364
- /**
365
- * Send a input request to the front-end.
366
- *
367
- * @param prompt the text to show at the prompt
368
- * @param password Is the request for a password?
369
- */
370
- async sendInputRequest(prompt, password) {
371
- const content = {
372
- prompt,
373
- password,
374
- };
375
- this._sendWorkerMessage({
376
- type: 'input_request',
377
- parentHeader: this.formatResult(this._kernel._parent_header)['header'],
378
- content,
379
- });
380
- }
381
- async getpass(prompt) {
391
+ getpass(prompt) {
382
392
  prompt = typeof prompt === 'undefined' ? '' : prompt;
383
- await this.sendInputRequest(prompt, true);
384
- const replyPromise = new Promise((resolve) => {
385
- this._resolveInputReply = resolve;
386
- });
387
- const result = await replyPromise;
388
- return result['value'];
393
+ return this.sendInputRequest(prompt, true);
389
394
  }
390
- async input(prompt) {
395
+ input(prompt) {
391
396
  prompt = typeof prompt === 'undefined' ? '' : prompt;
392
- await this.sendInputRequest(prompt, false);
393
- const replyPromise = new Promise((resolve) => {
394
- this._resolveInputReply = resolve;
395
- });
396
- const result = await replyPromise;
397
- return result['value'];
397
+ return this.sendInputRequest(prompt, false);
398
398
  }
399
399
  /**
400
400
  * Send a comm message to the front-end.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jupyterlite/pyodide-kernel",
3
- "version": "0.6.0-alpha.5",
3
+ "version": "0.6.0-beta.0",
4
4
  "description": "JupyterLite - Pyodide Kernel",
5
5
  "homepage": "https://github.com/jupyterlite/pyodide-kernel",
6
6
  "bugs": {
@@ -51,6 +51,7 @@
51
51
  },
52
52
  "dependencies": {
53
53
  "@jupyterlab/coreutils": "^6.4.0",
54
+ "@jupyterlab/logconsole": "^4.4.0",
54
55
  "@jupyterlite/contents": "^0.6.0-alpha.8",
55
56
  "@jupyterlite/kernel": "^0.6.0-alpha.8",
56
57
  "coincident": "^1.2.3",
@@ -68,8 +69,8 @@
68
69
  },
69
70
  "pyodide-kernel": {
70
71
  "packages": {
71
- "py/pyodide-kernel": "0.6.0a5",
72
- "py/piplite": "0.6.0a5",
72
+ "py/pyodide-kernel": "0.6.0b0",
73
+ "py/piplite": "0.6.0b0",
73
74
  "py/ipykernel": "6.9.2",
74
75
  "py/widgetsnbextension3/widgetsnbextension": "3.6.999",
75
76
  "py/widgetsnbextension4/widgetsnbextension": "4.0.999"
package/pypi/all.json CHANGED
@@ -5,19 +5,19 @@
5
5
  {
6
6
  "comment_text": "",
7
7
  "digests": {
8
- "md5": "459eaf3dcda3c01862712d9fd835001a",
9
- "sha256": "72c335b14858d4434942862254e657b328d1d7da6630bea9950d85893bafa27a"
8
+ "md5": "f37d584c1bc7c770b7c4d10c267474ac",
9
+ "sha256": "c1e200d95949b127b2c2778f2359c8419d5d5f2b9da38f088ead1cdc6cf14dbd"
10
10
  },
11
11
  "downloads": -1,
12
12
  "filename": "ipykernel-6.9.2-py3-none-any.whl",
13
13
  "has_sig": false,
14
- "md5_digest": "459eaf3dcda3c01862712d9fd835001a",
14
+ "md5_digest": "f37d584c1bc7c770b7c4d10c267474ac",
15
15
  "packagetype": "bdist_wheel",
16
16
  "python_version": "py3",
17
17
  "requires_python": ">=3.10",
18
18
  "size": 2731,
19
- "upload_time": "2025-04-15T15:09:15.435760Z",
20
- "upload_time_iso_8601": "2025-04-15T15:09:15.435760Z",
19
+ "upload_time": "2025-05-12T16:45:30.604864Z",
20
+ "upload_time_iso_8601": "2025-05-12T16:45:30.604864Z",
21
21
  "url": "./ipykernel-6.9.2-py3-none-any.whl",
22
22
  "yanked": false,
23
23
  "yanked_reason": null
@@ -27,24 +27,24 @@
27
27
  },
28
28
  "piplite": {
29
29
  "releases": {
30
- "0.6.0a5": [
30
+ "0.6.0b0": [
31
31
  {
32
32
  "comment_text": "",
33
33
  "digests": {
34
- "md5": "a6cda0b176cf541573a6ed0aba094400",
35
- "sha256": "32d584607eee32c0cbacc41435fe13255bbda99620584dc09834dd2275905ce9"
34
+ "md5": "08ae0da8c0bd9686fe1b80518599bafe",
35
+ "sha256": "2a8748fc0363fd1c1b8058b3a4bc8efd64521b0cacd3337685c7b40170769f9b"
36
36
  },
37
37
  "downloads": -1,
38
- "filename": "piplite-0.6.0a5-py3-none-any.whl",
38
+ "filename": "piplite-0.6.0b0-py3-none-any.whl",
39
39
  "has_sig": false,
40
- "md5_digest": "a6cda0b176cf541573a6ed0aba094400",
40
+ "md5_digest": "08ae0da8c0bd9686fe1b80518599bafe",
41
41
  "packagetype": "bdist_wheel",
42
42
  "python_version": "py3",
43
43
  "requires_python": "<3.12,>=3.11",
44
44
  "size": 7253,
45
- "upload_time": "2025-04-15T15:09:15.435760Z",
46
- "upload_time_iso_8601": "2025-04-15T15:09:15.435760Z",
47
- "url": "./piplite-0.6.0a5-py3-none-any.whl",
45
+ "upload_time": "2025-05-12T16:45:30.604864Z",
46
+ "upload_time_iso_8601": "2025-05-12T16:45:30.604864Z",
47
+ "url": "./piplite-0.6.0b0-py3-none-any.whl",
48
48
  "yanked": false,
49
49
  "yanked_reason": null
50
50
  }
@@ -53,24 +53,24 @@
53
53
  },
54
54
  "pyodide-kernel": {
55
55
  "releases": {
56
- "0.6.0a5": [
56
+ "0.6.0b0": [
57
57
  {
58
58
  "comment_text": "",
59
59
  "digests": {
60
- "md5": "ccf6951cf6a5c53eebdf8e633551ea4e",
61
- "sha256": "81e5a4eaa6e0d92b144e18b52a1c9295e89110ff7bf1d7c4853d52984b9ba8ee"
60
+ "md5": "ebb84e59c120ad300423b3da42f662da",
61
+ "sha256": "7c12b90f88cbf4c6b415082e930483913a3f15968fbc485d9275409de2eeeba3"
62
62
  },
63
63
  "downloads": -1,
64
- "filename": "pyodide_kernel-0.6.0a5-py3-none-any.whl",
64
+ "filename": "pyodide_kernel-0.6.0b0-py3-none-any.whl",
65
65
  "has_sig": false,
66
- "md5_digest": "ccf6951cf6a5c53eebdf8e633551ea4e",
66
+ "md5_digest": "ebb84e59c120ad300423b3da42f662da",
67
67
  "packagetype": "bdist_wheel",
68
68
  "python_version": "py3",
69
69
  "requires_python": "<3.12,>=3.11",
70
- "size": 11415,
71
- "upload_time": "2025-04-15T15:09:15.434760Z",
72
- "upload_time_iso_8601": "2025-04-15T15:09:15.434760Z",
73
- "url": "./pyodide_kernel-0.6.0a5-py3-none-any.whl",
70
+ "size": 11412,
71
+ "upload_time": "2025-05-12T16:45:30.604864Z",
72
+ "upload_time_iso_8601": "2025-05-12T16:45:30.604864Z",
73
+ "url": "./pyodide_kernel-0.6.0b0-py3-none-any.whl",
74
74
  "yanked": false,
75
75
  "yanked_reason": null
76
76
  }
@@ -83,19 +83,19 @@
83
83
  {
84
84
  "comment_text": "",
85
85
  "digests": {
86
- "md5": "2288aa58b161ae3dd5d590b364dce5ce",
87
- "sha256": "3389e73e8176ea1306788adff5d12b1559863f32851e668a9690494922633c30"
86
+ "md5": "11920654c4118e8c2f96ffe6a85529cc",
87
+ "sha256": "52c9995fb48f6576e73004de88c4a8c4e00b02166704735fef7041b373699df9"
88
88
  },
89
89
  "downloads": -1,
90
90
  "filename": "widgetsnbextension-3.6.999-py3-none-any.whl",
91
91
  "has_sig": false,
92
- "md5_digest": "2288aa58b161ae3dd5d590b364dce5ce",
92
+ "md5_digest": "11920654c4118e8c2f96ffe6a85529cc",
93
93
  "packagetype": "bdist_wheel",
94
94
  "python_version": "py3",
95
95
  "requires_python": "<3.12,>=3.11",
96
96
  "size": 2369,
97
- "upload_time": "2025-04-15T15:09:15.435760Z",
98
- "upload_time_iso_8601": "2025-04-15T15:09:15.435760Z",
97
+ "upload_time": "2025-05-12T16:45:30.605864Z",
98
+ "upload_time_iso_8601": "2025-05-12T16:45:30.605864Z",
99
99
  "url": "./widgetsnbextension-3.6.999-py3-none-any.whl",
100
100
  "yanked": false,
101
101
  "yanked_reason": null
@@ -105,19 +105,19 @@
105
105
  {
106
106
  "comment_text": "",
107
107
  "digests": {
108
- "md5": "ddd85a7cd15729c14b6387a0723793dc",
109
- "sha256": "a22acd9d9921b2c542bd98ce33ab8ca6317898aee8f819bef57b41b779981a40"
108
+ "md5": "5bc0ab1125788cfdee56177b5fd759ee",
109
+ "sha256": "90f5943bfac451c71c60232fc6d9e3435775538de12006b8843dd27d93c07936"
110
110
  },
111
111
  "downloads": -1,
112
112
  "filename": "widgetsnbextension-4.0.999-py3-none-any.whl",
113
113
  "has_sig": false,
114
- "md5_digest": "ddd85a7cd15729c14b6387a0723793dc",
114
+ "md5_digest": "5bc0ab1125788cfdee56177b5fd759ee",
115
115
  "packagetype": "bdist_wheel",
116
116
  "python_version": "py3",
117
117
  "requires_python": "<3.12,>=3.11",
118
118
  "size": 2370,
119
- "upload_time": "2025-04-15T15:09:15.435760Z",
120
- "upload_time_iso_8601": "2025-04-15T15:09:15.435760Z",
119
+ "upload_time": "2025-05-12T16:45:30.605864Z",
120
+ "upload_time_iso_8601": "2025-05-12T16:45:30.605864Z",
121
121
  "url": "./widgetsnbextension-4.0.999-py3-none-any.whl",
122
122
  "yanked": false,
123
123
  "yanked_reason": null
index 722cfdd..f81e15d 100644
Binary file