- lazy subtype initialization rna, was initializing every type in bpy.types at startu...
authorCampbell Barton <ideasman42@gmail.com>
Sat, 21 Mar 2009 06:55:30 +0000 (06:55 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Sat, 21 Mar 2009 06:55:30 +0000 (06:55 +0000)
- 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

source/blender/python/epy_doc_gen.py
source/blender/python/intern/bpy_operator.c
source/blender/python/intern/bpy_opwrapper.c
source/blender/python/intern/bpy_rna.c
source/blender/python/intern/bpy_rna.h
source/blender/python/intern/bpy_util.c
source/blender/python/rna_dump.py

index 75d9f88b6db1b29dbe7fa53aa200ef17fb7177d6..b6e5a7d024355da21c869aeedcfb74da1732000e 100644 (file)
@@ -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:
index a35c5ed2cb4e4ddd133451638083136c2d895829..b40d4640bcb03319303b4c5fb72bdca1e6bfdda7 100644 (file)
@@ -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 )
index 379fda35bb6ec423e088133449261e870de4c8b6..b7d4c82588e37789359f6d94dcea12ba7a65f564 100644 (file)
@@ -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 */
index ca65eee0c6f3fe6f52bebd998b01ad3d559b884f..8f08ce6308d2986dcacfd50392a716236170b917 100644 (file)
@@ -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
index 904529b58de05c45756957952cd04418a9d8ab06..878b2a7d17ae25cb8297ebb0dd64290679a0e45d 100644 (file)
@@ -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 );
index 47ac739eac0dbe0149d1d69936a2da4c4d0a7e44..ce307b5d8ac8ce1ac11a597478bc12e3afdfb836 100644 (file)
@@ -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;
 }
index f587cd983b2abf597fda43d79bd1bf8e89da6aea..66fb76c35aa00fc9354cd4bdf48112204dac5fd5 100644 (file)
  #
  # #**** 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")