0

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 });
    }
};

4
  • Hey! 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. Commented Jan 28, 2024 at 8:36
  • If you want to use a worker, you'll need to use a javascript means to pass the value out, usually messaging (page context, worker context), to get the content out of the worker and into the page. In that case, the bit about the python is incidental. Commented Jan 28, 2024 at 8:37
  • If return result.toString() writes to console, then what happens if you replace that with showResult(result.toString()) and add const showResult = str => document.getElementById('output').innerHTML = str; do? Commented Jan 28, 2024 at 8:43
  • Check out this answer which uses a web worker and outputs a string. Commented Mar 31 at 19:03

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.