From f50144ab512d1fad959dc0431fe2652b45c17c9c Mon Sep 17 00:00:00 2001 From: Hood Chatham Date: Tue, 4 Jun 2024 09:44:37 -0700 Subject: [PATCH] FIX Check if future is done before trying to set a result on it Otherwise, future raises invalid state error. Question: should we try to avoid getting to the point where we call this in the first place?? --- src/core/jsproxy.c | 8 ++++++-- src/py/_pyodide/_future_helper.py | 13 +++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 src/py/_pyodide/_future_helper.py diff --git a/src/core/jsproxy.c b/src/core/jsproxy.c index a57af6e56281..0e075d45fb01 100644 --- a/src/core/jsproxy.c +++ b/src/core/jsproxy.c @@ -2637,6 +2637,7 @@ wrap_promise(JsVal promise, JsVal done_callback, PyObject* js2py_converter) { bool success = false; PyObject* loop = NULL; + PyObject* helpers = NULL; PyObject* set_result = NULL; PyObject* set_exception = NULL; @@ -2648,9 +2649,11 @@ wrap_promise(JsVal promise, JsVal done_callback, PyObject* js2py_converter) result = _PyObject_CallMethodIdNoArgs(loop, &PyId_create_future); FAIL_IF_NULL(result); - set_result = _PyObject_GetAttrId(result, &PyId_set_result); + helpers = PyImport_ImportModule("_pyodide._future_helpers"); + FAIL_IF_NULL(helpers); + set_result = Py_XNewRef(PyTuple_GetItem(helpers, 0)); FAIL_IF_NULL(set_result); - set_exception = _PyObject_GetAttrId(result, &PyId_set_exception); + set_exception = Py_XNewRef(PyTuple_GetItem(helpers, 1)); FAIL_IF_NULL(set_exception); promise = JsvPromise_Resolve(promise); @@ -2663,6 +2666,7 @@ wrap_promise(JsVal promise, JsVal done_callback, PyObject* js2py_converter) success = true; finally: Py_CLEAR(loop); + Py_CLEAR(helpers); Py_CLEAR(set_result); Py_CLEAR(set_exception); if (!success) { diff --git a/src/py/_pyodide/_future_helper.py b/src/py/_pyodide/_future_helper.py new file mode 100644 index 000000000000..3d82300f3622 --- /dev/null +++ b/src/py/_pyodide/_future_helper.py @@ -0,0 +1,13 @@ +def set_result(fut, val): + if fut.done(): + return + fut.set_result(val) + +def set_exception(fut, val): + if fut.done(): + return + fut.set_result(val) + + +def get_future_resolvers(fut): + return (set_result.__get__(fut), set_exception.__get__(fut))