diff options
author | Campbell Barton <ideasman42@gmail.com> | 2009-11-08 04:13:19 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2009-11-08 04:13:19 +0300 |
commit | fac2ca1c7ca26b9e7019d5c3367b1cb758ba8ca4 (patch) | |
tree | 9f4b7e554ceee580d01fb22702d8b6ff01064bbf /source/blender | |
parent | 30c4c4599dfb72b430a409648bb1407a0f197332 (diff) |
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)
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/python/intern/bpy_interface.c | 53 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_rna.c | 110 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_rna.h | 1 |
3 files changed, 114 insertions, 50 deletions
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index e67df5db096..4a55c2fb6fb 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -176,35 +176,35 @@ static void bpy_init_modules( void ) { PyObject *mod; - mod = PyModule_New("bpy"); + /* Needs to be first since this dir is needed for future modules */ + char *modpath= BLI_gethome_folder("scripts/modules", BLI_GETHOME_ALL); + if(modpath) { + PyObject *sys_path= PySys_GetObject("path"); /* borrow */ + PyObject *py_modpath= PyUnicode_FromString(modpath); + PyList_Insert(sys_path, 0, py_modpath); /* add first */ + Py_DECREF(py_modpath); + } - PyModule_AddObject( mod, "data", BPY_rna_module() ); + mod = PyModule_New("bpy"); + + /* add the module so we can import it */ + PyDict_SetItemString(PySys_GetObject("modules"), "bpy", mod); + Py_DECREF(mod); + + /* run first, initializes rna types */ + BPY_rna_init(); + + PyModule_AddObject( mod, "types", BPY_rna_types() ); /* needs to be first so bpy_types can run */ + bpy_import_test("bpy_types"); + PyModule_AddObject( mod, "data", BPY_rna_module() ); /* imports bpy_types by running this */ + bpy_import_test("bpy_types"); /* PyModule_AddObject( mod, "doc", BPY_rna_doc() ); */ - PyModule_AddObject( mod, "types", BPY_rna_types() ); PyModule_AddObject( mod, "props", BPY_rna_props() ); PyModule_AddObject( mod, "__ops__", BPY_operator_module() ); /* ops is now a python module that does the conversion from SOME_OT_foo -> some.foo */ PyModule_AddObject( mod, "ui", BPY_ui_module() ); // XXX very experimental, consider this a test, especially PyCObject is not meant to be permanent - - /* add the module so we can import it */ - PyDict_SetItemString(PySys_GetObject("modules"), "bpy", mod); - Py_DECREF(mod); - /* add our own modules dir */ - { - char *modpath= BLI_gethome_folder("scripts/modules", BLI_GETHOME_ALL); - - if(modpath) { - PyObject *sys_path= PySys_GetObject("path"); /* borrow */ - PyObject *py_modpath= PyUnicode_FromString(modpath); - PyList_Insert(sys_path, 0, py_modpath); /* add first */ - Py_DECREF(py_modpath); - } - - bpy_import_test("bpy_ops"); /* adds its self to bpy.ops */ - bpy_import_test("bpy_utils"); /* adds its self to bpy.sys */ - bpy_import_test("bpy_ext"); /* extensions to our existing types */ - } - + + /* bpy context */ { bpy_context_module= ( BPy_StructRNA * ) PyObject_NEW( BPy_StructRNA, &pyrna_struct_Type ); @@ -213,11 +213,16 @@ static void bpy_init_modules( void ) PyModule_AddObject(mod, "context", (PyObject *)bpy_context_module); } - /* stand alone utility modules not related to blender directly */ Geometry_Init(); Mathutils_Init(); BGL_Init(); + + /* add our own modules dir */ + { + bpy_import_test("bpy_ops"); /* adds its self to bpy.ops */ + bpy_import_test("bpy_utils"); /* adds its self to bpy.sys */ + } } void BPY_update_modules( void ) diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 3e31e24a8e0..15c1f378cb1 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -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); diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h index d480fd3ec9b..fe38ddb6bd9 100644 --- a/source/blender/python/intern/bpy_rna.h +++ b/source/blender/python/intern/bpy_rna.h @@ -64,6 +64,7 @@ typedef struct { /* cheap trick */ #define BPy_BaseTypeRNA BPy_PropertyRNA +void BPY_rna_init( void ); PyObject *BPY_rna_module( void ); void BPY_update_rna_module( void ); /*PyObject *BPY_rna_doc( void );*/ |