diff --git a/source/blender/python/intern/bpy_rna.cc b/source/blender/python/intern/bpy_rna.cc index ff63f9631ab..40c6903e3fd 100644 --- a/source/blender/python/intern/bpy_rna.cc +++ b/source/blender/python/intern/bpy_rna.cc @@ -90,6 +90,11 @@ BPy_StructRNA *bpy_context_module = nullptr; /* for fast access */ +static PyObject *pyrna_struct_CreatePyObject_from_type(PointerRNA *ptr, + PyTypeObject *tp, + void **instance); + +static PyObject *pyrna_srna_Subtype(StructRNA *srna); static PyObject *pyrna_struct_Subtype(PointerRNA *ptr); static PyObject *pyrna_prop_collection_values(BPy_PropertyRNA *self); @@ -7347,8 +7352,6 @@ static void pyrna_prop_collection_iter_dealloc(BPy_PropertyCollectionIterRNA *se static void pyrna_subtype_set_rna(PyObject *newclass, StructRNA *srna) { - PyObject *item; - Py_INCREF(newclass); if (PyObject *oldclass = static_cast(RNA_struct_py_type_get(srna))) { @@ -7362,12 +7365,25 @@ static void pyrna_subtype_set_rna(PyObject *newclass, StructRNA *srna) /* Python deals with the circular reference. */ PointerRNA ptr = RNA_pointer_create(nullptr, &RNA_Struct, srna); - item = pyrna_struct_CreatePyObject(&ptr); - /* NOTE: must set the class not the __dict__ else the internal slots are not updated correctly. - */ - PyObject_SetAttr(newclass, bpy_intern_str_bl_rna, item); - Py_DECREF(item); + /* NOTE: using `pyrna_struct_CreatePyObject(&ptr)` is close to what is needed, + * however the it isn't correct because the result of: + * `type(bpy.types.Object.bl_rna) == bpy.types.Object`. + * In this case the type of `bl_rna` should be `bpy.types.Struct`. + * This is passed in explicitly, while #pyrna_struct_CreatePyObject could + * take this as an argument it's such a corner case that using a lower level + * function that takes the type is preferable. */ + { + BLI_assert(RNA_struct_instance(&ptr) == nullptr); + PyTypeObject *tp = (PyTypeObject *)pyrna_srna_Subtype(&RNA_Struct); + PyObject *item = pyrna_struct_CreatePyObject_from_type(&ptr, tp, nullptr); + Py_DECREF(tp); /* `srna` owns, can't hold a reference. */ + + /* NOTE: must set the class not the `__dict__` + * else the internal slots are not updated correctly. */ + PyObject_SetAttr(newclass, bpy_intern_str_bl_rna, item); + Py_DECREF(item); + } /* Add `staticmethod` and `classmethod` functions. */ { @@ -7392,8 +7408,6 @@ static void pyrna_subtype_set_rna(PyObject *newclass, StructRNA *srna) /* Done with RNA instance. */ } -static PyObject *pyrna_srna_Subtype(StructRNA *srna); - /* Return a borrowed reference. */ static PyObject *pyrna_srna_PyBase(StructRNA *srna) //, PyObject *bpy_types_dict) { @@ -7604,38 +7618,16 @@ static PyObject *pyrna_struct_Subtype(PointerRNA *ptr) /*-----------------------CreatePyObject---------------------------------*/ -PyObject *pyrna_struct_CreatePyObject(PointerRNA *ptr) +/** + * A lower level version of #pyrna_struct_CreatePyObject, + * use this when type (`tp`) needs to be set to a non-standard value. + */ +static PyObject *pyrna_struct_CreatePyObject_from_type(PointerRNA *ptr, + PyTypeObject *tp, + void **instance) { BPy_StructRNA *pyrna = nullptr; - - /* NOTE: don't rely on this to return None since nullptr data with a valid type can often crash. - */ - if (ptr->data == nullptr && ptr->type == nullptr) { /* Operator RNA has nullptr data. */ - Py_RETURN_NONE; - } - - /* New in 2.8x, since not many types support instancing - * we may want to use a flag to avoid looping over all classes. - campbell */ - void **instance = ptr->data ? RNA_struct_instance(ptr) : nullptr; - if (instance && *instance) { - pyrna = static_cast(*instance); - - /* Refine may have changed types after the first instance was created. */ - if (ptr->type == pyrna->ptr.type) { - Py_INCREF(pyrna); - return (PyObject *)pyrna; - } - - /* Existing users will need to use 'type_recast' method. */ - Py_DECREF(pyrna); - *instance = nullptr; -/* Continue as if no instance was made. */ -#if 0 /* No need to assign, will be written to next... */ - pyrna = nullptr; -#endif - } - - if (PyTypeObject *tp = (PyTypeObject *)pyrna_struct_Subtype(ptr)) { + if (tp) { pyrna = (BPy_StructRNA *)tp->tp_alloc(tp, 0); #ifdef USE_PYRNA_STRUCT_REFERENCE /* #PyType_GenericAlloc will have set tracking. @@ -7644,7 +7636,6 @@ PyObject *pyrna_struct_CreatePyObject(PointerRNA *ptr) PyObject_GC_UnTrack(pyrna); } #endif - Py_DECREF(tp); /* srna owns, can't hold a reference. */ } else { CLOG_WARN(BPY_LOG_RNA, "could not make type '%s'", RNA_struct_identifier(ptr->type)); @@ -7698,6 +7689,43 @@ PyObject *pyrna_struct_CreatePyObject(PointerRNA *ptr) return (PyObject *)pyrna; } +PyObject *pyrna_struct_CreatePyObject(PointerRNA *ptr) +{ + BPy_StructRNA *pyrna = nullptr; + + /* NOTE: don't rely on this to return None since nullptr data with a valid type can often crash. + */ + if (ptr->data == nullptr && ptr->type == nullptr) { /* Operator RNA has nullptr data. */ + Py_RETURN_NONE; + } + + /* New in 2.8x, since not many types support instancing + * we may want to use a flag to avoid looping over all classes. - campbell */ + void **instance = ptr->data ? RNA_struct_instance(ptr) : nullptr; + if (instance && *instance) { + pyrna = static_cast(*instance); + + /* Refine may have changed types after the first instance was created. */ + if (ptr->type == pyrna->ptr.type) { + Py_INCREF(pyrna); + return (PyObject *)pyrna; + } + + /* Existing users will need to use 'type_recast' method. */ + Py_DECREF(pyrna); + *instance = nullptr; +/* Continue as if no instance was made. */ +#if 0 /* No need to assign, will be written to next... */ + pyrna = nullptr; +#endif + } + + PyTypeObject *tp = (PyTypeObject *)pyrna_struct_Subtype(ptr); + pyrna = (BPy_StructRNA *)pyrna_struct_CreatePyObject_from_type(ptr, tp, instance); + Py_XDECREF(tp); /* `srna` owns, can't hold a reference. */ + return (PyObject *)pyrna; +} + PyObject *pyrna_struct_CreatePyObject_with_primitive_support(PointerRNA *ptr) { if (ptr->type == &RNA_PrimitiveString) {