Unverified Commit d82efe30 authored by Jeremy Tuloup's avatar Jeremy Tuloup Committed by GitHub
Browse files

Merge pull request #57 from jtpio/pyolite

First steps towards an improved Pyodide kernel
parents 4dacbe03 db48ea0c
......@@ -9,10 +9,13 @@
}
},
"jupyterlite-js": {
"command": ["yarn", "serve", "--port", "{port}"],
"command": ["yarn", "serve"],
"launcher_entry": {
"icon_path": "docs/_static/icon.svg",
"title": "JupyterLite (js)"
},
"environment": {
"PORT": "{port}"
}
}
}
......
lint-staged.config.js
.eslintrc.js
scripts/serve.js
node_modules
**/build
......
......@@ -124,3 +124,5 @@ app/test/data
app/kernels
yarn-error.log
!packages/pyolite-kernel/py/dist/
......@@ -67,11 +67,20 @@ yarn build:prod
#### Serve
> These are **not real server solutions**, but they _will_ serve all of the assets types
> (including `.wasm`) correctly for JupyterLite under development, testing, and demo
> purposes.
To serve with `scripts/serve.js`, based on Node.js's
[`http`](https://nodejs.org/api/http.html) module:
```
yarn serve
```
To serve with python's built-in http server:
To serve with Python's built-in
[`http.server`](https://docs.python.org/3/library/http.server.html) module (requires
Python 3.7+):
```
yarn serve:py
......
......@@ -13,7 +13,7 @@ require('./build/style.js');
const serverMods = [
import('@jupyterlite/javascript-kernel-extension'),
import('@jupyterlite/p5-kernel-extension'),
import('@jupyterlite/pyodide-kernel-extension'),
import('@jupyterlite/pyolite-kernel-extension'),
import('@jupyterlite/server-extension')
];
......
......@@ -20,7 +20,7 @@
"@jupyterlite/iframe-extension": "^0.1.0",
"@jupyterlite/javascript-kernel-extension": "^0.1.0",
"@jupyterlite/p5-kernel-extension": "^0.1.0",
"@jupyterlite/pyodide-kernel-extension": "^0.1.0",
"@jupyterlite/pyolite-kernel-extension": "^0.1.0",
"@jupyterlite/server-extension": "^0.1.0",
"@jupyterlite/theme-extension": "^0.1.0",
"@jupyterlab-classic/application": "^0.1.10",
......
......@@ -54,7 +54,7 @@ const mimeExtensions = [
const mods = [
import('@jupyterlite/javascript-kernel-extension'),
import('@jupyterlite/p5-kernel-extension'),
import('@jupyterlite/pyodide-kernel-extension'),
import('@jupyterlite/pyolite-kernel-extension'),
import('@jupyterlite/server-extension')
];
......
......@@ -19,7 +19,7 @@
"@jupyterlite/iframe-extension": "^0.1.0",
"@jupyterlite/javascript-kernel-extension": "^0.1.0",
"@jupyterlite/p5-kernel-extension": "^0.1.0",
"@jupyterlite/pyodide-kernel-extension": "^0.1.0",
"@jupyterlite/pyolite-kernel-extension": "^0.1.0",
"@jupyterlite/application-extension": "^0.1.0",
"@jupyterlite/server-extension": "^0.1.0",
"@jupyterlite/theme-extension": "^0.1.0",
......
......@@ -63,7 +63,9 @@ module.exports = [
entry: ['whatwg-fetch', './index.js'],
output: {
path: path.resolve(buildDir),
filename: 'bundle.js'
filename: 'bundle.js',
// to generate valid wheel names
assetModuleFilename: '[name][ext][query]'
},
bail: true,
devtool: 'source-map',
......@@ -106,6 +108,10 @@ module.exports = [
loader: 'raw-loader'
}
},
{
test: /\.whl/,
type: 'asset/resource'
},
{
resourceQuery: /raw/,
type: 'asset/source'
......
......@@ -19,6 +19,7 @@
"scripts": {
"bootstrap": "yarn && yarn clean && yarn build && yarn lint && yarn test",
"build": "yarn build:lib && yarn build:app",
"build:python": "lerna run build:python",
"build:lib": "lerna run build --scope @jupyterlite/metapackage",
"build:app": "lerna run build --stream --parallel --scope \"@jupyterlite/app-classic\" --scope \"@jupyterlite/app-lab\"",
"build:prod": "lerna run build:prod",
......@@ -37,8 +38,8 @@
"watch": "run-p watch:lib watch:app",
"watch:lib": "lerna exec --stream --scope @jupyterlite/metapackage yarn watch",
"watch:app": "lerna exec --stream --stream --parallel --scope \"@jupyterlite/app-classic\" --scope \"@jupyterlite/app-lab\" yarn watch",
"serve": "cd app && http-server",
"serve:py": "cd app && python -m http.server"
"serve": "node scripts/serve.js",
"serve:py": "cd app && python -m http.server -b 127.0.0.1"
},
"husky": {
"hooks": {
......@@ -55,7 +56,6 @@
"eslint-plugin-prettier": "^3.1.4",
"eslint-plugin-react": "^7.21.5",
"extra-watch-webpack-plugin": "^1.0.3",
"http-server": "^0.12.3",
"husky": "^3",
"jest": "^26.4.2",
"jest-junit": "^11.1.0",
......
......@@ -30,8 +30,8 @@
"@jupyterlite/kernel": "file:../kernel",
"@jupyterlite/p5-kernel": "file:../p5-kernel",
"@jupyterlite/p5-kernel-extension": "file:../p5-kernel-extension",
"@jupyterlite/pyodide-kernel": "file:../pyodide-kernel",
"@jupyterlite/pyodide-kernel-extension": "file:../pyodide-kernel-extension",
"@jupyterlite/pyolite-kernel": "file:../pyolite-kernel",
"@jupyterlite/pyolite-kernel-extension": "file:../pyolite-kernel-extension",
"@jupyterlite/server": "file:../server-extension",
"@jupyterlite/session": "file:../session",
"@jupyterlite/settings": "file:../settings",
......
......@@ -8,8 +8,8 @@ import '@jupyterlite/javascript-kernel';
import '@jupyterlite/kernel';
import '@jupyterlite/p5-kernel';
import '@jupyterlite/p5-kernel-extension';
import '@jupyterlite/pyodide-kernel-extension';
import '@jupyterlite/pyodide-kernel';
import '@jupyterlite/pyolite-kernel-extension';
import '@jupyterlite/pyolite-kernel';
import '@jupyterlite/server';
import '@jupyterlite/server-extension';
import '@jupyterlite/session';
......
......@@ -16,8 +16,8 @@
{ "path": "../kernel" },
{ "path": "../p5-kernel" },
{ "path": "../p5-kernel-extension" },
{ "path": "../pyodide-kernel" },
{ "path": "../pyodide-kernel-extension" },
{ "path": "../pyolite-kernel" },
{ "path": "../pyolite-kernel-extension" },
{ "path": "../server-extension" },
{ "path": "../session" },
{ "path": "../settings" },
......
......@@ -182,7 +182,7 @@ export abstract class BaseKernel implements IKernel {
* @param parentHeader The parent header.
* @param content The stream content.
*/
stream(content: KernelMessage.IStreamMsg['content']): void {
protected stream(content: KernelMessage.IStreamMsg['content']): void {
const message = KernelMessage.createMessage<KernelMessage.IStreamMsg>({
channel: 'iopub',
msgType: 'stream',
......@@ -194,6 +194,23 @@ export abstract class BaseKernel implements IKernel {
this._sendMessage(message);
}
/**
* Send a `display_data` message to the client.
*
* @param content The display_data content.
*/
protected displayData(content: KernelMessage.IDisplayDataMsg['content']): void {
const message = KernelMessage.createMessage<KernelMessage.IDisplayDataMsg>({
channel: 'iopub',
msgType: 'display_data',
// TODO: better handle this
session: this._parentHeader?.session ?? '',
parentHeader: this._parentHeader,
content
});
this._sendMessage(message);
}
/**
* Send an 'idle' status message.
*
......@@ -269,7 +286,10 @@ export abstract class BaseKernel implements IKernel {
if (!content.code.startsWith('%')) {
this._history.push([0, 0, content.code]);
}
this._executeResult(msg, result);
// send the execute result only if there is a result
if (Object.keys(result.data).length > 0) {
this._executeResult(msg, result);
}
this._executeReply(msg, {
execution_count: this._executionCount,
status: 'ok',
......
const BOOTSTRAP =
'import io, code, sys; sys.stdout = io.StringIO(); sys.stderr = io.StringIO()';
async function loadPyodideAndPackages() {
await languagePluginLoader;
await pyodide.loadPackage([]);
}
const pyodideReadyPromise = loadPyodideAndPackages();
self.onmessage = async (event: MessageEvent): Promise<void> => {
await pyodideReadyPromise;
const data = event.data;
console.log('Inside worker', data);
pyodide.runPython(BOOTSTRAP);
let msgType = 'results';
let renderHtml = false;
try {
let results = await pyodide.runPythonAsync(data.code, (ev: any) => {
console.log(ev);
});
const stdout = pyodide.runPython('sys.stdout.getvalue()');
if (stdout !== '') {
msgType = 'stdout';
}
const stderr = pyodide.runPython('sys.stderr.getvalue()');
if (stderr !== '') {
msgType = 'stderr';
}
// hack to support rendering of pandas dataframes.
if (pyodide._module.PyProxy.isPyProxy(results)) {
try {
results = results._repr_html_();
renderHtml = true;
} catch {
results = String(results);
}
}
const msg = {
result: results,
parentHeader: data.parentHeader,
stdout,
stderr,
type: msgType,
msg: data.message,
renderHtml: renderHtml
};
postMessage(msg);
} catch (error) {
msgType = 'stderr';
postMessage({ stderr: error, type: msgType, msg: data.message });
}
};
{
"name": "@jupyterlite/pyodide-kernel-extension",
"name": "@jupyterlite/pyolite-kernel-extension",
"version": "0.1.0",
"description": "JupyterLite - Pyodide Kernel Extension",
"description": "JupyterLite - Pyolite Kernel Extension",
"homepage": "https://github.com/jtpio/jupyterlite",
"bugs": {
"url": "https://github.com/jtpio/jupyterlite/issues"
......@@ -40,7 +40,7 @@
"dependencies": {
"@jupyterlab/coreutils": "^5.0.0",
"@jupyterlite/kernel": "^0.1.0",
"@jupyterlite/pyodide-kernel": "^0.1.0",
"@jupyterlite/pyolite-kernel": "^0.1.0",
"@jupyterlite/server": "^0.1.0"
},
"devDependencies": {
......
......@@ -7,18 +7,18 @@ import { JupyterLiteServer, JupyterLiteServerPlugin } from '@jupyterlite/server'
import { IKernel, IKernelSpecs } from '@jupyterlite/kernel';
import { PyodideKernel } from '@jupyterlite/pyodide-kernel';
import { PyoliteKernel } from '@jupyterlite/pyolite-kernel';
/**
* The default CDN fallback for Pyodide
*/
const PYODIDE_CDN_URL = 'https://pyodide-cdn2.iodide.io/v0.17.0a2/full/pyodide.js';
const PYODIDE_CDN_URL = 'https://cdn.jsdelivr.net/pyodide/v0.17.0/full/pyodide.js';
/**
* A plugin to register the Pyodide kernel.
*/
const kernel: JupyterLiteServerPlugin<void> = {
id: '@jupyterlite/pyodide-kernel-extension:kernel',
id: '@jupyterlite/pyolite-kernel-extension:kernel',
autoStart: true,
requires: [IKernelSpecs],
activate: (app: JupyterLiteServer, kernelspecs: IKernelSpecs) => {
......@@ -30,13 +30,13 @@ const kernel: JupyterLiteServerPlugin<void> = {
kernelspecs.register({
spec: {
name: 'python',
display_name: 'Pyodide',
display_name: 'Pyolite',
language: 'python',
argv: [],
spec: {
argv: [],
env: {},
display_name: 'Pyodide',
display_name: 'Pyolite',
language: 'python',
interrupt_mode: 'message',
metadata: {}
......@@ -47,7 +47,7 @@ const kernel: JupyterLiteServerPlugin<void> = {
}
},
create: async (options: IKernel.IOptions): Promise<IKernel> => {
return new PyodideKernel({
return new PyoliteKernel({
...options,
pyodideUrl
});
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment