Skip to content

Commit

Permalink
Make Kernel.run an async function
Browse files Browse the repository at this point in the history
  • Loading branch information
rameshvarun committed Sep 8, 2023
1 parent 382e6f2 commit 344b7ed
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 87 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"scripts": {
"start": "webpack serve --open --env mode=development",
"build": "rm -rf dist && webpack --env mode=production",
"format": "prettier --write src/*.ts src/*.tsx src/*.css",
"format": "prettier --write src/*.ts src/*.tsx src/*.css src/browser-unit.html",
"typecheck": "tsc --noEmit"
},
"dependencies": {
Expand Down
42 changes: 21 additions & 21 deletions src/blog-cells.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -192,27 +192,27 @@ class Cell extends React.Component<
setTimeout(() => resolve(), 500);
});

this.props.kernel.run(
code,
(line) => {
this.setState((state) => {
state.output.push(line);
return state;
});
},
async () => {
// Wait the minimum amount of run-time.
await minimumWait;

this.running = false;
this.setState((state) => {
state.kind = "re-runnable";
if (state.output.length === 0)
state.output.push({ type: "log", line: "Done." });
return state;
});
}
);
// Run the code.
await this.props.kernel.run(code, (line) => {
this.setState((state) => {
state.output.push(line);
return state;
});
});

// Wait the minimum amount of run-time.
await minimumWait;

// Mark as not running.
this.running = false;

// Update the state.
this.setState((state) => {
state.kind = "re-runnable";
if (state.output.length === 0)
state.output.push({ type: "log", line: "Done." });
return state;
});
}
}

Expand Down
98 changes: 75 additions & 23 deletions src/browser-unit.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,88 @@
<script type="module" src="./blog-cells.js"></script>

<script class="mocha-init">
mocha.setup('bdd');
mocha.setup("bdd");
chai.config.truncateThreshold = 0;
</script>
<script class="mocha-exec" type="module">
describe("JavaScriptKernel", () => {
it("Runs basic code.", (done) => {
const kernel = new BlogCells.JavaScriptKernel();
const onOutput = chai.spy();
kernel.run("console.log('Hello World!');", onOutput, () => {
chai.expect(onOutput).to.have.been.called.with({
type: "log",
line: "Hello World!"
});

done();
});
it("Runs basic code.", async () => {
const kernel = new BlogCells.JavaScriptKernel();
const onOutput = chai.spy();
await kernel.run("console.log('Hello World!');", onOutput);

chai.expect(onOutput).to.have.been.called.with({
type: "log",
line: "Hello World!",
});
});

it("Allows defining code across cells.", async () => {
const kernel = new BlogCells.JavaScriptKernel();
const onOutput = chai.spy();
await kernel.run(
`export function hello() { return "Hello World!"; }`,
onOutput
);
await kernel.run(`console.log(hello());`, onOutput);

chai.expect(onOutput).to.have.been.called.with({
type: "log",
line: "Hello World!",
});
});
});

describe("PythonKernel", () => {
it("Runs basic code.", (done) => {
const kernel = new BlogCells.PythonKernel();
const onOutput = chai.spy();
kernel.run("print('Hello World!');", onOutput, () => {
chai.expect(onOutput).to.have.been.called.with({
type: "log",
line: "Hello World!"
});

done();
});
it("Runs basic code.", async () => {
const kernel = new BlogCells.PythonKernel();
const onOutput = chai.spy();
await kernel.run("print('Hello World!');", onOutput);

chai.expect(onOutput).to.have.been.called.with({
type: "log",
line: "Hello World!",
});
}).timeout(10 * 1000);

it("Allows defining code across cells.", async () => {
const kernel = new BlogCells.PythonKernel();
const onOutput = chai.spy();
await kernel.run(`def hello(): return "Hello World!"`, onOutput);
await kernel.run(`print(hello())`, onOutput);

chai.expect(onOutput).to.have.been.called.with({
type: "log",
line: "Hello World!",
});
}).timeout(10 * 1000);

it("Allows importing packages with micropip.", async () => {
const kernel = new BlogCells.PythonKernel();
const onOutput = chai.spy();
await kernel.run(
`import micropip; await micropip.install("numpy")`,
onOutput
);
await kernel.run(
`import numpy as np; print(np.zeros(shape=(3, 3)))`,
onOutput
);

console.log(onOutput);

chai.expect(onOutput).on.nth(1).been.called.with({
type: "log",
line: "[[0. 0. 0.]",
});
chai.expect(onOutput).on.nth(2).been.called.with({
type: "log",
line: " [0. 0. 0.]",
});
chai.expect(onOutput).on.nth(3).been.called.with({
type: "log",
line: " [0. 0. 0.]]",
});
}).timeout(10 * 1000);
});

Expand Down
42 changes: 22 additions & 20 deletions src/javascript-kernel/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,29 +23,31 @@ export type ExecutionResponse = {
export class JavaScriptKernel extends Kernel {
worker: Worker = new Worker(URL.createObjectURL(blob));

run(code: string, onOutput: (line: OutputLine) => void, onDone: () => void) {
run(code: string, onOutput: (line: OutputLine) => void): Promise<void> {
// Generate a unique ID to track this execution request.
const requestID = this.getRequestID();

const messageHandler = (e: MessageEvent<ExecutionResponse>) => {
if (e.data.requestID != requestID) return;

if (e.data.kind === "run-code-output") {
onOutput(e.data.output);
} else if (e.data.kind === "run-code-done") {
this.worker.removeEventListener("message", messageHandler);
onDone();
}
};

this.worker.addEventListener("message", messageHandler);

// Post the code to the worker.
this.worker.postMessage({
kind: "run-code",
code: code,
requestID: requestID,
} as ExecutionRequest);
return new Promise<void>((resolve) => {
const messageHandler = (e: MessageEvent<ExecutionResponse>) => {
if (e.data.requestID != requestID) return;

if (e.data.kind === "run-code-output") {
onOutput(e.data.output);
} else if (e.data.kind === "run-code-done") {
this.worker.removeEventListener("message", messageHandler);
resolve();
}
};

this.worker.addEventListener("message", messageHandler);

// Post the code to the worker.
this.worker.postMessage({
kind: "run-code",
code: code,
requestID: requestID,
} as ExecutionRequest);
});
}

getSyntaxHighlighter() {
Expand Down
6 changes: 3 additions & 3 deletions src/kernel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ export abstract class Kernel {

abstract run(
code: string,
onOutput: (line: OutputLine) => void,
onDone: () => void
);
onOutput: (line: OutputLine) => void
): Promise<void>;

abstract getSyntaxHighlighter(): LanguageSupport;
}
40 changes: 21 additions & 19 deletions src/python-kernel/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,30 @@ import { Kernel, OutputLine } from "../kernel";
export class PythonKernel extends Kernel {
worker: Worker = new Worker(URL.createObjectURL(blob));

run(code: string, onOutput: (line: OutputLine) => void, onDone: () => void) {
run(code: string, onOutput: (line: OutputLine) => void): Promise<void> {
// Generate a unique ID to track this execution request.
const requestID = this.getRequestID();

const messageHandler = (e: MessageEvent) => {
if (e.data.requestID != requestID) return;

if (e.data.kind === "run-code-output") {
onOutput(e.data.output);
} else if (e.data.kind === "run-code-done") {
this.worker.removeEventListener("message", messageHandler);
onDone();
}
};

this.worker.addEventListener("message", messageHandler);

// Post the code to the worker.
this.worker.postMessage({
kind: "run-code",
code: code,
requestID: requestID,
return new Promise<void>((resolve) => {
const messageHandler = (e: MessageEvent) => {
if (e.data.requestID != requestID) return;

if (e.data.kind === "run-code-output") {
onOutput(e.data.output);
} else if (e.data.kind === "run-code-done") {
this.worker.removeEventListener("message", messageHandler);
resolve();
}
};

this.worker.addEventListener("message", messageHandler);

// Post the code to the worker.
this.worker.postMessage({
kind: "run-code",
code: code,
requestID: requestID,
});
});
}

Expand Down

0 comments on commit 344b7ed

Please sign in to comment.