@@ -974,6 +974,38 @@ static bool check_for_special_accessors(mp_obj_t key, mp_obj_t value) {
974
974
}
975
975
#endif
976
976
977
+ #if MICROPY_PY_DESCRIPTORS
978
+ static void run_set_name_hooks (mp_obj_t locals_dict , mp_obj_t owner ) {
979
+ // copy the dict so we can iterate safely even while __set_name__ potentially modifies the original
980
+ mp_obj_dict_t * locals_dict_copy = MP_OBJ_TO_PTR (mp_obj_dict_copy (locals_dict ));
981
+ mp_map_t * locals_map = mp_obj_dict_get_map (locals_dict_copy );
982
+
983
+ // make sure we don't leak this copy's memory
984
+ nlr_buf_t nlr ;
985
+ bool ok = (nlr_push (& nlr ) == 0 );
986
+ if (ok ) {
987
+ // use the copy to call __set_name__ on each
988
+ for (size_t i = 0 ; i < locals_map -> alloc ; i ++ ) {
989
+ if (mp_map_slot_is_filled (locals_map , i )) {
990
+ mp_map_elem_t * elem = & (locals_map -> table [i ]);
991
+ mp_obj_t set_name_method [4 ];
992
+ mp_load_method_maybe (elem -> value , MP_QSTR___set_name__ , set_name_method );
993
+ if (set_name_method [1 ] != MP_OBJ_NULL ) {
994
+ set_name_method [2 ] = owner ;
995
+ set_name_method [3 ] = elem -> key ;
996
+ mp_call_method_n_kw (2 , 0 , set_name_method );
997
+ }
998
+ }
999
+ }
1000
+ nlr_pop ();
1001
+ }
1002
+ m_del_obj (locals_dict_copy -> base .type , locals_dict_copy );
1003
+ if (!ok ) {
1004
+ nlr_raise (nlr .ret_val ); // TODO cpython raises a RuntimeError from this instead
1005
+ }
1006
+ }
1007
+ #endif
1008
+
977
1009
static void type_print (const mp_print_t * print , mp_obj_t self_in , mp_print_kind_t kind ) {
978
1010
(void )kind ;
979
1011
mp_obj_type_t * self = MP_OBJ_TO_PTR (self_in );
@@ -1242,20 +1274,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict)
1242
1274
}
1243
1275
1244
1276
#if MICROPY_PY_DESCRIPTORS
1245
- // call __set_name__ on all entries (especially descriptors)
1246
- for (size_t i = 0 ; i < locals_map -> alloc ; i ++ ) {
1247
- if (mp_map_slot_is_filled (locals_map , i )) {
1248
- elem = & (locals_map -> table [i ]);
1249
-
1250
- mp_obj_t set_name_method [4 ];
1251
- mp_load_method_maybe (elem -> value , MP_QSTR___set_name__ , set_name_method );
1252
- if (set_name_method [1 ] != MP_OBJ_NULL ) {
1253
- set_name_method [2 ] = MP_OBJ_FROM_PTR (o );
1254
- set_name_method [3 ] = elem -> key ;
1255
- mp_call_method_n_kw (2 , 0 , set_name_method );
1256
- }
1257
- }
1258
- }
1277
+ run_set_name_hooks (locals_dict , MP_OBJ_FROM_PTR (o ));
1259
1278
#endif
1260
1279
1261
1280
return MP_OBJ_FROM_PTR (o );
0 commit comments