Skip to content

Commit e2ca8ab

Browse files
laurensvalkdpgeorge
authored andcommitted
py/runtime: Allow types to use both .attr and .locals_dict.
Make it possible to proceed to a regular lookup in locals_dict if the custom type->attr fails. This allows type->attr to extend rather than completely replace the lookup in locals_dict. This is useful for custom builtin classes that have mostly regular methods but just a few special attributes/properties. This way, type->attr needs to deal with the special cases only and the default lookup will be used for generic methods. Signed-off-by: Laurens Valk <[email protected]>
1 parent 01ceb9a commit e2ca8ab

2 files changed

Lines changed: 14 additions & 4 deletions

File tree

‎py/obj.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,7 @@ struct _mp_obj_type_t {
551551
//
552552
// dest[0] = MP_OBJ_NULL means load
553553
// return: for fail, do nothing
554+
// for fail but continue lookup in locals_dict, dest[1] = MP_OBJ_SENTINEL
554555
// for attr, dest[0] = value
555556
// for method, dest[0] = method, dest[1] = self
556557
//

‎py/runtime.c‎

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,12 +1100,20 @@ void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) {
11001100
if (attr == MP_QSTR___next__ && type->iternext != NULL) {
11011101
dest[0] = MP_OBJ_FROM_PTR(&mp_builtin_next_obj);
11021102
dest[1] = obj;
1103-
1104-
} else if (type->attr != NULL) {
1103+
return;
1104+
}
1105+
if (type->attr != NULL) {
11051106
// this type can do its own load, so call it
11061107
type->attr(obj, attr, dest);
1107-
1108-
} else if (type->locals_dict != NULL) {
1108+
// If type->attr has set dest[1] = MP_OBJ_SENTINEL, we should proceed
1109+
// with lookups below (i.e. in locals_dict). If not, return right away.
1110+
if (dest[1] != MP_OBJ_SENTINEL) {
1111+
return;
1112+
}
1113+
// Clear the fail flag set by type->attr so it's like it never ran.
1114+
dest[1] = MP_OBJ_NULL;
1115+
}
1116+
if (type->locals_dict != NULL) {
11091117
// generic method lookup
11101118
// this is a lookup in the object (ie not class or type)
11111119
assert(type->locals_dict->base.type == &mp_type_dict); // MicroPython restriction, for now
@@ -1114,6 +1122,7 @@ void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) {
11141122
if (elem != NULL) {
11151123
mp_convert_member_lookup(obj, type, elem->value, dest);
11161124
}
1125+
return;
11171126
}
11181127
}
11191128

0 commit comments

Comments
 (0)