summaryrefslogtreecommitdiffstatshomepage
path: root/py/objmodule.c
diff options
context:
space:
mode:
authorDamien George <damien@micropython.org>2021-07-27 00:38:21 +1000
committerDamien George <damien@micropython.org>2022-03-10 10:35:44 +1100
commit3356b5ef8d1b232a1df493f70f0ba434f293fe11 (patch)
treeeecb3016d1c1b2c87c4eada76c0f35bbe2d0fa6c /py/objmodule.c
parentd470c5a5baa8660461b76585a57f2de28b30f5dc (diff)
downloadmicropython-3356b5ef8d1b232a1df493f70f0ba434f293fe11.tar.gz
micropython-3356b5ef8d1b232a1df493f70f0ba434f293fe11.zip
py/objmodule: Support delegating failed attr lookups.
This commit adds generic support for mutable module attributes on built in modules, by adding support for an optional hook function for module attribute lookup. If a module wants to support additional attribute load/ store/delete (beyond what is in the constant, globals dict) then it should add at the very end of its globals dict MP_MODULE_ATTR_DELEGATION_ENTRY(). This should point to a custom function which will handle any additional attributes. The mp_module_generic_attr() function is provided as a helper function for additional attributes: it requires an array of qstrs (terminated in MP_QSTRnull) and a corresponding array of objects (with a 1-1 mapping between qstrs and objects). If the qstr is found in the array then the corresponding object is loaded/stored/deleted. Signed-off-by: Damien George <damien@micropython.org>
Diffstat (limited to 'py/objmodule.c')
-rw-r--r--py/objmodule.c36
1 files changed, 36 insertions, 0 deletions
diff --git a/py/objmodule.c b/py/objmodule.c
index f7cd437bac..0cd10e61f0 100644
--- a/py/objmodule.c
+++ b/py/objmodule.c
@@ -62,6 +62,21 @@ STATIC void module_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kin
mp_printf(print, "<module '%s'>", module_name);
}
+STATIC void module_attr_try_delegation(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
+ #if MICROPY_MODULE_ATTR_DELEGATION
+ // Delegate lookup to a module's custom attr method (found in last lot of globals dict).
+ mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_map_t *map = &self->globals->map;
+ if (map->table[map->alloc - 1].key == MP_OBJ_NEW_QSTR(MP_QSTRnull)) {
+ ((mp_attr_fun_t)MP_OBJ_TO_PTR(map->table[map->alloc - 1].value))(self_in, attr, dest);
+ }
+ #else
+ (void)self_in;
+ (void)attr;
+ (void)dest;
+ #endif
+}
+
STATIC void module_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in);
if (dest[0] == MP_OBJ_NULL) {
@@ -74,8 +89,12 @@ STATIC void module_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___getattr__), MP_MAP_LOOKUP);
if (elem != NULL) {
dest[0] = mp_call_function_1(elem->value, MP_OBJ_NEW_QSTR(attr));
+ } else {
+ module_attr_try_delegation(self_in, attr, dest);
}
#endif
+ } else {
+ module_attr_try_delegation(self_in, attr, dest);
}
} else {
// delete/store attribute
@@ -91,6 +110,7 @@ STATIC void module_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
#endif
{
// can't delete or store to fixed map
+ module_attr_try_delegation(self_in, attr, dest);
return;
}
}
@@ -319,3 +339,19 @@ STATIC void mp_module_call_init(mp_obj_t module_name, mp_obj_t module_obj) {
}
}
#endif
+
+void mp_module_generic_attr(qstr attr, mp_obj_t *dest, const uint16_t *keys, mp_obj_t *values) {
+ for (size_t i = 0; keys[i] != MP_QSTRnull; ++i) {
+ if (attr == keys[i]) {
+ if (dest[0] == MP_OBJ_NULL) {
+ // load attribute (MP_OBJ_NULL returned for deleted items)
+ dest[0] = values[i];
+ } else {
+ // delete or store (delete stores MP_OBJ_NULL)
+ values[i] = dest[1];
+ dest[0] = MP_OBJ_NULL; // indicate success
+ }
+ return;
+ }
+ }
+}