1

I am trying to run a simple pyodide example, but am not too familiar with javascript or pyodide and am not sure why the output is undefined. The statement is executed fine as I can see the correct output in the console log, but I cannot assign the output to the document.

here is the code

<!DOCTYPE html>
<html>
<head>
    <script type="text/javascript">
        window.languagePluginUrl = 'https://cdn.jsdelivr.net/pyodide/v0.17.0a2/full/';
    </script>
    <script src="https://cdn.jsdelivr.net/pyodide/v0.17.0a2/full/pyodide.js"></script>
</head>

<body>
  <p>You can execute any Python code. Just enter something in the box below and click the button.</p>
  <textarea id='code' style='width: 50%;' rows='10'>print('hello')</textarea>
  <button onclick='evaluatePython()'>Run</button>
  <br>
  <br>
  <div>
    Output:
  </div>
  <textarea id='output' style='width: 50%;' rows='3' disabled></textarea>

  <script>
    const output = document.getElementById("output");
    const code = document.getElementById("code");

    // show output
    function addToOutput(s) {
      output.value =  s;
      
    }

    function evaluatePython() {
      let output = pyodide.runPythonAsync(code.value)
        .then(output => addToOutput(output))
        .catch((err) => { addToOutput(err)});
    }
  </script>
</body>

</html>

I was loosely following the alternative example from here -- https://pyodide.org/en/stable/using_pyodide_from_javascript.html

Aray Karjauv
  • 2,679
  • 2
  • 26
  • 44
JLJ
  • 77
  • 6
  • 1
    This code works. The problem is that `print` does not return anything. Try to evaluate something else (e.g. `1+1`). Also, check out this [tutorial](https://medium.com/swlh/python-in-web-easy-5f7de3813055) – Aray Karjauv Apr 12 '21 at 11:21
  • And please edit your question and wrap your code in an `html` block so others can run it live. – Aray Karjauv Apr 12 '21 at 11:23
  • @ArayKarjauv Thanks. Didn't know that you could run it live. Also, that completely makes sense, of course, print() doesn't return anything. I was trying to make it so that the user could type any python code including print and the output would be displayed in the output box. Currently, you can see the output of the print statement is in the console. I basically wanted to do the same as this https://ritabratamaiti.github.io/pyRunBrowser/ – JLJ Apr 12 '21 at 21:13
  • @ArayKarjauv Also, I did see your tutorial. After I had figured out the above problem, I was planning on moving on to plotting. – JLJ Apr 12 '21 at 21:14
  • Seems like this a known thing https://github.com/pyodide/pyodide/issues/8 – JLJ Apr 12 '21 at 21:23

1 Answers1

4

Basically, you can implement your own function for printing. However, if you want to use exactly print you can override the function from JS.

Update: Pyodide v0.21.0

pyodide.globals.set('print', s => console.log(s))

This will replace the python function print with the JS console.log

const output = document.getElementById("output");
const code = document.getElementById("code");

async function evaluatePython() {
  // load imports if there are any
  await pyodide.loadPackagesFromImports(code.value)
  addToOutput(pyodide.runPython(code.value))
}

// show output
function addToOutput(s) {
  output.value =  s;
}

let pyodide;

// init pyodide
(async () => { // enable await
  pyodide = await loadPyodide();
  
  // override default print behavior
  pyodide.globals.set('print', s => console.log(s))
})() // call the function immediately
<script src="https://cdn.jsdelivr.net/pyodide/v0.21.0/full/pyodide.js"></script>
<p>You can execute any Python code. Just enter something in the box below and click the button.</p>
  <textarea id='code' style='width: 50%;' rows='10'>print('hello')</textarea>
  <button onclick='evaluatePython()'>Run</button>
  <br>
  <br>
  <div>
    Output:
  </div>
  <textarea id='output' style='width: 50%; margin-bottom: 100px;' rows='3' disabled></textarea>

More examples can be found here.


Old answer (related to Pyodide v0.15.0)

languagePluginLoader.then(()=>{
  pyodide.globals.print = s => s
})

which does nothing but returns the input parameter, since its output will then be written to the container (.then(output => addToOutput(output))). Of course, you can implement any custom behavior, such as writing the input to a container directly.

<!DOCTYPE html>
<html>
<head>
    <script type="text/javascript">
        window.languagePluginUrl = 'https://cdn.jsdelivr.net/pyodide/v0.17.0a2/full/';
    </script>
    <script src="https://cdn.jsdelivr.net/pyodide/v0.17.0a2/full/pyodide.js"></script>
</head>

<body>
  <p>You can execute any Python code. Just enter something in the box below and click the button.</p>
  <textarea id='code' style='width: 50%;' rows='10'>print('hello')</textarea>
  <button onclick='evaluatePython()'>Run</button>
  <br>
  <br>
  <div>
    Output:
  </div>
  <textarea id='output' style='width: 50%;' rows='3' disabled></textarea>

  <script>
    const output = document.getElementById("output");
    const code = document.getElementById("code");

    // show output
    function addToOutput(s) {
      output.value =  s;
    }

    function evaluatePython() {
      let output = pyodide.runPythonAsync(code.value)
        .then(output => addToOutput(output))
        .catch((err) => { addToOutput(err)});
    }
    
    languagePluginLoader.then(()=>{
      // override default print behavior
      pyodide.globals.print = s => s
    })
  </script>
</body>

</html>
Aray Karjauv
  • 2,679
  • 2
  • 26
  • 44