diff options
author | Campbell Barton <ideasman42@gmail.com> | 2009-03-21 09:55:30 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2009-03-21 09:55:30 +0300 |
commit | 6ab2d7ad659606cbf2a315ef9a576c364e6ec9bb (patch) | |
tree | 56250d1706115c5e4fd5aa8157a8dda91b8d950a | |
parent | b4209c56565660c20718fc2e1ad74d4257683a3e (diff) |
- lazy subtype initialization rna, was initializing every type in bpy.types at startup, which is slow and doesn't allow access to dynamically added types.
- bpy.types isnt a module anymore, defined as its own PyType, getattr looks up the rna collection each time.
- refcounting fixes
- fixe epydoc generation with undefined values
-rw-r--r-- | source/blender/python/epy_doc_gen.py | 19 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_operator.c | 27 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_opwrapper.c | 4 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_rna.c | 160 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_rna.h | 3 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_util.c | 2 | ||||
-rw-r--r-- | source/blender/python/rna_dump.py | 78 |
7 files changed, 197 insertions, 96 deletions
diff --git a/source/blender/python/epy_doc_gen.py b/source/blender/python/epy_doc_gen.py index 75d9f88b6db..b6e5a7d0243 100644 --- a/source/blender/python/epy_doc_gen.py +++ b/source/blender/python/epy_doc_gen.py @@ -41,8 +41,6 @@ def get_array_str(length): def rna2epy(target_path): - - def write_struct(rna_struct, structs, ident): identifier = rna_struct.identifier @@ -131,8 +129,11 @@ def rna2epy(target_path): for rna_type_name in dir(bpy.types): rna_type = getattr(bpy.types, rna_type_name) if hasattr(rna_type, '__rna__'): + #if not rna_type_name.startswith('__'): rna_struct = rna_type.__rna__ structs.append( (base_id(rna_struct), rna_struct.identifier, rna_struct) ) + else: + print("Ignoring", rna_type_name) @@ -160,7 +161,7 @@ def rna2epy(target_path): i+=1 if not ok: - print('Dependancy "%s"could not be found for "%s"' % (identifier, rna_base)) + print('Dependancy "%s" could not be found for "%s"' % (identifier, rna_base)) break @@ -199,7 +200,9 @@ def op2epy(target_path): kw_args = [] # "foo = 1", "bar=0.5", "spam='ENUM'" kw_arg_attrs = [] # "@type mode: int" - rna = getattr(bpy.types, op).__rna__ + # rna = getattr(bpy.types, op).__rna__ + rna = bpy.ops.__rna__(op) + rna_struct = rna.rna_type # print (dir(rna)) # print (dir(rna_struct)) @@ -217,14 +220,18 @@ def op2epy(target_path): try: val = getattr(rna, rna_prop_identifier) + val_error = False except: - val = '<UNDEFINED>' + val = "'<UNDEFINED>'" + val_error = True kw_type_str= "@type %s: %s%s" % (rna_prop_identifier, rna_prop_type, array_str) kw_param_str= "@param %s: %s" % (rna_prop_identifier, rna_prop.description) kw_param_set = False - if rna_prop_type=='float': + if val_error: + val_str = val + elif rna_prop_type=='float': if length==0: val_str= '%g' % val if '.' not in val_str: diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index a35c5ed2cb4..b40d4640bcb 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -108,8 +108,10 @@ int PYOP_props_from_dict(PointerRNA *ptr, PyObject *kw) } static PyObject *pyop_base_dir(PyObject *self); +static PyObject *pyop_base_rna(PyObject *self, PyObject *pyname); static struct PyMethodDef pyop_base_methods[] = { {"__dir__", (PyCFunction)pyop_base_dir, METH_NOARGS, ""}, + {"__rna__", (PyCFunction)pyop_base_rna, METH_O, ""}, {"add", (PyCFunction)PYOP_wrap_add, METH_O, ""}, {"remove", (PyCFunction)PYOP_wrap_remove, METH_O, ""}, {NULL, NULL, 0, NULL} @@ -199,8 +201,9 @@ static PyObject *pyop_base_getattro( BPy_OperatorBase * self, PyObject *pyname ) { char *name = _PyUnicode_AsString(pyname); PyObject *ret; + wmOperatorType *ot; - if ((WM_operatortype_find(name))) { + if ((ot= WM_operatortype_find(name))) { ret = PyCFunction_New( pyop_base_call_meth, pyname); /* set the name string as self, PyCFunction_New incref's self */ } else if ((ret = PyObject_GenericGetAttr((PyObject *)self, pyname))) { @@ -235,6 +238,28 @@ static PyObject *pyop_base_dir(PyObject *self) return list; } +static PyObject *pyop_base_rna(PyObject *self, PyObject *pyname) +{ + char *name = _PyUnicode_AsString(pyname); + wmOperatorType *ot; + + if ((ot= WM_operatortype_find(name))) { + BPy_StructRNA *pyrna; + PointerRNA ptr; + + /* XXX POINTER - if this 'ot' is python generated, it could be free'd */ + 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 pyrna; + } + else { + PyErr_SetString(PyExc_AttributeError, "Operator not found"); + return NULL; + } +} + PyTypeObject pyop_base_Type = {NULL}; PyObject *BPY_operator_module( bContext *C ) diff --git a/source/blender/python/intern/bpy_opwrapper.c b/source/blender/python/intern/bpy_opwrapper.c index 379fda35bb6..b7d4c82588e 100644 --- a/source/blender/python/intern/bpy_opwrapper.c +++ b/source/blender/python/intern/bpy_opwrapper.c @@ -384,7 +384,8 @@ PyObject *PYOP_wrap_add(PyObject *self, PyObject *value) //PyObject *optype = PyObject_GetAttrString(PyObject_GetAttrString(PyDict_GetItemString(PyEval_GetGlobals(), "bpy"), "types"), "Operator"); optype = PyObject_GetAttrStringArgs(PyDict_GetItemString(PyEval_GetGlobals(), "bpy"), 2, "types", "Operator"); Py_DECREF(optype); - + + if (!PyObject_IsSubclass(value, optype)) { PyErr_SetString( PyExc_AttributeError, "expected Operator subclass of bpy.types.Operator"); return NULL; @@ -450,7 +451,6 @@ PyObject *PYOP_wrap_add(PyObject *self, PyObject *value) } else { PyErr_Clear(); } - Py_XDECREF(item); } /* If we have properties set, check its a list of dicts */ diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index ca65eee0c6f..8f08ce6308d 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -574,21 +574,27 @@ static PyMappingMethods pyrna_prop_as_mapping = { static PyObject *pyrna_struct_dir(BPy_StructRNA * self) { PyObject *ret, *dict; - PyObject *pystring = PyUnicode_FromString("__dict__"); + PyObject *pystring; /* 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 * */ - dict = PyObject_GenericGetAttr((PyObject *)self, pystring); - Py_DECREF(pystring); - - if (dict==NULL) { - PyErr_Clear(); + + if (BPy_StructRNA_CheckExact(self)) { ret = PyList_New(0); - } - else { - ret = PyDict_Keys(dict); - Py_DECREF(dict); + } else { + pystring = PyUnicode_FromString("__dict__"); + dict = PyObject_GenericGetAttr((PyObject *)self, pystring); + Py_DECREF(pystring); + + if (dict==NULL) { + PyErr_Clear(); + ret = PyList_New(0); + } + else { + ret = PyDict_Keys(dict); + Py_DECREF(dict); + } } /* Collect RNA items*/ @@ -629,12 +635,12 @@ static PyObject *pyrna_struct_getattro( BPy_StructRNA * self, PyObject *pyname ) /* 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 * */ - if (BPy_StructRNA_CheckExact(self) == 0) { - ret = PyObject_GenericGetAttr((PyObject *)self, pyname); - if (ret) return ret; - else PyErr_Clear(); - } + ret = PyObject_GenericGetAttr((PyObject *)self, pyname); + if (ret) return ret; + else PyErr_Clear(); /* done with subtypes */ prop = RNA_struct_find_property(&self->ptr, name); @@ -1061,6 +1067,8 @@ PyObject* pyrna_struct_Subtype(PointerRNA *ptr) if (ptr->type==NULL) { newclass= NULL; /* Nothing to do */ + } else if ((newclass= BPy_RNA_PYTYPE(ptr->data))) { + Py_INCREF(newclass); } else if ((nameprop = RNA_struct_name_property(ptr))) { /* for now, return the base RNA type rather then a real module */ @@ -1076,7 +1084,6 @@ PyObject* pyrna_struct_Subtype(PointerRNA *ptr) PyObject *args = PyTuple_New(3); PyObject *bases = PyTuple_New(1); PyObject *dict = PyDict_New(); - PyObject *rna; nameptr= RNA_property_string_get_alloc(ptr, nameprop, name, sizeof(name)); @@ -1087,6 +1094,7 @@ PyObject* pyrna_struct_Subtype(PointerRNA *ptr) // arg 2 PyTuple_SET_ITEM(bases, 0, (PyObject *)&pyrna_struct_Type); Py_INCREF(&pyrna_struct_Type); + PyTuple_SET_ITEM(args, 1, bases); // arg 3 - add an instance of the rna @@ -1100,9 +1108,11 @@ PyObject* pyrna_struct_Subtype(PointerRNA *ptr) newclass = PyObject_CallObject((PyObject *)&PyType_Type, args); // Set this later + if (newclass) { + PyObject *rna; BPy_RNA_PYTYPE(ptr->data) = (void *)newclass; /* Store for later use */ - + /* Not 100% needed but useful, * having an instance within a type looks wrong however this instance IS an rna type */ rna = pyrna_struct_CreatePyObject(ptr); @@ -1110,6 +1120,7 @@ PyObject* pyrna_struct_Subtype(PointerRNA *ptr) Py_DECREF(rna); /* done with rna instance */ } + Py_DECREF(args); if ((char *)&name != nameptr) @@ -1123,15 +1134,23 @@ PyObject* pyrna_struct_Subtype(PointerRNA *ptr) /*-----------------------CreatePyObject---------------------------------*/ PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr ) { - BPy_StructRNA *pyrna; + BPy_StructRNA *pyrna= NULL; + int tp_init= 0; if (ptr->data==NULL && ptr->type==NULL) { /* Operator RNA has NULL data */ Py_RETURN_NONE; } - if (ptr->type && BPy_RNA_PYTYPE(ptr->type)) { - PyTypeObject *tp = BPy_RNA_PYTYPE(ptr->type); - pyrna = (BPy_StructRNA *) tp->tp_alloc(tp, 0); + if (ptr->type == &RNA_Struct) { /* always return a python subtype from rna struct types */ + PyTypeObject *tp = pyrna_struct_Subtype(ptr); + + if (tp) { + pyrna = (BPy_StructRNA *) tp->tp_alloc(tp, 0); + } + else { + fprintf(stderr, "Could not make type\n"); + pyrna = ( BPy_StructRNA * ) PyObject_NEW( BPy_StructRNA, &pyrna_struct_Type ); + } } else { pyrna = ( BPy_StructRNA * ) PyObject_NEW( BPy_StructRNA, &pyrna_struct_Type ); @@ -1144,7 +1163,6 @@ PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr ) pyrna->ptr= *ptr; pyrna->freeptr= 0; - return ( PyObject * ) pyrna; } @@ -1201,51 +1219,75 @@ PyObject *BPY_rna_doc( void ) } #endif - PyObject *BPY_rna_types(void) - { - /* Now initialize new subtypes based on pyrna_struct_Type */ - PointerRNA ptr; - CollectionPropertyIterator iter; - PropertyRNA *prop; +/* pyrna_basetype_* - BPy_BaseTypeRNA is just a BPy_PropertyRNA struct with a differnt type + * the self->ptr and self->prop are always set to the "structs" collection */ +//---------------getattr-------------------------------------------- +static PyObject *pyrna_basetype_getattro( BPy_BaseTypeRNA * self, PyObject *pyname ) +{ + 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)) { + return pyrna_struct_Subtype(&newptr); + } + else { /* Override the error */ + PyErr_Format(PyExc_AttributeError, "bpy.types.%s not a valid RNA_Struct", _PyUnicode_AsString(pyname)); + return NULL; + } +} + +static PyObject *pyrna_basetype_dir(BPy_BaseTypeRNA *self); +static struct PyMethodDef pyrna_basetype_methods[] = { + {"__dir__", (PyCFunction)pyrna_basetype_dir, METH_NOARGS, ""}, + {NULL, NULL, 0, NULL} +}; - PyObject *mod, *dict, *type, *name; - - mod = PyModule_New("types"); - dict = PyModule_GetDict(mod); +static PyObject *pyrna_basetype_dir(BPy_BaseTypeRNA *self) +{ + PyObject *list, *name; + PyMethodDef *meth; - /* 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) { - type = (PyObject *)BPy_RNA_PYTYPE(iter.ptr.data); - if (type==NULL) { - type = pyrna_struct_Subtype(&iter.ptr); - } - if (type) { - name = PyObject_GetAttrString(type, "__name__"); /* myClass.__name__ */ - if (name) { - Py_DECREF(name); - PyDict_SetItem(dict, name, type); - } - else { - printf("could not get type __name__\n"); - } - } - else { - printf("could not generate type\n"); - } - } + list= pyrna_prop_keys(self); /* like calling structs.keys(), avoids looping here */ + + for(meth=pyrna_basetype_methods; meth->ml_name; meth++) { + name = PyUnicode_FromString(meth->ml_name); + PyList_Append(list, name); + Py_DECREF(name); } - RNA_property_collection_end(&iter); - return mod; + return list; +} + +PyTypeObject pyrna_basetype_Type = {NULL}; + +PyObject *BPY_rna_types(void) +{ + BPy_BaseTypeRNA *self; + pyrna_basetype_Type.tp_name = "RNA_Types"; + pyrna_basetype_Type.tp_basicsize = sizeof( BPy_BaseTypeRNA ); + pyrna_basetype_Type.tp_getattro = ( getattrofunc )pyrna_basetype_getattro; + pyrna_basetype_Type.tp_flags = Py_TPFLAGS_DEFAULT; + pyrna_basetype_Type.tp_methods = pyrna_basetype_methods; + + if( PyType_Ready( &pyrna_basetype_Type ) < 0 ) + return NULL; + + self= (BPy_BaseTypeRNA *)PyObject_NEW( BPy_BaseTypeRNA, &pyrna_basetype_Type ); + + /* avoid doing this lookup for every getattr */ + RNA_blender_rna_pointer_create(&self->ptr); + self->prop = RNA_struct_find_property(&self->ptr, "structs"); + + return (PyObject *)self; } + /* Orphan functions, not sure where they should go */ /* Function that sets RNA, NOTE - self is NULL when called from python, but being abused from C so we can pass the srna allong diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h index 904529b58de..878b2a7d17a 100644 --- a/source/blender/python/intern/bpy_rna.h +++ b/source/blender/python/intern/bpy_rna.h @@ -61,6 +61,9 @@ typedef struct { PropertyRNA *prop; } BPy_PropertyRNA; +/* cheap trick */ +#define BPy_BaseTypeRNA BPy_PropertyRNA + PyObject *BPY_rna_module( void ); /*PyObject *BPY_rna_doc( void );*/ PyObject *BPY_rna_types( void ); diff --git a/source/blender/python/intern/bpy_util.c b/source/blender/python/intern/bpy_util.c index 47ac739eac0..ce307b5d8ac 100644 --- a/source/blender/python/intern/bpy_util.c +++ b/source/blender/python/intern/bpy_util.c @@ -236,6 +236,6 @@ PyObject *PyObject_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...) } va_end(vargs); - Py_INCREF(item); /* final value has is increfed, to match PyObject_GetAttrString */ + Py_XINCREF(item); /* final value has is increfed, to match PyObject_GetAttrString */ return item; } diff --git a/source/blender/python/rna_dump.py b/source/blender/python/rna_dump.py index f587cd983b2..66fb76c35aa 100644 --- a/source/blender/python/rna_dump.py +++ b/source/blender/python/rna_dump.py @@ -18,20 +18,41 @@ # # #**** END GPL LICENSE BLOCK #**** +if 1: + # Print once every 1000 + GEN_PATH = True + PRINT_DATA = False + PRINT_DATA_INT = 1000 + VERBOSE = False + VERBOSE_TYPE = False + MAX_RECURSIVE = 8 +else: + # Print everything + GEN_PATH = True + PRINT_DATA = True + PRINT_DATA_INT = 0 + VERBOSE = False + VERBOSE_TYPE = False + MAX_RECURSIVE = 8 -PRINT_DATA = True -VERBOSE = False -VERBOSE_TYPE = False -SKIP_RECURSIVE = False +seek_count = [0] - -def seek(r, txt): - print(txt) +def seek(r, txt, recurs): + + seek_count[0] += 1 + + if PRINT_DATA_INT: + if not (seek_count[0] % PRINT_DATA_INT): + print(seek_count[0], txt) + + if PRINT_DATA: + print(txt) + newtxt = '' - if len(txt) > 200: - print ("Somthing is wrong") - print (txt) + if recurs > MAX_RECURSIVE: + #print ("Recursion is over max") + #print (txt) return type_r = type(r) @@ -64,27 +85,21 @@ def seek(r, txt): if item.startswith('__'): continue - if PRINT_DATA: newtxt = txt + '.' + item + if GEN_PATH: newtxt = txt + '.' + item if item == 'rna_type' and VERBOSE_TYPE==False: # just avoid because it spits out loads of data continue - if SKIP_RECURSIVE: - if item in txt: - if PRINT_DATA: - print(newtxt + ' - (skipping to avoid recursive search)') - continue - try: value = getattr(r, item) except: value = None - seek( value, newtxt) + seek( value, newtxt, recurs + 1) if keys: for k in keys: - if PRINT_DATA: newtxt = txt + '["' + k + '"]' - seek(r.__getitem__(k), newtxt) + if GEN_PATH: newtxt = txt + '["' + k + '"]' + seek(r.__getitem__(k), newtxt, recurs+1) else: try: length = len( r ) @@ -96,17 +111,26 @@ def seek(r, txt): if PRINT_DATA: print((' '*len(txt)) + ' ... skipping '+str(length-2)+' items ...') - if PRINT_DATA: newtxt = txt + '[' + str(i) + ']' - seek(r[i], newtxt) + if GEN_PATH: newtxt = txt + '[' + str(i) + ']' + seek(r[i], newtxt, recurs+1) else: for i in range(length): - if PRINT_DATA: newtxt = txt + '[' + str(i) + ']' - seek(r[i], newtxt) - -#print (dir(bpy)) -seek(bpy.data, 'bpy.data') + if GEN_PATH: newtxt = txt + '[' + str(i) + ']' + seek(r[i], newtxt, recurs+1) +seek(bpy.data, 'bpy.data', 0) +# seek(bpy.types, 'bpy.types', 0) +''' +for d in dir(bpy.types): + t = getattr(bpy.types, d) + try: r = t.__rna__ + except: r = None + if r: + seek(r, 'bpy.types.' + d + '.__rna__', 0) +''' #print dir(bpy) #import sys #sys.exit() + +print("iter over ", seek_count, "rna items") |