diff options
author | Campbell Barton <ideasman42@gmail.com> | 2009-03-11 20:28:37 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2009-03-11 20:28:37 +0300 |
commit | 64512d3e8e9f950b8249deb506eb243345dc107e (patch) | |
tree | 14c6d7ba33f8674b85aceede7730d91b871caae8 /source/blender/python/intern | |
parent | 891c3bc663b0f1ece07bfd48e06853a9eedb6178 (diff) |
WIP PyAPI from winter camp discussions, make subtypes of the base RNA python type, eventually allowing us to have python defined RNA classes in
python - lux/pov/renderman materials, lamps etc as well as operators.
At the moment there are 2 ways to do this, The first is like subclassing from python, another (disabled) method copies the base PyTypeObject struct
and makes some changes.
The PyType is stored in the RNA Struct for reuse, right now there are no access functions - needs to be improved.
Added a python script for printing all blend file data to the console which helps testing the api.
dir(rna) wont work for python 2.x now, use rna.__dir__() instead.
Diffstat (limited to 'source/blender/python/intern')
-rw-r--r-- | source/blender/python/intern/bpy_interface.c | 7 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_operator.c | 5 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_rna.c | 308 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_rna.h | 14 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_util.c | 2 |
5 files changed, 298 insertions, 38 deletions
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index bb315cda47a..19d8b79884f 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -80,6 +80,8 @@ void BPY_start_python( void ) // todo - sys paths - our own imports + BPY_rna_init_types(); + py_tstate = PyGILState_GetThisThreadState(); PyEval_ReleaseThread(py_tstate); @@ -90,8 +92,11 @@ void BPY_end_python( void ) PyGILState_Ensure(); /* finalizing, no need to grab the state */ // free other python data. + //BPY_rna_free_types(); Py_Finalize( ); + + BPY_rna_free_types(); /* this MUST run after Py_Finalize since it frees Dynamic allocated PyTypes so we cant free them first */ return; } @@ -123,7 +128,7 @@ int BPY_run_python_script( bContext *C, const char *fn, struct Text *text ) if( PyErr_Occurred( ) ) { BPY_free_compiled_text( text ); - return NULL; + return 0; } } py_result = PyEval_EvalCode( text->compiled, py_dict, py_dict ); diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index ec8227c670d..d158fc72c1b 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -190,10 +190,9 @@ PyObject *pyop_func_get_rna(BPy_OperatorFunc *self) return NULL; } - pyrna= (BPy_StructRNA *)pyrna_struct_CreatePyObject(&ptr); /* were not really using &ptr, overwite next */ - /* XXX POINTER - if this 'ot' is python generated, it could be free'd */ - RNA_pointer_create(NULL, ot->srna, NULL, &pyrna->ptr); + RNA_pointer_create(NULL, ot->srna, NULL, &ptr); + pyrna= (BPy_StructRNA *)pyrna_struct_CreatePyObject(&ptr); /* were not really using &ptr, overwite next */ pyrna->freeptr= 1; return (PyObject *)pyrna; diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index c4ba79d8373..fd6221d6ff9 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -30,8 +30,11 @@ #include "MEM_guardedalloc.h" #include "BKE_global.h" /* evil G.* */ -/* floats bigger then this are displayed as inf in the docstrings */ -#define MAXFLOAT_DOC 10000000 +/* There are 2 ways subclassing can work, PY_CLASS_SUBTYPE - Uses pythons internal subclassing + * - class MyClass(SomeClass): ... + * When PY_CLASS_SUBTYPE is not defined use a C subclass which copies the PyTypeObject and makes some changes. +*/ +#define PY_CLASS_SUBTYPE static int pyrna_struct_compare( BPy_StructRNA * a, BPy_StructRNA * b ) { @@ -565,27 +568,28 @@ static PyMappingMethods pyrna_prop_as_mapping = { ( objobjargproc ) pyrna_prop_assign_subscript, /* mp_ass_subscript */ }; -//---------------getattr-------------------------------------------- -static PyObject *pyrna_struct_getattro( BPy_StructRNA * self, PyObject *pyname ) +static PyObject *pyrna_struct_dir(BPy_StructRNA * self) { - char *name = _PyUnicode_AsString(pyname); - PyObject *ret; - PropertyRNA *prop; + PyObject *ret, *dict; + PyObject *pystring = PyUnicode_FromString("__dict__"); /* 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 * */ - ret = PyObject_GenericGetAttr((PyObject *)self, pyname); - if (ret) return ret; - else PyErr_Clear(); - /* done with subtypes */ - - prop = RNA_struct_find_property(&self->ptr, name); + dict = PyObject_GenericGetAttr((PyObject *)self, pystring); + Py_DECREF(pystring); - if (prop) { - ret = pyrna_prop_to_py(&self->ptr, prop); + if (dict==NULL) { + PyErr_Clear(); + ret = PyList_New(0); + } + else { + ret = PyDict_Keys(dict); + Py_DECREF(dict); } - else if (strcmp(name, "__dict__")==0) { /* Not quite correct, adding this so dir() gives good feedback */ + + /* Collect RNA items*/ + { PropertyRNA *iterprop, *nameprop; CollectionPropertyIterator iter; char name[256], *nameptr; @@ -593,11 +597,13 @@ static PyObject *pyrna_struct_getattro( BPy_StructRNA * self, PyObject *pyname ) iterprop= RNA_struct_iterator_property(&self->ptr); RNA_property_collection_begin(&self->ptr, iterprop, &iter); - ret = PyDict_New(); for(; iter.valid; RNA_property_collection_next(&iter)) { if(iter.ptr.data && (nameprop = RNA_struct_name_property(&iter.ptr))) { nameptr= RNA_property_string_get_alloc(&iter.ptr, nameprop, name, sizeof(name)); - PyDict_SetItemString(ret, nameptr, Py_None); + + pystring = PyUnicode_FromString(nameptr); + PyList_Append(ret, pystring); + Py_DECREF(pystring); if ((char *)&name != nameptr) MEM_freeN(nameptr); @@ -606,6 +612,31 @@ static PyObject *pyrna_struct_getattro( BPy_StructRNA * self, PyObject *pyname ) RNA_property_collection_end(&iter); } + + return ret; +} + + +//---------------getattr-------------------------------------------- +static PyObject *pyrna_struct_getattro( BPy_StructRNA * self, PyObject *pyname ) +{ + char *name = _PyUnicode_AsString(pyname); + PyObject *ret; + PropertyRNA *prop; + + /* 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 + * */ + ret = PyObject_GenericGetAttr((PyObject *)self, pyname); + if (ret) return ret; + else PyErr_Clear(); + /* done with subtypes */ + + prop = RNA_struct_find_property(&self->ptr, name); + + if (prop) { + ret = pyrna_prop_to_py(&self->ptr, prop); + } else { PyErr_Format( PyExc_AttributeError, "Attribute \"%s\" not found", name); ret = NULL; @@ -765,10 +796,10 @@ PyObject *pyrna_prop_iter(BPy_PropertyRNA *self) return NULL; } -/*static struct PyMethodDef pyrna_struct_methods[] = { +static struct PyMethodDef pyrna_struct_methods[] = { {"__dir__", (PyCFunction)pyrna_struct_dir, METH_NOARGS, ""}, {NULL, NULL, 0, NULL} -};*/ +}; static struct PyMethodDef pyrna_prop_methods[] = { {"keys", (PyCFunction)pyrna_prop_keys, METH_NOARGS, ""}, @@ -875,7 +906,7 @@ PyTypeObject pyrna_struct_Type = { NULL, /* iternextfunc tp_iternext; */ /*** Attribute descriptor and subclassing stuff ***/ - NULL, /* struct PyMethodDef *tp_methods; */ + pyrna_struct_methods, /* struct PyMethodDef *tp_methods; */ NULL, /* struct PyMemberDef *tp_members; */ NULL, /* struct PyGetSetDef *tp_getset; */ NULL, /* struct _typeobject *tp_base; */ @@ -990,12 +1021,32 @@ PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr ) { BPy_StructRNA *pyrna; - if (ptr->data==NULL) { + if (ptr->data==NULL && ptr->type==NULL) { Py_RETURN_NONE; } - + +#ifdef PY_CLASS_SUBTYPE pyrna = ( BPy_StructRNA * ) PyObject_NEW( BPy_StructRNA, &pyrna_struct_Type ); - + if (ptr->type && BPy_RNA_PYTYPE(ptr->type)) { + PyTypeObject *tp = BPy_RNA_PYTYPE(ptr->type); + pyrna = (BPy_StructRNA *) tp->tp_alloc(tp, 0); + } + else { + pyrna = ( BPy_StructRNA * ) PyObject_NEW( BPy_StructRNA, &pyrna_struct_Type ); + } + +#else + /* get subtype from RNA struct if its been set */ + PyTypeObject *tp; + if (ptr->type && ptr->type) + tp = BPy_RNA_PYTYPE(ptr->type); + + if (tp==NULL) + tp= &pyrna_struct_Type; + + pyrna = ( BPy_StructRNA * ) PyObject_NEW( BPy_StructRNA, tp ); +#endif + if( !pyrna ) { PyErr_SetString( PyExc_MemoryError, "couldn't create BPy_StructRNA object" ); return NULL; @@ -1029,15 +1080,7 @@ PyObject *BPY_rna_module( void ) { PointerRNA ptr; - if( PyType_Ready( &pyrna_struct_Type ) < 0 ) - return NULL; - - /* This can't be set in the pytype struct because some compilers complain */ - pyrna_prop_Type.tp_getattro = PyObject_GenericGetAttr; - pyrna_prop_Type.tp_setattro = PyObject_GenericSetAttr; - - if( PyType_Ready( &pyrna_prop_Type ) < 0 ) - return NULL; + /* types init moved to BPY_rna_init_types */ /* for now, return the base RNA type rather then a real module */ RNA_main_pointer_create(G.main, &ptr); @@ -1058,4 +1101,203 @@ PyObject *BPY_rna_doc( void ) return pyrna_struct_CreatePyObject(&ptr); } +#ifdef PY_CLASS_SUBTYPE +void BPY_rna_init_types(void) +{ + /* Now initialize new subtypes based on pyrna_struct_Type */ + char tp_name[64]; + PointerRNA ptr; + + CollectionPropertyIterator iter; + PropertyRNA *nameprop, *prop; + char name[256], *nameptr; + + + /* This can't be set in the pytype struct because some compilers complain */ + pyrna_prop_Type.tp_getattro = PyObject_GenericGetAttr; + pyrna_prop_Type.tp_setattro = PyObject_GenericSetAttr; + + if( PyType_Ready( &pyrna_struct_Type ) < 0 ) + return; + + if( PyType_Ready( &pyrna_prop_Type ) < 0 ) + return; + + + /* for now, return the base RNA type rather then a real module */ + RNA_blender_rna_pointer_create(&ptr); + prop = RNA_struct_find_property(&ptr, "structs"); + + RNA_property_collection_begin(&ptr, prop, &iter); + for(; iter.valid; RNA_property_collection_next(&iter)) { + if(iter.ptr.data && (nameprop = RNA_struct_name_property(&iter.ptr))) { + + /* subclass = type(name='myClass', bases=(myBase,), dict={'some':'value'}) */ + PyObject *args = PyTuple_New(3); + PyObject *bases = PyTuple_New(1); + PyObject *dict = PyDict_New(); + PyObject *newclass; + + nameptr= RNA_property_string_get_alloc(&iter.ptr, nameprop, name, sizeof(name)); + snprintf(tp_name, 64, "BPyRNA_%s", nameptr); + + + // arg 1 + PyTuple_SET_ITEM(args, 0, PyUnicode_FromString(tp_name)); + + // arg 2 + PyTuple_SET_ITEM(bases, 0, (PyObject *)&pyrna_struct_Type); + Py_INCREF(&pyrna_struct_Type); + PyTuple_SET_ITEM(args, 1, bases); + + // arg 3 + PyTuple_SET_ITEM(args, 2, dict); // fill with useful subclass things! + + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + } + + newclass = PyObject_CallObject((PyObject *)&PyType_Type, args); + + Py_DECREF(args); + + BPy_RNA_PYTYPE(iter.ptr.data) = (void * )newclass; + + // printf("BPyRNA_PyTypes: %s\n", tp_name); + + if ((char *)&name != nameptr) + MEM_freeN(nameptr); + } + } + RNA_property_collection_end(&iter); +} + +void BPY_rna_free_types(void) {}; + +#else // Other method uses C defined PyTypes + +static void *tp_mem = NULL; +void BPY_rna_init_types(void) +{ + PyTypeObject init_struct_type = pyrna_struct_Type; /* store this type to make copies from */ + + /* Now initialize new subtypes based on pyrna_struct_Type */ + typedef struct PyTypeObject_Name {PyTypeObject tp; char name[64];} PyTypeObject_Name; + PyTypeObject_Name *tp_mem_ptr; + PyTypeObject *tp; + char *tp_name; + PointerRNA ptr; + + CollectionPropertyIterator iter; + PropertyRNA *nameprop, *prop; + char name[256], *nameptr; + + + /* This can't be set in the pytype struct because some compilers complain */ + pyrna_prop_Type.tp_getattro = PyObject_GenericGetAttr; + pyrna_prop_Type.tp_setattro = PyObject_GenericSetAttr; + + if( PyType_Ready( &pyrna_struct_Type ) < 0 ) + return; + + if( PyType_Ready( &pyrna_prop_Type ) < 0 ) + return; + + /* Note, making subtypes could be done by using an equivelent of + class MyClass(RNA_Struct) + */ + + + /* for now, return the base RNA type rather then a real module */ + RNA_blender_rna_pointer_create(&ptr); + prop = RNA_struct_find_property(&ptr, "structs"); + + tp_mem = tp_mem_ptr = MEM_mallocN(sizeof(PyTypeObject_Name) * RNA_property_collection_length(&ptr, prop), "BPyRNA_PyTypes"); + + RNA_property_collection_begin(&ptr, prop, &iter); + for(; iter.valid; RNA_property_collection_next(&iter)) { + if(iter.ptr.data && (nameprop = RNA_struct_name_property(&iter.ptr))) { + + nameptr= RNA_property_string_get_alloc(&iter.ptr, nameprop, name, sizeof(name)); + + //tp = MEM_mallocN(sizeof(PyTypeObject_Name), "pyrna"); + tp = &(tp_mem_ptr->tp); + tp_name = tp_mem_ptr->name; + snprintf(tp_name, 64, "BPyRNA_%s", nameptr); + + + *tp= init_struct_type; /* Copy the uninitialized pyrna_struct_Type */ + tp->tp_name= tp_name; + tp->tp_base= &pyrna_struct_Type; + + /* Todo - add special tp->tp_new function that lets us subtupe rna! */ + + if( PyType_Ready( tp ) < 0 ) { + printf("PyType_Ready failed\n"); + } + + BPy_RNA_PYTYPE(iter.ptr.data) = tp; + + // printf("BPyRNA_PyTypes: %s\n", tp_name); + + if ((char *)&name != nameptr) + MEM_freeN(nameptr); + } + tp_mem_ptr++; + } + RNA_property_collection_end(&iter); +} + +/* Runs after python is finished, dont use any python functions */ +void BPY_rna_free_types(void) +{ + if (tp_mem==NULL) + return; + + /* We dont really have to clear each structs type but may want to, also might allocate each type on its own */ +#if 0 + PointerRNA ptr; + + CollectionPropertyIterator iter; + PropertyRNA *prop; + + /* for now, return the base RNA type rather then a real module */ + RNA_blender_rna_pointer_create(&ptr); + prop = RNA_struct_find_property(&ptr, "structs"); + + RNA_property_collection_begin(&ptr, prop, &iter); + for(; iter.valid; RNA_property_collection_next(&iter)) { + if(iter.ptr.data) { + if (BPy_RNA_PYTYPE(iter.ptr.data)) { + /* + PyTypeObject *tp = BPy_RNA_PYTYPE(iter.ptr.data); + printf("BPyRNA clear: %s %d\n", tp->tp_name, (int)(long)BPy_RNA_PYTYPE(iter.ptr.data)); + */ + + /* May want to alloc each type on its own however this makes it hard to know if RNA subtypes are using the type */ + + /* PyMem_Free( BPy_RNA_PYTYPE(iter.ptr.data) ); + MEM_freeN( BPy_RNA_PYTYPE(iter.ptr.data) ); */ + BPy_RNA_PYTYPE(iter.ptr.data)= NULL; + } + } + } + RNA_property_collection_end(&iter); +#endif + + MEM_freeN( tp_mem ); + tp_mem = NULL; +} +#endif // END PYTYPE COPY METHOD + + + + + + + + + + diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h index fc16ad6ea9a..63a2be9a31a 100644 --- a/source/blender/python/intern/bpy_rna.h +++ b/source/blender/python/intern/bpy_rna.h @@ -36,6 +36,17 @@ extern PyTypeObject pyrna_prop_Type; #define BPy_StructRNA_Check(v) (PyObject_TypeCheck(v, &pyrna_struct_Type)) #define BPy_PropertyRNA_Check(v) (PyObject_TypeCheck(v, &pyrna_prop_Type)) + //XXX add propper accessor function, we know this is just after next/prev pointers + + #define BPy_RNA_PYTYPE( _data ) (((BPy_StructFakeType *)(_data))->py_type) + +typedef struct { + void * _a; + void * _b; + PyTypeObject *py_type; +} BPy_StructFakeType; + + typedef struct { PyObject_HEAD /* required python macro */ PointerRNA ptr; @@ -50,6 +61,9 @@ typedef struct { PyObject *BPY_rna_module( void ); PyObject *BPY_rna_doc( void ); +void BPY_rna_init_types( void ); +void BPY_rna_free_types( void ); + PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr ); PyObject *pyrna_prop_CreatePyObject( PointerRNA *ptr, PropertyRNA *prop ); diff --git a/source/blender/python/intern/bpy_util.c b/source/blender/python/intern/bpy_util.c index 8bdb6334a91..724c99098f4 100644 --- a/source/blender/python/intern/bpy_util.c +++ b/source/blender/python/intern/bpy_util.c @@ -163,7 +163,7 @@ void PyObSpit(char *name, PyObject *var) { } void PyLineSpit(void) { - char filename[512]; + char *filename; int lineno; PyErr_Clear(); |