bpy/rna api class feature

- python defined classes will be used when available (otherwise automaically generated metaclasses are made as before)
- use properties rather then functions for python defined rna class's
- call the classes getattr AFTER doing an RNA lookup, avoids setting and clearing exceptions for most attribute lookups, tested UI scripts are ~25% faster.
- extending rna py classes this way is a nicer alternative to modifying the generated metaclasses in place.

Example class

--- snip
class Object(bpy.types.ID):

    def _get_children(self):
        return [child for child in bpy.data.objects if child.parent == self]

    children = property(_get_children)
--- snip

The C initialization function looks in bpy_types.py for classes matching RNA structure names, using them when available.
This means all objects in python will be instances of these classes.
Python properties/funcs defined in ID py class will also be available for subclasses for eg. (Group Mesh etc)
This commit is contained in:
2009-11-08 01:13:19 +00:00
parent 30c4c4599d
commit fac2ca1c7c
9 changed files with 202 additions and 170 deletions

View File

@@ -1364,16 +1364,6 @@ static PyObject *pyrna_struct_getattro( BPy_StructRNA * self, PyObject *pyname )
PropertyRNA *prop;
FunctionRNA *func;
/* Include this incase this instance is a subtype of a python class
* In these instances we may want to return a function or variable provided by the subtype
*
* Also needed to return methods when its not a subtype
* */
ret = PyObject_GenericGetAttr((PyObject *)self, pyname);
if (ret) return ret;
else PyErr_Clear();
/* done with subtypes */
if ((prop = RNA_struct_find_property(&self->ptr, name))) {
ret = pyrna_prop_to_py(&self->ptr, prop);
}
@@ -1419,8 +1409,18 @@ static PyObject *pyrna_struct_getattro( BPy_StructRNA * self, PyObject *pyname )
}
}
else {
#if 0
PyErr_Format( PyExc_AttributeError, "StructRNA - Attribute \"%.200s\" not found", name);
ret = NULL;
#endif
/* Include this incase this instance is a subtype of a python class
* In these instances we may want to return a function or variable provided by the subtype
*
* Also needed to return methods when its not a subtype
* */
/* The error raised here will be displayed */
ret = PyObject_GenericGetAttr((PyObject *)self, pyname);
}
return ret;
@@ -2551,6 +2551,7 @@ static PyObject* pyrna_srna_PyBase(StructRNA *srna) //, PyObject *bpy_types_dict
/* get the base type */
base= RNA_struct_base(srna);
if(base && base != srna) {
/*/printf("debug subtype %s %p\n", RNA_struct_identifier(srna), srna); */
py_base= pyrna_srna_Subtype(base); //, bpy_types_dict);
@@ -2564,6 +2565,56 @@ static PyObject* pyrna_srna_PyBase(StructRNA *srna) //, PyObject *bpy_types_dict
return py_base;
}
/* check if we have a native python subclass, use it when it exists
* return a borrowed reference */
static PyObject* pyrna_srna_ExternalType(StructRNA *srna)
{
PyObject *bpy_types_dict= NULL;
const char *idname= RNA_struct_identifier(srna);
PyObject *newclass;
if(bpy_types_dict==NULL) {
PyObject *bpy_types= PyImport_ImportModuleLevel("bpy_types", NULL, NULL, NULL, 0);
if(bpy_types==NULL) {
PyErr_Print();
PyErr_Clear();
fprintf(stderr, "pyrna_srna_ExternalType: failed to find 'bpy_types' module\n");
return NULL;
}
bpy_types_dict = PyModule_GetDict(bpy_types); // borrow
Py_DECREF(bpy_types); // fairly safe to assume the dict is kept
}
newclass= PyDict_GetItemString(bpy_types_dict, idname);
/* sanity check, could skip this unless in debug mode */
if(newclass) {
PyObject *base_compare= pyrna_srna_PyBase(srna);
PyObject *bases= PyObject_GetAttrString(newclass, "__bases__");
if(PyTuple_GET_SIZE(bases)) {
PyObject *base= PyTuple_GET_ITEM(bases, 0);
if(base_compare != base) {
PyLineSpit();
fprintf(stderr, "pyrna_srna_ExternalType: incorrect subclassing of SRNA '%s'\n", idname);
PyObSpit("Expected! ", base_compare);
newclass= NULL;
}
else {
if(G.f & G_DEBUG)
fprintf(stderr, "SRNA Subclassed: '%s'\n", idname);
}
}
Py_DECREF(bases);
}
return newclass;
}
static PyObject* pyrna_srna_Subtype(StructRNA *srna)
{
PyObject *newclass = NULL;
@@ -2572,6 +2623,9 @@ static PyObject* pyrna_srna_Subtype(StructRNA *srna)
newclass= NULL; /* Nothing to do */
} else if ((newclass= RNA_struct_py_type_get(srna))) {
Py_INCREF(newclass);
} else if ((newclass= pyrna_srna_ExternalType(srna))) {
pyrna_subtype_set_rna(newclass, srna);
Py_INCREF(newclass);
} else {
/* subclass equivelents
- class myClass(myBase):
@@ -2681,23 +2735,26 @@ PyObject *pyrna_prop_CreatePyObject( PointerRNA *ptr, PropertyRNA *prop )
return ( PyObject * ) pyrna;
}
/* bpy.data from python */
static PointerRNA *rna_module_ptr= NULL;
PyObject *BPY_rna_module( void )
void BPY_rna_init(void)
{
BPy_StructRNA *pyrna;
PointerRNA ptr;
#ifdef USE_MATHUTILS // register mathutils callbacks, ok to run more then once.
mathutils_rna_array_cb_index= Mathutils_RegisterCallback(&mathutils_rna_array_cb);
mathutils_rna_matrix_cb_index= Mathutils_RegisterCallback(&mathutils_rna_matrix_cb);
#endif
if( PyType_Ready( &pyrna_struct_Type ) < 0 )
return NULL;
return;
if( PyType_Ready( &pyrna_prop_Type ) < 0 )
return NULL;
return;
}
/* bpy.data from python */
static PointerRNA *rna_module_ptr= NULL;
PyObject *BPY_rna_module(void)
{
BPy_StructRNA *pyrna;
PointerRNA ptr;
/* for now, return the base RNA type rather then a real module */
RNA_main_pointer_create(G.main, &ptr);
@@ -2735,21 +2792,22 @@ static PyObject *pyrna_basetype_getattro( BPy_BaseTypeRNA * self, PyObject *pyna
PointerRNA newptr;
PyObject *ret;
ret = PyObject_GenericGetAttr((PyObject *)self, pyname);
if (ret) return ret;
else PyErr_Clear();
if (RNA_property_collection_lookup_string(&self->ptr, self->prop, _PyUnicode_AsString(pyname), &newptr)) {
ret= pyrna_struct_Subtype(&newptr);
if (ret==NULL) {
PyErr_Format(PyExc_SystemError, "bpy.types.%.200s subtype could not be generated, this is a bug!", _PyUnicode_AsString(pyname));
}
return ret;
}
else { /* Override the error */
else {
#if 0
PyErr_Format(PyExc_AttributeError, "bpy.types.%.200s RNA_Struct does not exist", _PyUnicode_AsString(pyname));
return NULL;
#endif
/* The error raised here will be displayed */
ret= PyObject_GenericGetAttr((PyObject *)self, pyname);
}
return ret;
}
static PyObject *pyrna_basetype_dir(BPy_BaseTypeRNA *self);