mirror of https://github.com/pyodide/pyodide.git
FIX Check if future is done before trying to set a result on it (#4837)
Otherwise, the future raises invalid state error
This commit is contained in:
parent
97eda9d0bf
commit
43cce6e5ff
|
@ -24,9 +24,14 @@ myst:
|
||||||
stack switching is disabled.
|
stack switching is disabled.
|
||||||
{pr}`4817`
|
{pr}`4817`
|
||||||
|
|
||||||
- {{ Fix }} Resolved an issue where string keys in `PyProxyJsonAdaptor` were unexpectedly cast to numbers.
|
- {{ Fix }} Resolved an issue where string keys in `PyProxyJsonAdaptor` were
|
||||||
|
unexpectedly cast to numbers.
|
||||||
{pr}`4825`
|
{pr}`4825`
|
||||||
|
|
||||||
|
- {{ Fix }} When a `Future` connected to a `Promise` is cancelled, don't raise
|
||||||
|
`InvalidStateError`.
|
||||||
|
{pr}`4837`
|
||||||
|
|
||||||
### Packages
|
### Packages
|
||||||
|
|
||||||
- New Packages: `pytest-asyncio` {pr}`4819`
|
- New Packages: `pytest-asyncio` {pr}`4819`
|
||||||
|
|
|
@ -2637,6 +2637,8 @@ wrap_promise(JsVal promise, JsVal done_callback, PyObject* js2py_converter)
|
||||||
{
|
{
|
||||||
bool success = false;
|
bool success = false;
|
||||||
PyObject* loop = NULL;
|
PyObject* loop = NULL;
|
||||||
|
PyObject* helpers_mod = NULL;
|
||||||
|
PyObject* helpers = NULL;
|
||||||
PyObject* set_result = NULL;
|
PyObject* set_result = NULL;
|
||||||
PyObject* set_exception = NULL;
|
PyObject* set_exception = NULL;
|
||||||
|
|
||||||
|
@ -2648,9 +2650,15 @@ wrap_promise(JsVal promise, JsVal done_callback, PyObject* js2py_converter)
|
||||||
result = _PyObject_CallMethodIdNoArgs(loop, &PyId_create_future);
|
result = _PyObject_CallMethodIdNoArgs(loop, &PyId_create_future);
|
||||||
FAIL_IF_NULL(result);
|
FAIL_IF_NULL(result);
|
||||||
|
|
||||||
set_result = _PyObject_GetAttrId(result, &PyId_set_result);
|
helpers_mod = PyImport_ImportModule("_pyodide._future_helper");
|
||||||
|
FAIL_IF_NULL(helpers_mod);
|
||||||
|
_Py_IDENTIFIER(get_future_resolvers);
|
||||||
|
helpers = _PyObject_CallMethodIdOneArg(
|
||||||
|
helpers_mod, &PyId_get_future_resolvers, result);
|
||||||
|
FAIL_IF_NULL(helpers);
|
||||||
|
set_result = Py_XNewRef(PyTuple_GetItem(helpers, 0));
|
||||||
FAIL_IF_NULL(set_result);
|
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);
|
FAIL_IF_NULL(set_exception);
|
||||||
|
|
||||||
promise = JsvPromise_Resolve(promise);
|
promise = JsvPromise_Resolve(promise);
|
||||||
|
@ -2663,6 +2671,8 @@ wrap_promise(JsVal promise, JsVal done_callback, PyObject* js2py_converter)
|
||||||
success = true;
|
success = true;
|
||||||
finally:
|
finally:
|
||||||
Py_CLEAR(loop);
|
Py_CLEAR(loop);
|
||||||
|
Py_CLEAR(helpers_mod);
|
||||||
|
Py_CLEAR(helpers);
|
||||||
Py_CLEAR(set_result);
|
Py_CLEAR(set_result);
|
||||||
Py_CLEAR(set_exception);
|
Py_CLEAR(set_exception);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
def set_result(fut, val):
|
||||||
|
if fut.done():
|
||||||
|
return
|
||||||
|
fut.set_result(val)
|
||||||
|
|
||||||
|
|
||||||
|
def set_exception(fut, val):
|
||||||
|
if fut.done():
|
||||||
|
return
|
||||||
|
fut.set_exception(val)
|
||||||
|
|
||||||
|
|
||||||
|
def get_future_resolvers(fut):
|
||||||
|
return (set_result.__get__(fut), set_exception.__get__(fut))
|
|
@ -2,6 +2,7 @@ import asyncio
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from pytest_pyodide import run_in_pyodide
|
||||||
|
|
||||||
from pyodide.code import eval_code_async
|
from pyodide.code import eval_code_async
|
||||||
|
|
||||||
|
@ -421,3 +422,24 @@ def test_await_pyproxy_async_def(selenium):
|
||||||
return (!!packages.packages) && (!!packages.info);
|
return (!!packages.packages) && (!!packages.info);
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@run_in_pyodide
|
||||||
|
async def inner_test_cancellation(selenium):
|
||||||
|
from asyncio import ensure_future, sleep
|
||||||
|
|
||||||
|
from js import fetch
|
||||||
|
|
||||||
|
async def f():
|
||||||
|
while True:
|
||||||
|
await fetch("/")
|
||||||
|
|
||||||
|
fut = ensure_future(f())
|
||||||
|
await sleep(0.01)
|
||||||
|
fut.cancel()
|
||||||
|
await sleep(0.1)
|
||||||
|
|
||||||
|
|
||||||
|
def test_cancellation(selenium):
|
||||||
|
inner_test_cancellation(selenium)
|
||||||
|
assert "InvalidStateError" not in selenium.logs
|
||||||
|
|
Loading…
Reference in New Issue