Merge branch 'master' into blender2.8
[blender.git] / source / blender / python / intern / bpy_rna.c
index 2ffb2ba5291b9cc4c816b0ef1579a0dc090033d1..1368b610b53e1021cd26d8d74d524b7da76d4305 100644 (file)
@@ -3716,6 +3716,66 @@ static PyObject *pyrna_struct_type_recast(BPy_StructRNA *self)
        return pyrna_struct_CreatePyObject(&r_ptr);
 }
 
+/**
+ * \note Return value is borrowed, caller must incref.
+ */
+static PyObject *pyrna_struct_bl_rna_find_subclass_recursive(PyObject *cls, const char *id)
+{
+       PyObject *ret_test = NULL;
+       PyObject *subclasses = ((PyTypeObject *)cls)->tp_subclasses;
+       if (subclasses) {
+               /* Unfortunately we can't use the dict key because Python class names
+                * don't match the bl_idname used internally. */
+               BLI_assert(PyDict_CheckExact(subclasses));
+               PyObject *key = NULL;
+               Py_ssize_t pos = 0;
+               PyObject *value = NULL;
+               while (PyDict_Next(subclasses, &pos, &key, &value)) {
+                       BLI_assert(PyWeakref_CheckRef(value));
+                       PyObject *subcls = PyWeakref_GET_OBJECT(value);
+                       if (subcls != Py_None) {
+                               BPy_StructRNA *py_srna = (BPy_StructRNA *)PyDict_GetItem(
+                                       ((PyTypeObject *)subcls)->tp_dict, bpy_intern_str_bl_rna);
+                               if (py_srna) {
+                                       StructRNA *srna = py_srna->ptr.data;
+                                       if (STREQ(id, RNA_struct_identifier(srna))) {
+                                               ret_test = subcls;
+                                               break;
+                                       }
+                               }
+                               ret_test = pyrna_struct_bl_rna_find_subclass_recursive(subcls, id);
+                               if (ret_test) {
+                                       break;
+                               }
+                       }
+               }
+       }
+       return ret_test;
+}
+
+PyDoc_STRVAR(pyrna_struct_bl_rna_get_subclass_doc,
+".. classmethod:: bl_rna_get_subclass(id, default=None)\n"
+"\n"
+"   :arg id: The RNA type identifier.\n"
+"   :type vector: string\n"
+"   :return: The class or default when not found.\n"
+"   :rtype: type\n"
+);
+static PyObject *pyrna_struct_bl_rna_get_subclass(PyObject *cls, PyObject *args)
+{
+       char *id;
+       PyObject *ret_default = Py_None;
+
+       if (!PyArg_ParseTuple(args, "s|O:bl_rna_get_subclass", &id, &ret_default)) {
+               return NULL;
+       }
+       PyObject *ret = pyrna_struct_bl_rna_find_subclass_recursive(cls, id);
+       if (ret == NULL) {
+               ret = ret_default;
+       }
+       return Py_INCREF_RET(ret);
+}
+
 static void pyrna_dir_members_py__add_keys(PyObject *list, PyObject *dict)
 {
        PyObject *list_tmp;
@@ -5014,6 +5074,7 @@ static struct PyMethodDef pyrna_struct_methods[] = {
        {"path_resolve", (PyCFunction)pyrna_struct_path_resolve, METH_VARARGS, pyrna_struct_path_resolve_doc},
        {"path_from_id", (PyCFunction)pyrna_struct_path_from_id, METH_VARARGS, pyrna_struct_path_from_id_doc},
        {"type_recast", (PyCFunction)pyrna_struct_type_recast, METH_NOARGS, pyrna_struct_type_recast_doc},
+       {"bl_rna_get_subclass", (PyCFunction) pyrna_struct_bl_rna_get_subclass, METH_VARARGS | METH_CLASS, pyrna_struct_bl_rna_get_subclass_doc},
        {"__dir__", (PyCFunction)pyrna_struct_dir, METH_NOARGS, NULL},
 
        /* experimental */