diff --git a/source/blender/python/intern/bpy_rna.cc b/source/blender/python/intern/bpy_rna.cc index 4af762aa089..33d54fd3246 100644 --- a/source/blender/python/intern/bpy_rna.cc +++ b/source/blender/python/intern/bpy_rna.cc @@ -102,17 +102,30 @@ static PyObject *pyrna_unregister_class(PyObject *self, PyObject *py_class); " Only the :class:`bpy.types.ID`, :class:`bpy.types.Bone` and\n" \ " :class:`bpy.types.PoseBone` classes support custom properties.\n" -int pyrna_struct_validity_check(BPy_StructRNA *pysrna) +int pyrna_struct_validity_check_only(const BPy_StructRNA *pysrna) { if (pysrna->ptr.type) { return 0; } - PyErr_Format( - PyExc_ReferenceError, "StructRNA of type %.200s has been removed", Py_TYPE(pysrna)->tp_name); return -1; } -int pyrna_prop_validity_check(BPy_PropertyRNA *self) +void pyrna_struct_validity_exception_only(const BPy_StructRNA *pysrna) +{ + PyErr_Format( + PyExc_ReferenceError, "StructRNA of type %.200s has been removed", Py_TYPE(pysrna)->tp_name); +} + +int pyrna_struct_validity_check(const BPy_StructRNA *pysrna) +{ + if (pysrna->ptr.type) { + return 0; + } + pyrna_struct_validity_exception_only(pysrna); + return -1; +} + +int pyrna_prop_validity_check(const BPy_PropertyRNA *self) { if (self->ptr.type) { return 0; @@ -4382,7 +4395,8 @@ static PyObject *pyrna_struct_getattro(BPy_StructRNA *self, PyObject *pyname) PropertyRNA *prop; FunctionRNA *func; - PYRNA_STRUCT_CHECK_OBJ(self); + /* Allow `__class__` so `isinstance(ob, cls)` can be used without raising an exception. */ + PYRNA_STRUCT_CHECK_OBJ_UNLESS(self, name && STREQ(name, "__class__")); if (name == nullptr) { PyErr_SetString(PyExc_AttributeError, "bpy_struct: __getattr__ must be a string"); diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h index 661c7062462..c6aa29964ab 100644 --- a/source/blender/python/intern/bpy_rna.h +++ b/source/blender/python/intern/bpy_rna.h @@ -96,6 +96,16 @@ extern PyTypeObject pyrna_func_Type; } \ (void)0 +#define PYRNA_STRUCT_CHECK_OBJ_UNLESS(obj, unless) \ + { \ + const BPy_StructRNA *_obj = obj; \ + if (UNLIKELY(pyrna_struct_validity_check_only(_obj) == -1) && !(unless)) { \ + pyrna_struct_validity_exception_only(_obj); \ + return NULL; \ + } \ + } \ + (void)0 + #define PYRNA_STRUCT_IS_VALID(pysrna) (LIKELY(((BPy_StructRNA *)(pysrna))->ptr.type != NULL)) #define PYRNA_PROP_IS_VALID(pysrna) (LIKELY(((BPy_PropertyRNA *)(pysrna))->ptr.type != NULL)) @@ -256,8 +266,12 @@ bool pyrna_write_check(void); void pyrna_write_set(bool val); void pyrna_invalidate(BPy_DummyPointerRNA *self); -int pyrna_struct_validity_check(BPy_StructRNA *pysrna); -int pyrna_prop_validity_check(BPy_PropertyRNA *self); + +int pyrna_struct_validity_check_only(const BPy_StructRNA *pysrna); +void pyrna_struct_validity_exception_only(const BPy_StructRNA *pysrna); +int pyrna_struct_validity_check(const BPy_StructRNA *pysrna); + +int pyrna_prop_validity_check(const BPy_PropertyRNA *self); /* bpy.utils.(un)register_class */ extern PyMethodDef meth_bpy_register_class;