FIX Fix feature detection when `obj.constructor` is undefined (#2520)

Currently the following code fails:
```py
from js import eval
eval("Object.create(null)")
```
with:
```py
Traceback (most recent call last):
  File "<console>", line 1, in <module>
JsException: TypeError: Cannot read properties of undefined (reading 'name')
```
This fixes it.
This commit is contained in:
Hood Chatham 2022-05-18 22:19:37 -07:00 committed by GitHub
parent 35db93ea06
commit 7fc1c2da8e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 26 additions and 2 deletions

View File

@ -210,6 +210,7 @@ dist/test.tar: $(CPYTHONLIB) node_modules/.installed
for testname in $(TEST_EXTENSIONS); do \
cd $(CPYTHONBUILD) && \
emcc Modules/$${testname%.*}.o -o $$testname $(SIDE_MODULE_LDFLAGS) && \
rm -f $(CPYTHONLIB)/$$testname && \
ln -s $(CPYTHONBUILD)/$$testname $(CPYTHONLIB)/$$testname ; \
done

View File

@ -61,6 +61,9 @@ substitutions:
translated to negative Python ints.
{pr}`2484`
- {{ Fix }} Pyodide now correctly handles JavaScript objects with `null` constructor.
{pr}`2520`
- {{ Fix }} Fix garbage collection of `once_callable` {pr}`2401`
- {{ Enhancement }} `run_in_pyodide` now has support for pytest assertion

View File

@ -194,6 +194,9 @@ function convertCppException(ptr: number): CppException {
Tests.convertCppException = convertCppException;
function isPyodideFrame(frame: ErrorStackParser.StackFrame): boolean {
if (!frame) {
return false;
}
const fileName = frame.fileName || "";
if (fileName.includes("wasm-function")) {
return true;

View File

@ -712,7 +712,7 @@ EM_JS_REF(JsRef, hiwire_to_string, (JsRef idobj), {
return Hiwire.new_value(Hiwire.get_value(idobj).toString());
});
EM_JS_REF(JsRef, hiwire_typeof, (JsRef idobj), {
EM_JS(JsRef, hiwire_typeof, (JsRef idobj), {
return Hiwire.new_value(typeof Hiwire.get_value(idobj));
});
@ -781,7 +781,7 @@ EM_JS_REF(JsRef, JsObject_Values, (JsRef idobj), {
EM_JS(bool, hiwire_is_typedarray, (JsRef idobj), {
let jsobj = Hiwire.get_value(idobj);
// clang-format off
return ArrayBuffer.isView(jsobj) || jsobj.constructor.name === "ArrayBuffer";
return ArrayBuffer.isView(jsobj) || (jsobj.constructor && jsobj.constructor.name === "ArrayBuffer");
// clang-format on
});

View File

@ -119,6 +119,12 @@ static PyObject*
JsProxy_Repr(PyObject* self)
{
JsRef idrepr = hiwire_to_string(JsProxy_REF(self));
if (idrepr == NULL) {
PyErr_Format(PyExc_TypeError,
"Pyodide cannot generate a repr for this Javascript object "
"because it has no 'toString' method");
return NULL;
}
PyObject* pyrepr = js2python(idrepr);
hiwire_decref(idrepr);
return pyrepr;

View File

@ -1425,6 +1425,17 @@ def test_buffer_format_string(selenium):
assert array_name == expected_array_name
@run_in_pyodide
def test_object_with_null_constructor():
from unittest import TestCase
from js import eval as run_js
o = run_js("Object.create(null)")
with TestCase().assertRaises(TypeError):
repr(o)
def test_dict_converter_cache(selenium):
selenium.run_js(
"""