pyodide/docs/using_pyodide_from_javascri...

201 lines
6.8 KiB
Markdown
Raw Normal View History

(using_from_javascript)=
2018-06-21 15:19:34 +00:00
# Using Pyodide from Javascript
This document describes using Pyodide directly from Javascript. For information about using Pyodide from Iodide, see {ref}`using_from_iodide`.
2018-06-21 15:19:34 +00:00
## Startup
To include Pyodide in your project you can use the following CDN URL,
2018-06-21 15:19:34 +00:00
2020-05-20 19:11:50 +00:00
https://pyodide-cdn2.iodide.io/v0.15.0/full/pyodide.js
2019-05-31 20:02:51 +00:00
You can also download a release from
[Github releases](https://github.com/iodide-project/pyodide/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](#serving-pyodide-files) for more details.
2019-05-31 20:02:51 +00:00
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:
2018-06-21 15:19:34 +00:00
`pyodide`.
```javascript
2018-11-08 13:25:33 +00:00
languagePluginLoader.then(() => {
2018-06-21 15:19:34 +00:00
// 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`).
2018-06-21 15:19:34 +00:00
```javascript
2020-07-13 19:46:20 +00:00
pyodide.runPython(`
import sys
sys.version
`);
2018-06-21 15:19:34 +00:00
```
## Complete example
Create and save a test `index.html` page with the following contents:
```html
<!DOCTYPE html>
<html>
2020-07-13 19:46:20 +00:00
<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">
2020-07-13 19:46:20 +00:00
languagePluginLoader.then(function () {
console.log(pyodide.runPython(`
import sys
sys.version
`));
console.log(pyodide.runPython('print(1 + 2)'));
});
</script>
2020-07-13 19:46:20 +00:00
</body>
</html>
```
2018-06-21 15:19:34 +00:00
## 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.
2018-06-21 15:19:34 +00:00
2018-09-05 09:28:20 +00:00
Multiple packages can also be loaded in a single call,
```js
pyodide.loadPackage(['cycler', 'pytz'])
```
2018-06-21 15:19:34 +00:00
`pyodide.loadPackage` returns a `Promise`.
```javascript
pyodide.loadPackage('matplotlib').then(() => {
// matplotlib is now available
2018-06-21 15:19:34 +00:00
});
```
## 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
```html
<!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:
```js
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:
```js
// 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.
```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.