mirror of https://github.com/pyodide/pyodide.git
Add destroy method to remove references to Python objects
This commit is contained in:
parent
e2e8b29739
commit
a4154d9669
|
@ -82,9 +82,16 @@ currently supported:
|
|||
|
||||
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).
|
||||
Therefore, custom Python objects must be manually destroyed when passed to Javascript, or
|
||||
they will leak. To do this, call `.destroy()` on the object, after which Javascript will no longer have access to the object.
|
||||
|
||||
```javascript
|
||||
var foo = pyodide.pyimport('foo');
|
||||
foo.call_method();
|
||||
foo.destroy();
|
||||
foo.call_method(); // This will raise an exception, since the object has been
|
||||
// destroyed
|
||||
```
|
||||
|
||||
## Using Python objects from Javascript
|
||||
|
||||
|
|
|
@ -116,6 +116,13 @@ _pyproxy_apply(int ptrobj, int idargs)
|
|||
return idresult;
|
||||
}
|
||||
|
||||
void
|
||||
_pyproxy_destroy(int ptrobj)
|
||||
{
|
||||
PyObject* pyobj = (PyObject*)ptrobj;
|
||||
Py_DECREF(ptrobj);
|
||||
}
|
||||
|
||||
EM_JS(int, pyproxy_new, (int ptrobj), {
|
||||
var target = function(){};
|
||||
target['$$'] = { ptr : ptrobj, type : 'PyProxy' };
|
||||
|
@ -126,7 +133,11 @@ EM_JS(int, pyproxy_init, (), {
|
|||
// clang-format off
|
||||
Module.PyProxy = {
|
||||
getPtr: function(jsobj) {
|
||||
return jsobj['$$']['ptr'];
|
||||
var ptr = jsobj['$$']['ptr'];
|
||||
if (ptr === null) {
|
||||
throw new Error("Object has already been destroyed");
|
||||
}
|
||||
return ptr;
|
||||
},
|
||||
isPyProxy: function(jsobj) {
|
||||
return jsobj['$$'] !== undefined && jsobj['$$']['type'] === 'PyProxy';
|
||||
|
@ -149,6 +160,9 @@ EM_JS(int, pyproxy_init, (), {
|
|||
}
|
||||
} else if (jskey === '$$') {
|
||||
return jsobj['$$'];
|
||||
} else if (jskey === 'destroy') {
|
||||
__pyproxy_destroy(this.getPtr(jsobj));
|
||||
jsobj['$$']['ptr'] = null;
|
||||
}
|
||||
ptrobj = this.getPtr(jsobj);
|
||||
var idkey = Module.hiwire_new_value(jskey);
|
||||
|
|
|
@ -52,6 +52,8 @@ def test_pythonexc2js(selenium):
|
|||
selenium.run_js('return pyodide.runPython("5 / 0")')
|
||||
except JavascriptException as e:
|
||||
assert('ZeroDivisionError' in str(e))
|
||||
else:
|
||||
assert False, 'Expected exception'
|
||||
|
||||
|
||||
def test_js2python(selenium):
|
||||
|
@ -131,6 +133,26 @@ def test_pyproxy(selenium):
|
|||
"return pyodide.pyimport('f').toString()").startswith('<Foo')
|
||||
|
||||
|
||||
def test_pyproxy_destroy(selenium):
|
||||
selenium.run(
|
||||
"class Foo:\n"
|
||||
" bar = 42\n"
|
||||
" def get_value(self, value):\n"
|
||||
" return value * 64\n"
|
||||
"f = Foo()\n"
|
||||
)
|
||||
try:
|
||||
selenium.run_js(
|
||||
"let f = pyodide.pyimport('f');\n"
|
||||
"console.assert(f.get_value(1) === 64);\n"
|
||||
"f.destroy();\n"
|
||||
"f.get_value();\n")
|
||||
except JavascriptException as e:
|
||||
assert 'f.get_value is not a function' in str(e)
|
||||
else:
|
||||
assert False, 'Expected exception'
|
||||
|
||||
|
||||
def test_jsproxy(selenium):
|
||||
assert selenium.run(
|
||||
"from js import document\n"
|
||||
|
|
Loading…
Reference in New Issue