@dodona/papyros
Version:
Scratchpad for multiple programming languages in the browser.
114 lines • 4.6 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Backend, RunMode } from "../../Backend";
import { pyodideExpose, loadPyodideAndPackage } from "pyodide-worker-runner";
/* eslint-disable-next-line */
const pythonPackageUrl = require("./python_package.tar.gz.load_by_url").default;
/**
* Implementation of a Python backend for Papyros
* Powered by Pyodide (https://pyodide.org/)
*/
export class PythonWorker extends Backend {
constructor() {
super();
this.pyodide = {};
this.papyros = {};
this.installPromise = null;
}
static convert(data) {
return data.toJs ? data.toJs({ dict_converter: Object.fromEntries }) : data;
}
/**
* @return {any} Function to expose a method with Pyodide support
*/
syncExpose() {
return pyodideExpose;
}
static getPyodide() {
return __awaiter(this, void 0, void 0, function* () {
return yield loadPyodideAndPackage({ url: pythonPackageUrl, format: ".tgz" });
});
}
launch(onEvent, onOverflow) {
const _super = Object.create(null, {
launch: { get: () => super.launch }
});
return __awaiter(this, void 0, void 0, function* () {
yield _super.launch.call(this, onEvent, onOverflow);
this.pyodide = yield PythonWorker.getPyodide();
// Python calls our function with a PyProxy dict or a Js Map,
// These must be converted to a PapyrosEvent (JS Object) to allow message passing
this.papyros = this.pyodide.pyimport("papyros").Papyros.callKwargs({
callback: (e) => {
const converted = PythonWorker.convert(e);
return this.onEvent(converted);
},
buffer_constructor: (cb) => {
this.queue.setCallback(cb);
return this.queue;
}
});
// preload micropip to allow installing packages
yield this.pyodide.loadPackage("micropip");
});
}
/**
* Helper method to install imports and prevent race conditions with double downloading
* @param {string} code The code containing import statements
*/
installImports(code) {
return __awaiter(this, void 0, void 0, function* () {
if (this.installPromise == null) {
this.installPromise = this.papyros.install_imports.callKwargs({
source_code: code,
ignore_missing: true
});
}
yield this.installPromise;
this.installPromise = null;
});
}
runModes(code) {
let modes = super.runModes(code);
if (this.papyros.has_doctests(code)) {
modes = [RunMode.Doctest, ...modes];
}
modes = [RunMode.Debug, ...modes];
return modes;
}
runCode(extras_1, code_1) {
return __awaiter(this, arguments, void 0, function* (extras, code, mode = "exec") {
this.extras = extras;
if (extras.interruptBuffer) {
this.pyodide.setInterruptBuffer(extras.interruptBuffer);
}
yield this.installImports(code);
return yield this.papyros.run_async.callKwargs({
source_code: code,
mode: mode
});
});
}
lintCode(code) {
return __awaiter(this, void 0, void 0, function* () {
yield this.installImports(code);
return PythonWorker.convert(this.papyros.lint(code));
});
}
provideFiles(inlineFiles, hrefFiles) {
return __awaiter(this, void 0, void 0, function* () {
yield this.papyros.provide_files.callKwargs({
inline_files: JSON.stringify(inlineFiles),
href_files: JSON.stringify(hrefFiles)
});
});
}
}
//# sourceMappingURL=PythonWorker.js.map