diff --git a/src/hiwire.c b/src/hiwire.c index 14a0c9e62..277c109f2 100644 --- a/src/hiwire.c +++ b/src/hiwire.c @@ -249,16 +249,32 @@ MAKE_OPERATOR(greater_than, >); MAKE_OPERATOR(greater_than_equal, >=); EM_JS(int, hiwire_next, (int idobj), { - var jsobj = Module.hiwire_get_value(idobj); // clang-format off - if (jsobj.next === undefined) { + if (idobj === -2) { // clang-format on - return HW_ERROR; + return -1; } + var jsobj = Module.hiwire_get_value(idobj); return Module.hiwire_new_value(jsobj.next()); }); +EM_JS(int, hiwire_get_iterator, (int idobj), { + // clang-format off + if (idobj === -2) { + return -1; + } + + var jsobj = Module.hiwire_get_value(idobj); + if (typeof jsobj.next === 'function') { + return Module.hiwire_new_value(jsobj); + } else if (typeof jsobj[Symbol.iterator] === 'function') { + return Module.hiwire_new_value(jsobj[Symbol.iterator]()) + } + return -1; + // clang-format on +}) + EM_JS(int, hiwire_nonzero, (int idobj), { var jsobj = Module.hiwire_get_value(idobj); return (jsobj != 0) ? 1 : 0; diff --git a/src/hiwire.h b/src/hiwire.h index 158adf184..5b9cf013d 100644 --- a/src/hiwire.h +++ b/src/hiwire.h @@ -366,6 +366,12 @@ hiwire_greater_than_equal(int ida, int idb); int hiwire_next(int idobj); +/** + * Returns the iterator associated with the given object, if any. + */ +int +hiwire_get_iterator(int idobj); + /** * Returns 1 if the value is non-zero. * diff --git a/src/jsproxy.c b/src/jsproxy.c index 571bec0fa..70def0bea 100644 --- a/src/jsproxy.c +++ b/src/jsproxy.c @@ -169,8 +169,16 @@ JsProxy_RichCompare(PyObject* a, PyObject* b, int op) static PyObject* JsProxy_GetIter(PyObject* o) { - Py_INCREF(o); - return o; + JsProxy* self = (JsProxy*)o; + + int iditer = hiwire_get_iterator(self->js); + + if (iditer == HW_ERROR) { + PyErr_SetString(PyExc_TypeError, "Object is not iterable"); + return NULL; + } + + return js2python(iditer); } static PyObject* @@ -375,6 +383,10 @@ static PyMethodDef JsProxy_Methods[] = { (PyCFunction)JsProxy_New, METH_VARARGS | METH_KEYWORDS, "Construct a new instance" }, + { "__iter__", + (PyCFunction)JsProxy_GetIter, + METH_NOARGS, + "Get an iterator over the object" }, { "_has_bytes", (PyCFunction)JsProxy_HasBytes, METH_NOARGS, diff --git a/test/test_python.py b/test/test_python.py index 83ef16f2c..313430d53 100644 --- a/test/test_python.py +++ b/test/test_python.py @@ -325,8 +325,14 @@ def test_jsproxy_implicit_iter(selenium): """ window.ITER = [1, 2, 3];""") assert selenium.run( - "from js import ITER\n" + "from js import ITER, Object\n" + "list(ITER)") == [1, 2, 3] + assert selenium.run( + "from js import ITER, Object\n" "list(ITER.values())") == [1, 2, 3] + assert selenium.run( + "from js import ITER, Object\n" + "list(Object.values(ITER))") == [1, 2, 3] def test_open_url(selenium):