[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [31856] trunk/blender: rewrote python IDProperty metaclass in C, this was a quick hack to get it working.

Campbell Barton ideasman42 at gmail.com
Fri Sep 10 16:54:53 CEST 2010


Revision: 31856
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=31856
Author:   campbellbarton
Date:     2010-09-10 16:54:50 +0200 (Fri, 10 Sep 2010)

Log Message:
-----------
rewrote python IDProperty metaclass in C, this was a quick hack to get it working.

The reason this didnt work is all sibclasses of pythons type() or PyType_Type in C, have to have their size set to sizeof(PyHeapTypeObject) rather then sizeof(PyTypeObject) as you might expect.
This is strange since its not a heap-class (defined in pythons runtime), but a static C type, so Im not sure about this, and cant find any documentation but it seems to work ok.

Modified Paths:
--------------
    trunk/blender/release/scripts/modules/bpy_types.py
    trunk/blender/source/blender/python/intern/bpy.c
    trunk/blender/source/blender/python/intern/bpy_rna.c
    trunk/blender/source/blender/python/intern/bpy_rna.h

Modified: trunk/blender/release/scripts/modules/bpy_types.py
===================================================================
--- trunk/blender/release/scripts/modules/bpy_types.py	2010-09-10 12:46:43 UTC (rev 31855)
+++ trunk/blender/release/scripts/modules/bpy_types.py	2010-09-10 14:54:50 UTC (rev 31856)
@@ -18,70 +18,12 @@
 
 # <pep8 compliant>
 
-
-class RNA_IDProp_Meta(type):
-    # metaclass for all structures which can have rna prop's defined.
-    # important this class is defined first.
-
-    # setattr, so we can do this...
-    # bpy.types.Scene.myprop = bpy.props.BoolProperty()
-    def __setattr__(cls, attr, value):
-        if type(value) == tuple and len(value) == 2:
-            prop = cls.bl_rna.properties.get(attr)
-            if prop and prop.is_runtime:
-                _bpy.props.RemoveProperty(cls, attr=attr)
-            func, kw = value
-            kw["attr"] = attr
-            func(cls, **kw)
-        else:
-            # XXX, pure evil, need to find a better way
-            _setattr = RNA_IDProp_Meta.__setattr__
-            del RNA_IDProp_Meta.__setattr__
-            try:
-                setattr(cls, attr, value)
-            except Exception as exc:
-                RNA_IDProp_Meta.__setattr__ = _setattr
-                raise exc
-            
-            RNA_IDProp_Meta.__setattr__ = _setattr
-
-    def __getattr__(cls, attr):
-        if attr in cls.bl_rna.properties:
-            return cls.bl_rna.properties[attr]
-        elif attr:
-            # XXX, pure evil, need to find a better way
-            _getattr = RNA_IDProp_Meta.__getattr__
-            del RNA_IDProp_Meta.__getattr__
-            try:
-                ret = getattr(cls, attr)
-            except Exception as exc:
-                RNA_IDProp_Meta.__getattr__ = _getattr
-                raise exc
-            
-            RNA_IDProp_Meta.__getattr__ = _getattr
-            return ret
-
-    def __delattr__(cls, attr):
-        if attr in cls.bl_rna.properties:
-            _bpy.props.RemoveProperty(cls, attr=attr)
-        elif attr:
-            # XXX, pure evil, need to find a better way
-            _delattr = RNA_IDProp_Meta.__delattr__
-            del RNA_IDProp_Meta.__delattr__
-            try:
-                delattr(cls, attr, value)
-            except Exception as exc:
-                RNA_IDProp_Meta.__delattr__ = _delattr
-                raise exc
-            
-            RNA_IDProp_Meta.__delattr__ = _delattr
-
-
 from _bpy import types as bpy_types
 import _bpy
 from mathutils import Vector
 
 StructRNA = bpy_types.Struct.__bases__[0]
+StructMetaIDProp = _bpy.StructMetaIDProp
 # StructRNA = bpy_types.Struct
 
 
@@ -101,10 +43,6 @@
         return new_context
 
 
-class ID(StructRNA, metaclass=RNA_IDProp_Meta):
-    __slots__ = ()
-
-
 class Library(bpy_types.ID):
     __slots__ = ()
 
@@ -123,7 +61,7 @@
         return tuple(id_block for attr in attr_links for id_block in getattr(bpy.data, attr) if id_block.library == self)
 
 
-class Texture(bpy_types.ID, metaclass=RNA_IDProp_Meta):
+class Texture(bpy_types.ID):
     __slots__ = ()
 
     @property
@@ -320,15 +258,15 @@
         return bones
 
 
-class PoseBone(StructRNA, _GenericBone, metaclass=RNA_IDProp_Meta):
+class PoseBone(StructRNA, _GenericBone):
     __slots__ = ()
 
 
-class Bone(StructRNA, _GenericBone, metaclass=RNA_IDProp_Meta):
+class Bone(StructRNA, _GenericBone):
     __slots__ = ()
 
 
-class EditBone(StructRNA, _GenericBone, metaclass=RNA_IDProp_Meta):
+class EditBone(StructRNA, _GenericBone):
     __slots__ = ()
 
     def align_orientation(self, other):
@@ -680,13 +618,12 @@
         return result
 
 
-class RNAMetaRegister(RNAMeta, RNA_IDProp_Meta):
+class RNAMetaRegister(RNAMeta, StructMetaIDProp):
     @classmethod
     def _register_immediate(cls):
         return True
 
 
-
 class OrderedMeta(RNAMeta):
 
     def __init__(cls, name, bases, attributes):

Modified: trunk/blender/source/blender/python/intern/bpy.c
===================================================================
--- trunk/blender/source/blender/python/intern/bpy.c	2010-09-10 12:46:43 UTC (rev 31855)
+++ trunk/blender/source/blender/python/intern/bpy.c	2010-09-10 14:54:50 UTC (rev 31856)
@@ -167,6 +167,8 @@
 	BPY_rna_init();
 
 	PyModule_AddObject( mod, "types", BPY_rna_types() ); /* needs to be first so bpy_types can run */
+	PyModule_AddObject(mod, "StructMetaIDProp", (PyObject *)&pyrna_struct_meta_idprop_Type); /* metaclass for idprop types, bpy_types.py needs access */
+			
 	bpy_import_test("bpy_types");
 	PyModule_AddObject( mod, "data", BPY_rna_module() ); /* imports bpy_types by running this */
 	bpy_import_test("bpy_types");

Modified: trunk/blender/source/blender/python/intern/bpy_rna.c
===================================================================
--- trunk/blender/source/blender/python/intern/bpy_rna.c	2010-09-10 12:46:43 UTC (rev 31855)
+++ trunk/blender/source/blender/python/intern/bpy_rna.c	2010-09-10 14:54:50 UTC (rev 31856)
@@ -32,6 +32,7 @@
 #include "float.h" /* FLT_MIN/MAX */
 
 #include "RNA_enum_types.h"
+#include "RNA_define.h" /* RNA_def_property_free_identifier */
 
 #include "MEM_guardedalloc.h"
 #include "BKE_utildefines.h"
@@ -50,7 +51,6 @@
 
 #define USE_MATHUTILS
 #define USE_STRING_COERCE
-#define USE_PY_METACLASS
 
 #ifdef USE_MATHUTILS
 #include "../generic/mathutils.h" /* so we can have mathutils callbacks */
@@ -62,7 +62,7 @@
 static Py_ssize_t pyrna_prop_array_length(BPy_PropertyArrayRNA *self);
 static Py_ssize_t pyrna_prop_collection_length(BPy_PropertyRNA *self);
 static short pyrna_rotation_euler_order_get(PointerRNA *ptr, PropertyRNA **prop_eul_order, short order_fallback);
-static int deferred_register_prop(StructRNA *srna, PyObject *item, PyObject *key);
+static int deferred_register_prop(StructRNA *srna, PyObject *key, PyObject *item);
 
 /* bpyrna vector/euler/quat callbacks */
 static int mathutils_rna_array_cb_index= -1; /* index for our callbacks */
@@ -2587,23 +2587,58 @@
 #endif
 
 //--------------- setattr-------------------------------------------
+static int pyrna_is_deferred_prop(PyObject *value)
+{
+	return PyTuple_CheckExact(value) && PyTuple_GET_SIZE(value)==2 && PyCallable_Check(PyTuple_GET_ITEM(value, 0)) && PyDict_CheckExact(PyTuple_GET_ITEM(value, 1));
+}
 
-#ifndef USE_PY_METACLASS
-static int pyrna_struct_meta_idprop_setattro(PyObject *cls, PyObject *pyname, PyObject *value)
+static PyObject *pyrna_struct_meta_idprop_getattro(PyObject *cls, PyObject *pyname)
 {
-	/* check if the value is a property */
-	if(PyTuple_CheckExact(value) && PyTuple_GET_SIZE(value)==2) { /* weak */
-		StructRNA *srna= srna_from_self(cls, "struct_meta_idprop.setattr()");
-		if(srna==NULL) {
+	return PyType_Type.tp_getattro(cls, pyname);	
+}
+
+static int pyrna_struct_meta_idprop_setattro(PyObject *cls, PyObject *attr, PyObject *value)
+{
+	StructRNA *srna= srna_from_self(cls, "");
+
+	if(srna == NULL) {
+		if(value && pyrna_is_deferred_prop(value)) {
+			PyErr_Format(PyExc_AttributeError, "pyrna_struct_meta_idprop_setattro() unable to get srna from class '%.200s'", ((PyTypeObject *)cls)->tp_name);
 			return -1;
 		}
-		return deferred_register_prop(srna, pyname, value);
+
+		/* srna_from_self may set an error */
+		PyErr_Clear(); 
+		return PyType_Type.tp_setattro(cls, attr, value);
 	}
-	else {
-		return PyType_Type.tp_setattro(cls, pyname, value);	
+
+	if(value) {
+		/* check if the value is a property */
+		if(pyrna_is_deferred_prop(value)) {
+			int ret= deferred_register_prop(srna, attr, value);
+			if(ret < 0)
+				return ret;
+			/* pass through, when the value isn't assigned it still works but gets confusing from script writers POV */
+		}
+		else {
+			/* remove existing property if its set or we also end up with confusement */
+			char *attr_str= _PyUnicode_AsString(attr);
+			RNA_def_property_free_identifier(srna, attr_str); /* ignore on failier */
+		}
 	}
+	else { /* __delattr__ */
+		/* first find if this is a registered property */
+		char *attr_str= _PyUnicode_AsString(attr);
+		int ret= RNA_def_property_free_identifier(srna, attr_str);
+		if (ret == -1) {
+			PyErr_Format(PyExc_TypeError, "struct_meta_idprop.detattr(): '%s' not a dynamic property.", attr_str);
+			return -1;
+		}
+	}
+	
+	/* fallback to standard py, delattr/setattr */
+	return PyType_Type.tp_setattro(cls, attr, value);
 }
-#endif
 		
 static int pyrna_struct_setattro( BPy_StructRNA *self, PyObject *pyname, PyObject *value )
 {
@@ -3750,13 +3785,13 @@
 	Py_RETURN_NONE;
 }
 
-#ifndef USE_PY_METACLASS
+
 /* subclasses of pyrna_struct_Type which support idprop definitions use this as a metaclass */
 /* note: tp_base member is set to &PyType_Type on init */
 PyTypeObject pyrna_struct_meta_idprop_Type = {
 	PyVarObject_HEAD_INIT(NULL, 0)
 	"bpy_struct_meta_idprop",	/* tp_name */
-	sizeof(PyTypeObject),		/* tp_basicsize */
+	sizeof(PyHeapTypeObject),		/* tp_basicsize */ // XXX, would be PyTypeObject, but subtypes of Type must be PyHeapTypeObject's
 	0,							/* tp_itemsize */
 	/* methods */
 	NULL,						/* tp_dealloc */
@@ -3775,8 +3810,8 @@
 	NULL,						/* hashfunc tp_hash; */
 	NULL,						/* ternaryfunc tp_call; */
 	NULL,						/* reprfunc tp_str; */
-	NULL,						/* pyrna_struct_meta_idprop_getattro*/	/* getattrofunc tp_getattro; */
-	NULL /*( setattrofunc ) pyrna_struct_meta_idprop_setattro*/,	/* setattrofunc tp_setattro; */
+	(getattrofunc) pyrna_struct_meta_idprop_getattro,	/* getattrofunc tp_getattro; */
+	(setattrofunc) pyrna_struct_meta_idprop_setattro,	/* setattrofunc tp_setattro; */
 
 	/* Functions to access object as input/output buffer */
 	NULL,                       /* PyBufferProcs *tp_as_buffer; */
@@ -3784,7 +3819,6 @@
   /*** Flags to define presence of optional/expanded features ***/
 	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,         /* long tp_flags; */
 };
-#endif
 
 
 /*-----------------------BPy_StructRNA method def------------------------------*/
@@ -4245,10 +4279,6 @@
 /* check if we have a native python subclass, use it when it exists
  * return a borrowed reference */
 static PyObject *bpy_types_dict= NULL;
-#ifdef USE_PY_METACLASS
-#define BPY_SRNA_IDPROP_META "RNA_IDProp_Meta"
-static PyObject *bpy_types_rna_meta_base= NULL;
-#endif
 
 static PyObject* pyrna_srna_ExternalType(StructRNA *srna)
 {
@@ -4265,9 +4295,6 @@
 			return NULL;
 		}
 		bpy_types_dict = PyModule_GetDict(bpy_types); // borrow
-#ifdef USE_PY_METACLASS
-		bpy_types_rna_meta_base = PyDict_GetItemString(bpy_types_dict, BPY_SRNA_IDPROP_META);

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list