I want to run Python code from a text-area in HTML and save the output in a div. I am using pyodide.js
https://cdn.jsdelivr.net/pyodide/v0.25.0/full/pyodide.js to run Python. I would also like to use a worker which does not affect the main JS thread.
I have a working code that logs the output to the JavaScript console in the browser, and I can’t figure out a way to get the result in a string.
Can you help me get the code output saved to a variable?
The main function runPythonCode
outputs the result to the console instead of returning an output to the variable result
(result=undefined)
in main-worker.js
.
Find the detailed code below.
//test-code
import { runPythonCode } from "./main-worker.js";
$(element).find(".run-code:first").click(
async function() {
let current_code = "print('Hello, World!')"
let result = await runPythonCode(current_code)
console.log("Run clicked", result)
}
)
// main-worker.js
// main-worker.js
import { asyncRun } from "./py-worker.js";
console.log("Python main worker started.")
async function runPythonCode(pythonCode, context) {
try {
const { result, error } = await asyncRun(pythonCode, context);
if (result) {
return result.toString()
} else if (error) {
return error
}
} catch (e) {
console.error("Error communicating with the worker:", e);
}
}
export {runPythonCode}
// py-worker.js
// py-worker.js
const pyodideWorker = new Worker("./worker.js");
const callbacks = {};
pyodideWorker.onmessage = (event) => {
const { id, result, error } = event.data;
const onSuccess = callbacks[id];
delete callbacks[id];
if (onSuccess) {
if (result) {
onSuccess({ result });
} else if (error) {
onSuccess({ error });
}
}
};
const asyncRun = (pythonCode, context = {}) => {
const id = Date.now().toString(); // Unique identifier for each run
return new Promise((resolve) => {
callbacks[id] = resolve;
pyodideWorker.postMessage({ id, pythonCode, context });
});
};
export { asyncRun };
// worker.js
// worker.js
importScripts("https://cdn.jsdelivr.net/pyodide/v0.25.0/full/pyodide.js");
async function loadPyodideAndPackages() {
self.pyodide = await loadPyodide({
"indexURL" : "https://cdn.jsdelivr.net/pyodide/v0.25.0/full/",
});
// Add any necessary packages here
// await self.pyodide.loadPackage(["numpy"]);
}
let pyodideReadyPromise = loadPyodideAndPackages();
self.onmessage = async (event) => {
await pyodideReadyPromise;
const { id, pythonCode, context } = event.data;
// Copy the context variables to the worker's scope
for (const key in context) {
self[key] = context[key];
}
try {
// Load packages and run Python code
await self.pyodide.runPythonAsync(pythonCode);
postMessage({ id, result: "Execution complete" });
} catch (error) {
postMessage({ id, error: error.message });
}
};