Skip to content

Commit

Permalink
Merge pull request #382 from Distributive-Network/philippe/379-fix
Browse files Browse the repository at this point in the history
Properly print/repr Promises/Futures and structural cycles at the JS level
  • Loading branch information
philippedistributive authored Jul 16, 2024
2 parents 63be1bb + 5db54b2 commit d0f237f
Showing 1 changed file with 31 additions and 12 deletions.
43 changes: 31 additions & 12 deletions src/JSObjectProxy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -338,15 +338,23 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_iter_next(JSObjectProxy
}

PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_repr(JSObjectProxy *self) {
Py_ssize_t i = Py_ReprEnter((PyObject *)self);
// Detect cyclic objects
PyObject *objPtr = PyLong_FromVoidPtr(self->jsObject->get());
// For `Py_ReprEnter`, we must get a same PyObject when visiting the same JSObject.
// We cannot simply use the object returned by `PyLong_FromVoidPtr` because it won't reuse the PyLongObjects for ints not between -5 and 256.
// Instead, we store this PyLongObject in a global dict, using itself as the hashable key, effectively interning the PyLongObject.
PyObject *tsDict = PyThreadState_GetDict();
PyObject *cyclicKey = PyDict_SetDefault(tsDict, /*key*/ objPtr, /*value*/ objPtr); // cyclicKey = (tsDict[objPtr] ??= objPtr)
int i = Py_ReprEnter(cyclicKey);
if (i != 0) {
return i > 0 ? PyUnicode_FromString("{...}") : NULL;
}

Py_ssize_t selfLength = JSObjectProxy_length(self);

if (selfLength == 0) {
Py_ReprLeave((PyObject *)self);
Py_ReprLeave(cyclicKey);
PyDict_DelItem(tsDict, cyclicKey);
return PyUnicode_FromString("{}");
}

Expand Down Expand Up @@ -417,15 +425,24 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_repr(JSObjectProxy *self
value = pyTypeFactory(GLOBAL_CX, elementVal);
}

s = PyObject_Repr(value);
if (s == NULL) {
goto error;
}
if (value != NULL) {
s = PyObject_Repr(value);
if (s == NULL) {
goto error;
}

res = _PyUnicodeWriter_WriteStr(&writer, s);
Py_DECREF(s);
if (res < 0) {
goto error;
res = _PyUnicodeWriter_WriteStr(&writer, s);
Py_DECREF(s);
if (res < 0) {
goto error;
}
} else {
// clear any exception that was just set
PyErr_Clear();

if (_PyUnicodeWriter_WriteASCIIString(&writer, "<cannot repr type>", 19) < 0) {
goto error;
}
}

Py_CLEAR(key);
Expand All @@ -437,11 +454,13 @@ PyObject *JSObjectProxyMethodDefinitions::JSObjectProxy_repr(JSObjectProxy *self
goto error;
}

Py_ReprLeave((PyObject *)self);
Py_ReprLeave(cyclicKey);
PyDict_DelItem(tsDict, cyclicKey);
return _PyUnicodeWriter_Finish(&writer);

error:
Py_ReprLeave((PyObject *)self);
Py_ReprLeave(cyclicKey);
PyDict_DelItem(tsDict, cyclicKey);
_PyUnicodeWriter_Dealloc(&writer);
Py_XDECREF(key);
Py_XDECREF(value);
Expand Down

0 comments on commit d0f237f

Please sign in to comment.