py: Implement delete for property and descriptors.
Without this patch deleting a property, or class with descriptor, will call the setter with a NULL value and lead to a crash.
This commit is contained in:
parent
0528c5a22a
commit
56606f3475
62
py/objtype.c
62
py/objtype.c
|
@ -533,35 +533,59 @@ bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
|
||||||
if (member[0] != MP_OBJ_NULL) {
|
if (member[0] != MP_OBJ_NULL) {
|
||||||
#if MICROPY_PY_BUILTINS_PROPERTY
|
#if MICROPY_PY_BUILTINS_PROPERTY
|
||||||
if (MP_OBJ_IS_TYPE(member[0], &mp_type_property)) {
|
if (MP_OBJ_IS_TYPE(member[0], &mp_type_property)) {
|
||||||
// attribute exists and is a property; delegate the store
|
// attribute exists and is a property; delegate the store/delete
|
||||||
// Note: This is an optimisation for code size and execution time.
|
// Note: This is an optimisation for code size and execution time.
|
||||||
// The proper way to do it is have the functionality just below
|
// The proper way to do it is have the functionality just below in
|
||||||
// in a __set__ method of the property object, and then it would
|
// a __set__/__delete__ method of the property object, and then it
|
||||||
// be called by the descriptor code down below. But that way
|
// would be called by the descriptor code down below. But that way
|
||||||
// requires overhead for the nested mp_call's and overhead for
|
// requires overhead for the nested mp_call's and overhead for
|
||||||
// the code.
|
// the code.
|
||||||
const mp_obj_t *proxy = mp_obj_property_get(member[0]);
|
const mp_obj_t *proxy = mp_obj_property_get(member[0]);
|
||||||
if (proxy[1] == mp_const_none) {
|
mp_obj_t dest[2] = {self_in, value};
|
||||||
// TODO better error message?
|
if (value == MP_OBJ_NULL) {
|
||||||
return false;
|
// delete attribute
|
||||||
|
if (proxy[2] == mp_const_none) {
|
||||||
|
// TODO better error message?
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
mp_call_function_n_kw(proxy[2], 1, 0, dest);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
mp_obj_t dest[2] = {self_in, value};
|
// store attribute
|
||||||
mp_call_function_n_kw(proxy[1], 2, 0, dest);
|
if (proxy[1] == mp_const_none) {
|
||||||
return true;
|
// TODO better error message?
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
mp_call_function_n_kw(proxy[1], 2, 0, dest);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MICROPY_PY_DESCRIPTORS
|
#if MICROPY_PY_DESCRIPTORS
|
||||||
// found a class attribute; if it has a __set__ method then call it with the
|
// found a class attribute; if it has a __set__/__delete__ method then
|
||||||
// class instance and value as arguments
|
// call it with the class instance (and value) as arguments
|
||||||
mp_obj_t attr_set_method[4];
|
if (value == MP_OBJ_NULL) {
|
||||||
mp_load_method_maybe(member[0], MP_QSTR___set__, attr_set_method);
|
// delete attribute
|
||||||
if (attr_set_method[0] != MP_OBJ_NULL) {
|
mp_obj_t attr_delete_method[3];
|
||||||
attr_set_method[2] = self_in;
|
mp_load_method_maybe(member[0], MP_QSTR___delete__, attr_delete_method);
|
||||||
attr_set_method[3] = value;
|
if (attr_delete_method[0] != MP_OBJ_NULL) {
|
||||||
mp_call_method_n_kw(2, 0, attr_set_method);
|
attr_delete_method[2] = self_in;
|
||||||
return true;
|
mp_call_method_n_kw(1, 0, attr_delete_method);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// store attribute
|
||||||
|
mp_obj_t attr_set_method[4];
|
||||||
|
mp_load_method_maybe(member[0], MP_QSTR___set__, attr_set_method);
|
||||||
|
if (attr_set_method[0] != MP_OBJ_NULL) {
|
||||||
|
attr_set_method[2] = self_in;
|
||||||
|
attr_set_method[3] = value;
|
||||||
|
mp_call_method_n_kw(2, 0, attr_set_method);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,7 @@ Q(__str__)
|
||||||
#if MICROPY_PY_DESCRIPTORS
|
#if MICROPY_PY_DESCRIPTORS
|
||||||
Q(__get__)
|
Q(__get__)
|
||||||
Q(__set__)
|
Q(__set__)
|
||||||
|
Q(__delete__)
|
||||||
#endif
|
#endif
|
||||||
Q(__getattr__)
|
Q(__getattr__)
|
||||||
Q(__del__)
|
Q(__del__)
|
||||||
|
|
Loading…
Reference in New Issue