forked from bartvdbraak/blender
support for defining rna class properties as class attributes
eg: bpy.types.Scene.myprop = BoolProperty() note, this uses an ugly python metaclass, this should be replaced with a C implimentation which is included but commented out, causing crashes in pythons GC which gives no hint as to where the bug comes from.
This commit is contained in:
parent
4eaa10aa02
commit
f4be9a6393
@ -18,6 +18,65 @@
|
||||
|
||||
# <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:
|
||||
print(cls, attr, value)
|
||||
if attr in cls.bl_rna.properties:
|
||||
_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
|
||||
@ -42,6 +101,10 @@ class Context(StructRNA):
|
||||
return new_context
|
||||
|
||||
|
||||
class ID(StructRNA, metaclass=RNA_IDProp_Meta):
|
||||
__slots__ = ()
|
||||
|
||||
|
||||
class Library(bpy_types.ID):
|
||||
__slots__ = ()
|
||||
|
||||
@ -60,7 +123,7 @@ class Library(bpy_types.ID):
|
||||
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):
|
||||
class Texture(bpy_types.ID, metaclass=RNA_IDProp_Meta):
|
||||
__slots__ = ()
|
||||
|
||||
@property
|
||||
@ -257,15 +320,15 @@ class _GenericBone:
|
||||
return bones
|
||||
|
||||
|
||||
class PoseBone(StructRNA, _GenericBone):
|
||||
class PoseBone(StructRNA, _GenericBone, metaclass=RNA_IDProp_Meta):
|
||||
__slots__ = ()
|
||||
|
||||
|
||||
class Bone(StructRNA, _GenericBone):
|
||||
class Bone(StructRNA, _GenericBone, metaclass=RNA_IDProp_Meta):
|
||||
__slots__ = ()
|
||||
|
||||
|
||||
class EditBone(StructRNA, _GenericBone):
|
||||
class EditBone(StructRNA, _GenericBone, metaclass=RNA_IDProp_Meta):
|
||||
__slots__ = ()
|
||||
|
||||
def align_orientation(self, other):
|
||||
@ -617,12 +680,13 @@ class RNAMeta(type):
|
||||
return result
|
||||
|
||||
|
||||
class RNAMetaRegister(RNAMeta):
|
||||
class RNAMetaRegister(RNAMeta, RNA_IDProp_Meta):
|
||||
@classmethod
|
||||
def _register_immediate(cls):
|
||||
return True
|
||||
|
||||
|
||||
|
||||
class OrderedMeta(RNAMeta):
|
||||
|
||||
def __init__(cls, name, bases, attributes):
|
||||
|
@ -50,6 +50,7 @@
|
||||
|
||||
#define USE_MATHUTILS
|
||||
#define USE_STRING_COERCE
|
||||
#define USE_PY_METACLASS
|
||||
|
||||
#ifdef USE_MATHUTILS
|
||||
#include "../generic/mathutils.h" /* so we can have mathutils callbacks */
|
||||
@ -61,6 +62,7 @@ static PyObject *pyrna_prop_array_subscript_slice(BPy_PropertyArrayRNA *self, Po
|
||||
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);
|
||||
|
||||
/* bpyrna vector/euler/quat callbacks */
|
||||
static int mathutils_rna_array_cb_index= -1; /* index for our callbacks */
|
||||
@ -2583,6 +2585,24 @@ static int pyrna_struct_pydict_contains(PyObject *self, PyObject *pyname)
|
||||
#endif
|
||||
|
||||
//--------------- setattr-------------------------------------------
|
||||
|
||||
#ifndef USE_PY_METACLASS
|
||||
static int pyrna_struct_meta_idprop_setattro(PyObject *cls, PyObject *pyname, PyObject *value)
|
||||
{
|
||||
/* 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 -1;
|
||||
}
|
||||
return deferred_register_prop(srna, pyname, value);
|
||||
}
|
||||
else {
|
||||
return PyType_Type.tp_setattro(cls, pyname, value);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int pyrna_struct_setattro( BPy_StructRNA *self, PyObject *pyname, PyObject *value )
|
||||
{
|
||||
char *name = _PyUnicode_AsString(pyname);
|
||||
@ -3742,6 +3762,43 @@ static PyObject * pyrna_func_call(PyObject *self, PyObject *args, PyObject *kw)
|
||||
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 */
|
||||
0, /* tp_itemsize */
|
||||
/* methods */
|
||||
NULL, /* tp_dealloc */
|
||||
NULL, /* printfunc tp_print; */
|
||||
NULL, /* getattrfunc tp_getattr; */
|
||||
NULL, /* setattrfunc tp_setattr; */
|
||||
NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */
|
||||
NULL, /* tp_repr */
|
||||
|
||||
/* Method suites for standard classes */
|
||||
NULL, /* PyNumberMethods *tp_as_number; */
|
||||
NULL, /* PySequenceMethods *tp_as_sequence; */
|
||||
NULL, /* PyMappingMethods *tp_as_mapping; */
|
||||
|
||||
/* More standard operations (here for binary compatibility) */
|
||||
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; */
|
||||
|
||||
/* Functions to access object as input/output buffer */
|
||||
NULL, /* PyBufferProcs *tp_as_buffer; */
|
||||
|
||||
/*** Flags to define presence of optional/expanded features ***/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* long tp_flags; */
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
/*-----------------------BPy_StructRNA method def------------------------------*/
|
||||
PyTypeObject pyrna_struct_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
@ -4199,9 +4256,14 @@ static PyObject* pyrna_srna_PyBase(StructRNA *srna) //, PyObject *bpy_types_dict
|
||||
|
||||
/* 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)
|
||||
{
|
||||
PyObject *bpy_types_dict= NULL;
|
||||
const char *idname= RNA_struct_identifier(srna);
|
||||
PyObject *newclass;
|
||||
|
||||
@ -4214,8 +4276,10 @@ static PyObject* pyrna_srna_ExternalType(StructRNA *srna)
|
||||
fprintf(stderr, "pyrna_srna_ExternalType: failed to find 'bpy_types' module\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef USE_PY_METACLASS
|
||||
bpy_types_dict = PyModule_GetDict(bpy_types); // borrow
|
||||
bpy_types_rna_meta_base = PyDict_GetItemString(bpy_types_dict, BPY_SRNA_IDPROP_META);
|
||||
#endif
|
||||
Py_DECREF(bpy_types); // fairly safe to assume the dict is kept
|
||||
}
|
||||
|
||||
@ -4276,16 +4340,30 @@ static PyObject* pyrna_srna_Subtype(StructRNA *srna)
|
||||
|
||||
/* Assume RNA_struct_py_type_get(srna) was already checked */
|
||||
PyObject *py_base= pyrna_srna_PyBase(srna);
|
||||
|
||||
PyObject *metaclass;
|
||||
const char *idname= RNA_struct_identifier(srna);
|
||||
|
||||
|
||||
/* remove __doc__ for now */
|
||||
// const char *descr= RNA_struct_ui_description(srna);
|
||||
// if(!descr) descr= "(no docs)";
|
||||
// "__doc__",descr
|
||||
|
||||
|
||||
#ifdef USE_PY_METACLASS
|
||||
if(RNA_struct_idprops_check(srna) && !PyObject_IsSubclass(py_base, bpy_types_rna_meta_base)) {
|
||||
metaclass= bpy_types_rna_meta_base;
|
||||
}
|
||||
#else
|
||||
if(RNA_struct_idprops_check(srna) && !PyObject_IsSubclass(py_base, &pyrna_struct_meta_idprop_Type)) {
|
||||
metaclass= (PyObject *)&pyrna_struct_meta_idprop_Type;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
metaclass= (PyObject *)&PyType_Type;
|
||||
}
|
||||
|
||||
/* always use O not N when calling, N causes refcount errors */
|
||||
newclass = PyObject_CallFunction((PyObject*)&PyType_Type, "s(O){sss()}", idname, py_base, "__module__","bpy.types", "__slots__");
|
||||
newclass = PyObject_CallFunction(metaclass, "s(O){sss()}", idname, py_base, "__module__","bpy.types", "__slots__");
|
||||
|
||||
/* newclass will now have 2 ref's, ???, probably 1 is internal since decrefing here segfaults */
|
||||
|
||||
/* PyC_ObSpit("new class ref", newclass); */
|
||||
@ -4299,6 +4377,7 @@ static PyObject* pyrna_srna_Subtype(StructRNA *srna)
|
||||
}
|
||||
else {
|
||||
/* this should not happen */
|
||||
printf("Error registering '%s'\n", idname);
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
@ -4403,7 +4482,14 @@ void BPY_rna_init(void)
|
||||
mathutils_rna_array_cb_index= Mathutils_RegisterCallback(&mathutils_rna_array_cb);
|
||||
mathutils_rna_matrix_cb_index= Mathutils_RegisterCallback(&mathutils_rna_matrix_cb);
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef USE_PY_METACLASS
|
||||
/* metaclass */
|
||||
pyrna_struct_meta_idprop_Type.tp_base= &PyType_Type;
|
||||
if( PyType_Ready( &pyrna_struct_meta_idprop_Type ) < 0 )
|
||||
return;
|
||||
#endif
|
||||
|
||||
if( PyType_Ready( &pyrna_struct_Type ) < 0 )
|
||||
return;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user