pyodide/docs/using_pyodide_from_javascri...

6.8 KiB

(using_from_javascript)=

Using Pyodide from Javascript

This document describes using Pyodide directly from Javascript. For information about using Pyodide from Iodide, see {ref}using_from_iodide.

Startup

To include Pyodide in your project you can use the following CDN URL,

https://pyodide-cdn2.iodide.io/v0.15.0/full/pyodide.js

You can also download a release from Github releases (or build it yourself), include its contents in your distribution, and import the pyodide.js file there from a <script> tag. See the following section on serving pyodide files for more details.

The pyodide.js file has a single Promise object which bootstraps the Python environment: languagePluginLoader. Since this must happen asynchronously, it is a Promise, which you must call then on to complete initialization. When the promise resolves, pyodide will have installed a namespace in global scope: pyodide.

languagePluginLoader.then(() => {
  // pyodide is now ready to use...
  console.log(pyodide.runPython('import sys\nsys.version'));
});

Running Python code

Python code is run using the pyodide.runPython function. It takes as input a string of Python code. If the code ends in an expression, it returns the result of the expression, converted to Javascript objects (see {ref}type_conversions).

pyodide.runPython(`
import sys
sys.version
`);

Complete example

Create and save a test index.html page with the following contents:

<!DOCTYPE html>
<html>
  <head>
      <script type="text/javascript">
          // set the pyodide files URL (packages.json, pyodide.asm.data etc)
          window.languagePluginUrl = 'https://pyodide-cdn2.iodide.io/v0.15.0/full/';
      </script>
      <script src="https://pyodide-cdn2.iodide.io/v0.15.0/full/pyodide.js"></script>
  </head>
  <body>
    Pyodide test page <br>
    Open your browser console to see pyodide output
    <script type="text/javascript">
          languagePluginLoader.then(function () {
              console.log(pyodide.runPython(`
                  import sys
                  sys.version
              `));
              console.log(pyodide.runPython('print(1 + 2)'));
          });
    </script>
  </body>
</html>

Loading packages

Only the Python standard library and six are available after importing Pyodide. To use other libraries, you'll need to load their package using pyodide.loadPackage. This downloads the file data over the network (as a .data and .js index file) and installs the files in the virtual filesystem.

Packages can be loaded by name, for those included in the official pyodide repository (e.g. pyodide.loadPackage('numpy')). It is also possible to load packages from custom URLs (e.g. pyodide.loadPackage('https://foo/bar/numpy.js')), in which case the URL must end with <package-name>.js.

When you request a package from the official repository, all of that package's dependencies are also loaded. Dependency resolution is not yet implemented when loading packages from custom URLs.

Multiple packages can also be loaded in a single call,

pyodide.loadPackage(['cycler', 'pytz'])

pyodide.loadPackage returns a Promise.

pyodide.loadPackage('matplotlib').then(() => {
  // matplotlib is now available
});

Alternative way to load packages and run Python code

Alternatively you can run Python code without manually pre-loading packages. You can do this with {ref}pyodide.runPythonAsync <api_pyodide_runPythonAsync>) function, which will automatically download all packages that the code snippet imports.

Note: although the function is called Async, it still blocks the main thread. To run Python code asynchronously see {ref}using_from_webworker.

Alternative Example

<!DOCTYPE html>
<html>
<head>
    <script type="text/javascript">
        window.languagePluginUrl = 'https://pyodide-cdn2.iodide.io/v0.15.0/full/';
    </script>
    <script src="https://pyodide-cdn2.iodide.io/v0.15.0/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>
  <input id='code' value='sum([1, 2, 3, 4, 5])'>
  <button onclick='evaluatePython()'>Run</button>
  <br>
  <br>
  <div>
    Output:
  </div>
  <textarea id='output' style='width: 100%;' rows='6' disabled></textarea>

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

    function addToOutput(s) {
      output.value += '>>>' + code.value + '\n' + s + '\n';
    }

    output.value = 'Initializing...\n';
    // init pyodide
    languagePluginLoader.then(() => { output.value += 'Ready!\n'; });

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

</html>

Accessing Python scope from JavaScript

You can also access from JavaScript all functions and variables defined in Python using the {ref}pyodide.globals <api_pyodide_globals>) object.

For example, if you initialize the variable x = numpy.ones([3,3]) in Python, you can access it from JavaScript in your browser's developer console as follows: pyodide.globals.x. The same goes for functions and imports. See {ref}type_conversions for more details.

You can try it yourself in the browser console:

pyodide.globals.x
// >>> [Float64Array(3), Float64Array(3), Float64Array(3)]

// create the same 3x3 ndarray from js
let x = pyodide.globals.numpy.ones(new Int32Array([3, 3]))
// x >>> [Float64Array(3), Float64Array(3), Float64Array(3)]

Since you have full scope access, you can also re-assign new values or even JavaScript functions to variables, and create new ones from JavaScript:

// re-assign a new value to an existing variable
pyodide.globals.x = 'x will be now string'

// create a new js function that will be available from Python
// this will show a browser alert if the function is called from Python
pyodide.globals.alert = msg => alert(msg)

// this new function will also be available in Python and will return the squared value.
pyodide.globals.squer = x => x*x

Feel free to play around with the code using the browser console and the above example.

Accessing JavaScript scope from Python

The JavaScript scope can be accessed from Python using the js module (see {ref}type_conversions_using_js_obj_from_py). This module represents the gloabal object window that allows us to directly manipulate the DOM and access global variables and functions from Python.

import js

div = js.document.createElement("div")
div.innerHTML = "<h1>This element was created from Python</h1>"
js.document.body.prepend(div)

See {ref}serving_pyodide_packages to distribute pyodide files locally.