From dfbe045895e0082bc18ef1e12511cc79885dba49 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 22 Apr 2019 14:10:09 -0400 Subject: [PATCH] Fix #382: Proxies should return the same object (#394) --- src/pyproxy.c | 20 +++++++++++++++++++- test/test_python.py | 8 ++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/pyproxy.c b/src/pyproxy.c index 3db4b045b..0601f38ed 100644 --- a/src/pyproxy.c +++ b/src/pyproxy.c @@ -121,16 +121,34 @@ _pyproxy_destroy(int ptrobj) { PyObject* pyobj = (PyObject*)ptrobj; Py_DECREF(ptrobj); + EM_ASM(delete Module.PyProxies[ptrobj];); } EM_JS(int, pyproxy_new, (int ptrobj), { + // Proxies we've already created are just returned again, so that the + // same object on the Python side is always the same object on the + // Javascript side. + + // Technically, this leaks memory, since we're holding on to a reference + // to the proxy forever. But we have that problem anyway since we don't + // have a destructor in Javascript to free the Python object. + // _pyproxy_destroy, which is a way for users to manually delete the proxy, + // also deletes the proxy from this set. + if (Module.PyProxies.hasOwnProperty(ptrobj)) { + return Module.hiwire_new_value(Module.PyProxies[ptrobj]); + } + var target = function(){}; target['$$'] = { ptr : ptrobj, type : 'PyProxy' }; - return Module.hiwire_new_value(new Proxy(target, Module.PyProxy)); + var proxy = new Proxy(target, Module.PyProxy); + Module.PyProxies[ptrobj] = proxy; + + return Module.hiwire_new_value(proxy); }); EM_JS(int, pyproxy_init, (), { // clang-format off + Module.PyProxies = {}; Module.PyProxy = { getPtr: function(jsobj) { var ptr = jsobj['$$']['ptr']; diff --git a/test/test_python.py b/test/test_python.py index cf44484dc..a0df59a4c 100644 --- a/test/test_python.py +++ b/test/test_python.py @@ -317,6 +317,14 @@ def test_pyimport_multiple(selenium): selenium.run_js("pyodide.pyimport('v')") +def test_pyimport_same(selenium): + """See #382""" + selenium.run("def func(): return 42") + assert selenium.run_js( + "return pyodide.pyimport('func') == pyodide.pyimport('func')" + ) + + def test_pyproxy(selenium): selenium.run( """