Content-Length: 386527 | pFad | http://github.com/micropython/micropython/commit/95c19e05ffd204f8f375b6e04e4ae45770ec0dbc

E0 webassembly/objjsproxy: Lookup attributes without testing they exist. · micropython/micropython@95c19e0 · GitHub
Skip to content

Commit 95c19e0

Browse files
committed
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>
1 parent 5dff78f commit 95c19e0

File tree

3 files changed

+51
-2
lines changed

3 files changed

+51
-2
lines changed

Diff for: ports/webassembly/objjsproxy.c

+8-2
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,14 @@ EM_JS(bool, has_attr, (int jsref, const char *str), {
4646
EM_JS(bool, lookup_attr, (int jsref, const char *str, uint32_t * out), {
4747
const base = proxy_js_ref[jsref];
4848
const attr = UTF8ToString(str);
49-
if (attr in base) {
50-
let value = base[attr];
49+
50+
// Attempt to lookup the requested attribute from the base object:
51+
// - If the value is not `undefined` then the attribute exists with that value.
52+
// - Otherwise if the value is `undefined` and the `in` operator returns true, then
53+
// that attribute does exist and is intended to have a value of `undefined`.
54+
// - Otherwise, the attribute does not exist.
55+
let value = base[attr];
56+
if (value !== undefined || attr in base) {
5157
if (typeof value === "function") {
5258
if (base !== globalThis) {
5359
if ("_ref" in value) {

Diff for: tests/ports/webassembly/js_proxy_attribute.mjs

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Test lookup of attributes on JsProxy objects.
2+
3+
const mp = await (await import(process.argv[2])).loadMicroPython();
4+
5+
// Simple attribute names and values.
6+
globalThis.obj1 = { a: 1, b: 2 };
7+
8+
// Unconventional attribute names and values.
9+
globalThis.obj2 = { undefined: "undefined", undef: undefined };
10+
11+
// Dynamically created attribute names and values.
12+
globalThis.obj3 = new Proxy(new Map(), {
13+
get(map, name) {
14+
if (!map.has(name)) {
15+
console.log("creating attribute", name);
16+
map.set(name, name);
17+
}
18+
return map.get(name);
19+
},
20+
});
21+
22+
mp.runPython(`
23+
import js
24+
25+
print(js.obj1.a, js.obj1.b)
26+
print(js.obj1["a"], js.obj1["b"])
27+
28+
print(js.obj2.undefined, js.obj2.undef)
29+
30+
print(js.obj3.c)
31+
print(js.obj3["c"])
32+
print(hasattr(js.obj3, "d"))
33+
print(js.obj3.d)
34+
`);

Diff for: tests/ports/webassembly/js_proxy_attribute.mjs.exp

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
1 2
2+
1 2
3+
undefined <undefined>
4+
creating attribute c
5+
c
6+
c
7+
creating attribute d
8+
True
9+
d

0 commit comments

Comments
 (0)








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/micropython/micropython/commit/95c19e05ffd204f8f375b6e04e4ae45770ec0dbc

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy