mirror of
https://github.com/micropython/micropython.git
synced 2026-01-07 12:40:15 +01:00
webassembly/objjsproxy: Lookup attributes without testing they exist.
In JavaScript when accessing an attribute such as `obj.attr` a value of `undefined` is returned if the attribute does not exist. This is unlike Python semantics where an `AttributeError` is raised. Furthermore, in some cases in JavaScript (eg a Proxy instance) `attr in obj` can return false yet `obj.attr` is still valid and returns something other than `undefined`. So the source of truth for whether a JavaScript attribute exists is to just right away attempt `obj.attr`. To more closely match these JavaScript semantics when proxying a JavaScript object through to Python, change the attribute lookup logic on a `JsProxy` so that it immediately attempts `obj.attr` instead of first testing if the attribute exists via `attr in obj`. This allows JavaScript objects which dynamically create attributes to work correctly on the Python side, with both `obj.attr` and `obj["attr"]`. Note that `obj["attr"]` already works in all cases because it immediately does the subscript access without first testing if the attribute exists. As a benefit, this new behaviour matches the Pyodide behaviour. Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
34
tests/ports/webassembly/js_proxy_attribute.mjs
Normal file
34
tests/ports/webassembly/js_proxy_attribute.mjs
Normal file
@@ -0,0 +1,34 @@
|
||||
// Test lookup of attributes on JsProxy objects.
|
||||
|
||||
const mp = await (await import(process.argv[2])).loadMicroPython();
|
||||
|
||||
// Simple attribute names and values.
|
||||
globalThis.obj1 = { a: 1, b: 2 };
|
||||
|
||||
// Unconventional attribute names and values.
|
||||
globalThis.obj2 = { undefined: "undefined", undef: undefined };
|
||||
|
||||
// Dynamically created attribute names and values.
|
||||
globalThis.obj3 = new Proxy(new Map(), {
|
||||
get(map, name) {
|
||||
if (!map.has(name)) {
|
||||
console.log("creating attribute", name);
|
||||
map.set(name, name);
|
||||
}
|
||||
return map.get(name);
|
||||
},
|
||||
});
|
||||
|
||||
mp.runPython(`
|
||||
import js
|
||||
|
||||
print(js.obj1.a, js.obj1.b)
|
||||
print(js.obj1["a"], js.obj1["b"])
|
||||
|
||||
print(js.obj2.undefined, js.obj2.undef)
|
||||
|
||||
print(js.obj3.c)
|
||||
print(js.obj3["c"])
|
||||
print(hasattr(js.obj3, "d"))
|
||||
print(js.obj3.d)
|
||||
`);
|
||||
9
tests/ports/webassembly/js_proxy_attribute.mjs.exp
Normal file
9
tests/ports/webassembly/js_proxy_attribute.mjs.exp
Normal file
@@ -0,0 +1,9 @@
|
||||
1 2
|
||||
1 2
|
||||
undefined <undefined>
|
||||
creating attribute c
|
||||
c
|
||||
c
|
||||
creating attribute d
|
||||
True
|
||||
d
|
||||
Reference in New Issue
Block a user