2018-06-21 15:19:34 +00:00
|
|
|
# Type conversions
|
|
|
|
|
|
|
|
Python to Javascript conversions occur:
|
|
|
|
|
|
|
|
- when returning the final expression from a `pyodide.runPython` call (evaluating a Python cell in Iodide)
|
|
|
|
- using `pyodide.pyimport`
|
|
|
|
- passing arguments to a Javascript function from Python
|
|
|
|
|
|
|
|
Javascript to Python conversions occur:
|
|
|
|
|
|
|
|
- when using the `from js import ...` syntax
|
|
|
|
- returning the result of a Javascript function to Python
|
|
|
|
|
|
|
|
## Basic types
|
|
|
|
|
|
|
|
The following basic types are implicitly converted between Javascript and
|
|
|
|
Python. The values are copied and any connection to the original object is lost.
|
|
|
|
|
2018-06-22 15:49:32 +00:00
|
|
|
| Python | Javascript |
|
|
|
|
|-----------------|---------------------|
|
|
|
|
| `int`, `float` | `Number` |
|
|
|
|
| `str` | `String` |
|
|
|
|
| `True` | `true` |
|
|
|
|
| `False` | `false` |
|
|
|
|
| `None` | `undefined`, `null` |
|
|
|
|
| `list`, `tuple` | `Array` |
|
|
|
|
| `dict` | `Object` |
|
2018-06-21 15:19:34 +00:00
|
|
|
|
|
|
|
Additionally, Python `bytes` and `buffer` objects are converted to/from Javascript
|
|
|
|
`Uint8ClampedArray` typed arrays. In this case, however, the underlying data is
|
|
|
|
not copied, and is shared between the Python and Javascript sides. This makes
|
|
|
|
passing raw memory between the languages (which in practice can be quite large)
|
|
|
|
very efficient.
|
|
|
|
|
|
|
|
Aside: This is the technology on which matplotlib images are passed to
|
|
|
|
Javascript to render in a canvas, and will be the basis of sharing Numpy arrays
|
|
|
|
with n-dimensional array data structures in Javascript.
|
|
|
|
|
|
|
|
## Class instances
|
|
|
|
|
|
|
|
Any of the types not listed above are shared between languages using proxies
|
|
|
|
that allow methods and some operators to be called on the object from the other
|
|
|
|
language.
|
|
|
|
|
|
|
|
|
2018-06-22 15:49:32 +00:00
|
|
|
When passing a Javascript object to Python, an extension type is used to
|
2018-06-21 15:19:34 +00:00
|
|
|
delegate Python operations to the Javascript side. The following operations are
|
|
|
|
currently supported. (More should be possible in the future -- work in ongoing
|
|
|
|
to make this more complete):
|
|
|
|
|
2018-06-22 15:49:32 +00:00
|
|
|
| Python | Javascript |
|
|
|
|
|----------------|----------------|
|
|
|
|
| `repr(x)` | `x.toString()` |
|
|
|
|
| `x.foo` | `x.foo` |
|
|
|
|
| `x.foo = bar` | `x.foo = bar` |
|
|
|
|
| `x(...)` | `x(...)` |
|
|
|
|
| `x.foo(...)` | `x.foo(...)` |
|
|
|
|
| `X.new(...)` | `new X(...)` |
|
|
|
|
| `len(x)` | `x.length` |
|
|
|
|
| `x[foo]` | `x[foo]` |
|
|
|
|
| `x[foo] = bar` | `x[foo] = bar` |
|
2018-06-21 15:19:34 +00:00
|
|
|
|
|
|
|
When passing a Python object to Javascript, the Javascript [Proxy
|
|
|
|
API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)
|
|
|
|
is used to delegate Javascript operations to the Python side. In general, the
|
|
|
|
Proxy API is more limited than what can be done with a Python extension, so
|
|
|
|
there are certain operations that are impossible or more cumbersome when using
|
|
|
|
Python from Javascript than vice versa. The most notable limitation is that
|
2018-06-22 15:49:32 +00:00
|
|
|
while Python has distinct ways of accessing attributes and items (`x.foo` and
|
2018-06-21 15:19:34 +00:00
|
|
|
`x[foo]`), Javascript conflates these two concepts. The following operations are
|
|
|
|
currently supported:
|
|
|
|
|
2018-06-22 15:49:32 +00:00
|
|
|
| Javascript | Python |
|
|
|
|
|----------------|--------------------------|
|
|
|
|
| `foo in x` | `hasattr(x, 'foo')` |
|
|
|
|
| `x.foo` | `getattr(x, 'foo')` |
|
|
|
|
| `x.foo = bar` | `setattr(x, 'foo', bar)` |
|
|
|
|
| `delete x.foo` | `delattr(x, 'foo')` |
|
|
|
|
| `x.ownKeys()` | `dir(x)` |
|
|
|
|
| `x(...)` | `x(...)` |
|
|
|
|
| `x.foo(...)` | `x.foo(...)` |
|
2018-06-21 15:19:34 +00:00
|
|
|
|
|
|
|
An additional limitation is that when passing a Python object to Javascript,
|
|
|
|
there is no way for Javascript to automatically garbage collect that object.
|
|
|
|
Therefore, Python objects must be manually free'd when passed to Javascript, or
|
|
|
|
they will leak. (TODO: There isn't currently a way to do this, but it will be
|
|
|
|
implemented soon).
|
|
|
|
|
2018-06-22 15:49:32 +00:00
|
|
|
## Using Python objects from Javascript
|
2018-06-21 15:19:34 +00:00
|
|
|
|
|
|
|
A Python object (in global scope) can be brought over to Javascript using the
|
|
|
|
`pyodide.pyimport` function. It takes a string giving the name of the variable,
|
|
|
|
and returns the object, converted to Javascript (See [type
|
|
|
|
conversions](type_conversions.md)).
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
var sys = pyodide.pyimport('sys');
|
|
|
|
```
|
|
|
|
|
2018-06-22 15:49:32 +00:00
|
|
|
## Using Javascript objects from Python
|
2018-06-21 15:19:34 +00:00
|
|
|
|
|
|
|
Javascript objects can be accessed from Python using the `from js import ...`
|
|
|
|
syntax. The object must be in the global (`window`) namespace.
|
|
|
|
|
|
|
|
```python
|
|
|
|
from js import document
|
|
|
|
document.title = 'New window title'
|
|
|
|
```
|