forked from bartvdbraak/blender
* removed warnings and fixed some python refcount errors
* operator class names - Changed 'name' to '__label__' (since __name__ is already used for the class name) - Changed 'properties' to '__props__' * added a PyObject_GetAttrStringArgs(), utility function which Id like to see in pythons C api. PyObject_GetAttrStringArgs(pyob, "someattr", "foo", "bar") /* pyob.someattr.foo.bar */
This commit is contained in:
parent
43d4e3fa7e
commit
3aab50f775
@ -264,6 +264,7 @@ int BPY_run_python_script_space(const char *modulename, const char *func)
|
||||
PyErr_SetFormat(PyExc_SystemError, "module has no function '%s.%s'\n", scpt->script.filename, func);
|
||||
}
|
||||
else {
|
||||
Py_DECREF(py_func);
|
||||
if (!PyCallable_Check(py_func)) {
|
||||
PyErr_SetFormat(PyExc_SystemError, "module item is not callable '%s.%s'\n", scpt->script.filename, func);
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ int PYOP_props_from_dict(PointerRNA *ptr, PyObject *kw)
|
||||
static PyObject *pyop_base_dir(PyObject *self);
|
||||
static struct PyMethodDef pyop_base_methods[] = {
|
||||
{"__dir__", (PyCFunction)pyop_base_dir, METH_NOARGS, ""},
|
||||
{"add", (PyCFunction)PYOP_wrap_add, METH_VARARGS, ""},
|
||||
{"add", (PyCFunction)PYOP_wrap_add, METH_O, ""},
|
||||
{"remove", (PyCFunction)PYOP_wrap_remove, METH_O, ""},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
@ -40,6 +40,11 @@
|
||||
#include "bpy_compat.h"
|
||||
#include "bpy_util.h"
|
||||
|
||||
#define PYOP_ATTR_PROP "__props__"
|
||||
#define PYOP_ATTR_UINAME "__label__"
|
||||
#define PYOP_ATTR_IDNAME "__name__" /* use pythons class name */
|
||||
#define PYOP_ATTR_DESCRIPTION "__doc__" /* use pythons docstring */
|
||||
|
||||
typedef struct PyOperatorType {
|
||||
void *next, *prev;
|
||||
char idname[OP_MAX_TYPENAME];
|
||||
@ -316,17 +321,16 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata)
|
||||
|
||||
ot->pyop_data= userdata;
|
||||
|
||||
// TODO - set properties
|
||||
props= PyObject_GetAttrString(py_class, PYOP_ATTR_PROP);
|
||||
|
||||
|
||||
if ((props=PyObject_GetAttrString(py_class, "properties"))) {
|
||||
if (props) {
|
||||
PyObject *dummy_args = PyTuple_New(0);
|
||||
|
||||
int i;
|
||||
|
||||
Py_DECREF(props);
|
||||
|
||||
for(i=0; i<PyList_Size(props); i++) {
|
||||
PyObject *py_func_ptr, *py_kw, *py_srna_cobject, *py_ret;
|
||||
|
||||
item = PyList_GET_ITEM(props, i);
|
||||
|
||||
if (PyArg_ParseTuple(item, "O!O!", &PyCObject_Type, &py_func_ptr, &PyDict_Type, &py_kw)) {
|
||||
@ -360,11 +364,9 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata)
|
||||
|
||||
|
||||
/* pyOperators - Operators defined IN Python */
|
||||
PyObject *PYOP_wrap_add(PyObject *self, PyObject *args)
|
||||
{
|
||||
// XXX ugly - store the Operator type elsewhere!, probably leaks memory
|
||||
PyObject *optype = PyObject_GetAttrString(PyObject_GetAttrString(PyDict_GetItemString(PyEval_GetGlobals(), "bpy"), "types"), "Operator");
|
||||
PyObject *value, *item;
|
||||
PyObject *PYOP_wrap_add(PyObject *self, PyObject *value)
|
||||
{
|
||||
PyObject *optype, *item;
|
||||
|
||||
PyOperatorType *pyot;
|
||||
char *idname= NULL;
|
||||
@ -373,30 +375,37 @@ PyObject *PYOP_wrap_add(PyObject *self, PyObject *args)
|
||||
|
||||
static char *pyop_func_names[] = {"exec", "invoke", "poll", NULL};
|
||||
static int pyop_func_nargs[] = {1, 2, 2, 0};
|
||||
|
||||
PyObject *pyargcount;
|
||||
int i, argcount;
|
||||
|
||||
|
||||
// in python would be...
|
||||
//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);
|
||||
|
||||
int i;
|
||||
int argcount;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O", &value) || !PyObject_IsSubclass(value, optype)) {
|
||||
if (!PyObject_IsSubclass(value, optype)) {
|
||||
PyErr_SetString( PyExc_AttributeError, "expected Operator subclass of bpy.types.Operator");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* class name is used for operator ID - this can be changed later if we want */
|
||||
item = PyObject_GetAttrString(value, "__name__");
|
||||
idname = _PyUnicode_AsString(item);
|
||||
item = PyObject_GetAttrString(value, PYOP_ATTR_IDNAME);
|
||||
Py_DECREF(item);
|
||||
idname = _PyUnicode_AsString(item);
|
||||
|
||||
|
||||
if (WM_operatortype_find(idname)) {
|
||||
PyErr_Format( PyExc_AttributeError, "Operator already exists with this name: %s", idname);
|
||||
PyErr_Format( PyExc_AttributeError, "Operator alredy exists with this name \"%s\"", idname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Operator user readible name */
|
||||
item = PyObject_GetAttrString(value, "name");
|
||||
item = PyObject_GetAttrString(value, PYOP_ATTR_UINAME);
|
||||
if (item) {
|
||||
name = _PyUnicode_AsString(item);
|
||||
Py_DECREF(item);
|
||||
name = _PyUnicode_AsString(item);
|
||||
}
|
||||
if (name == NULL) {
|
||||
name = idname;
|
||||
@ -404,36 +413,37 @@ PyObject *PYOP_wrap_add(PyObject *self, PyObject *args)
|
||||
}
|
||||
|
||||
/* use py docstring for description, should always be None or a string */
|
||||
item = PyObject_GetAttrString(value, "__doc__");
|
||||
item = PyObject_GetAttrString(value, PYOP_ATTR_DESCRIPTION);
|
||||
Py_DECREF(item);
|
||||
|
||||
if (PyUnicode_Check(item)) {
|
||||
description = _PyUnicode_AsString(item);
|
||||
}
|
||||
else {
|
||||
description = "";
|
||||
}
|
||||
Py_DECREF(item);
|
||||
|
||||
/* Check known functions and argument lengths */
|
||||
for (i=0; pyop_func_names[i]; i++) {
|
||||
if ((item=PyObject_GetAttrString(value, pyop_func_names[i]))) {
|
||||
PyObject *pyargcount;
|
||||
|
||||
item=PyObject_GetAttrString(value, pyop_func_names[i]);
|
||||
if (item) {
|
||||
Py_DECREF(item);
|
||||
|
||||
/* check its callable */
|
||||
if (!PyFunction_Check(item)) {
|
||||
PyErr_Format(PyExc_ValueError, "Cant register operator class - %s.%s() is not a function", idname, pyop_func_names[i]);
|
||||
Py_DECREF(item);
|
||||
return NULL;
|
||||
}
|
||||
/* check the number of args is correct */
|
||||
// MyClass.exec.func_code.co_argcount
|
||||
/* MyClass.exec.func_code.co_argcount */
|
||||
|
||||
pyargcount = PyObject_GetAttrString(PyFunction_GetCode(item), "co_argcount");
|
||||
argcount = PyLong_AsSsize_t(pyargcount);
|
||||
pyargcount = PyObject_GetAttrString(PyFunction_GET_CODE(item), "co_argcount");
|
||||
Py_DECREF(pyargcount);
|
||||
argcount = PyLong_AsSsize_t(pyargcount);
|
||||
|
||||
if (argcount != pyop_func_nargs[i]) {
|
||||
PyErr_Format(PyExc_ValueError, "Cant register operator class - %s.%s() takes %d args, should be %d", idname, pyop_func_names[i], argcount, pyop_func_nargs[i]);
|
||||
Py_DECREF(item);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -444,13 +454,12 @@ PyObject *PYOP_wrap_add(PyObject *self, PyObject *args)
|
||||
}
|
||||
|
||||
/* If we have properties set, check its a list of dicts */
|
||||
item = PyObject_GetAttrString(value, "properties");
|
||||
item = PyObject_GetAttrString(value, PYOP_ATTR_PROP);
|
||||
if (item) {
|
||||
int i;
|
||||
Py_DECREF(item);
|
||||
|
||||
if (!PyList_Check(item)) {
|
||||
PyErr_Format(PyExc_ValueError, "Cant register operator class - %s.properties must be a list", idname);
|
||||
Py_DECREF(item);
|
||||
PyErr_Format(PyExc_ValueError, "Cant register operator class - %s.properties must be a list", idname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -460,12 +469,9 @@ PyObject *PYOP_wrap_add(PyObject *self, PyObject *args)
|
||||
|
||||
if (!PyArg_ParseTuple(py_args, "O!O!", &PyCObject_Type, &py_func_ptr, &PyDict_Type, &py_kw)) {
|
||||
PyErr_Format(PyExc_ValueError, "Cant register operator class - %s.properties must contain values from FloatProperty", idname);
|
||||
Py_DECREF(item);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Py_DECREF(item);
|
||||
}
|
||||
else {
|
||||
PyErr_Clear();
|
||||
|
@ -1071,7 +1071,7 @@ PyObject* pyrna_struct_Subtype(PointerRNA *ptr)
|
||||
// Set this later
|
||||
|
||||
if (newclass) {
|
||||
BPy_RNA_PYTYPE(ptr->data) = newclass; /* Store for later use */
|
||||
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 */
|
||||
@ -1198,8 +1198,8 @@ PyObject *BPY_rna_doc( void )
|
||||
if (type) {
|
||||
name = PyObject_GetAttrString(type, "__name__"); /* myClass.__name__ */
|
||||
if (name) {
|
||||
PyDict_SetItem(dict, name, type);
|
||||
Py_DECREF(name);
|
||||
PyDict_SetItem(dict, name, type);
|
||||
}
|
||||
else {
|
||||
printf("could not get type __name__\n");
|
||||
@ -1222,7 +1222,7 @@ PyObject *BPY_rna_doc( void )
|
||||
* This isnt incorrect since its a python object - but be careful */
|
||||
PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
|
||||
{
|
||||
static char *kwlist[] = {"attribute", "name", "description", "min", "max", "soft_min", "soft_max", "default", NULL};
|
||||
static char *kwlist[] = {"attr", "name", "description", "min", "max", "soft_min", "soft_max", "default", NULL};
|
||||
char *id, *name="", *description="";
|
||||
float min=FLT_MIN, max=FLT_MAX, soft_min=FLT_MIN, soft_max=FLT_MAX, def=0.0f;
|
||||
|
||||
@ -1249,7 +1249,7 @@ PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
|
||||
|
||||
PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
|
||||
{
|
||||
static char *kwlist[] = {"attribute", "name", "description", "min", "max", "soft_min", "soft_max", "default", NULL};
|
||||
static char *kwlist[] = {"attr", "name", "description", "min", "max", "soft_min", "soft_max", "default", NULL};
|
||||
char *id, *name="", *description="";
|
||||
int min=INT_MIN, max=INT_MAX, soft_min=INT_MIN, soft_max=INT_MAX, def=0;
|
||||
|
||||
@ -1276,7 +1276,7 @@ PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
|
||||
|
||||
PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
|
||||
{
|
||||
static char *kwlist[] = {"attribute", "name", "description", "default", NULL};
|
||||
static char *kwlist[] = {"attr", "name", "description", "default", NULL};
|
||||
char *id, *name="", *description="";
|
||||
int def=0;
|
||||
|
||||
|
@ -418,7 +418,6 @@ static struct PyMethodDef ui_methods[] = {
|
||||
{"registerKey", (PyCFunction)Method_registerKey, METH_VARARGS, ""}, // XXX could have this in another place too
|
||||
|
||||
|
||||
|
||||
{"getRegonPtr", (PyCFunction)Method_getRegonPtr, METH_NOARGS, ""}, // XXX Nasty, we really need to improve dealing with context!
|
||||
{"getAreaPtr", (PyCFunction)Method_getAreaPtr, METH_NOARGS, ""},
|
||||
{"getScreenPtr", (PyCFunction)Method_getScreenPtr, METH_NOARGS, ""},
|
||||
|
@ -175,39 +175,67 @@ void PyLineSpit(void) {
|
||||
void BPY_getFileAndNum(char **filename, int *lineno)
|
||||
{
|
||||
PyObject *getframe, *frame;
|
||||
PyObject *f_lineno, *f_code, *co_filename;
|
||||
PyObject *f_lineno= NULL, *co_filename= NULL;
|
||||
|
||||
if (filename) *filename= NULL;
|
||||
if (lineno) *lineno = -1;
|
||||
|
||||
getframe = PySys_GetObject("_getframe"); // borrowed
|
||||
if (getframe) {
|
||||
frame = PyObject_CallObject(getframe, NULL);
|
||||
if (frame) {
|
||||
f_lineno= PyObject_GetAttrString(frame, "f_lineno");
|
||||
f_code= PyObject_GetAttrString(frame, "f_code");
|
||||
if (f_lineno && f_code) {
|
||||
co_filename= PyObject_GetAttrString(f_code, "co_filename");
|
||||
if (co_filename) {
|
||||
|
||||
if (filename) *filename = _PyUnicode_AsString(co_filename);
|
||||
if (lineno) *lineno = (int)PyLong_AsSsize_t(f_lineno);
|
||||
|
||||
Py_DECREF(f_lineno);
|
||||
Py_DECREF(f_code);
|
||||
Py_DECREF(co_filename);
|
||||
Py_DECREF(frame);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (getframe==NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
Py_XDECREF(co_filename);
|
||||
Py_XDECREF(f_lineno);
|
||||
Py_XDECREF(f_code);
|
||||
Py_XDECREF(frame);
|
||||
frame = PyObject_CallObject(getframe, NULL);
|
||||
if (frame==NULL)
|
||||
return;
|
||||
|
||||
PyErr_SetString(PyExc_SystemError, "Could not access sys._getframe().f_code.co_filename");
|
||||
if (filename) {
|
||||
co_filename= PyObject_GetAttrStringArgs(frame, 1, "f_code", "co_filename");
|
||||
if (co_filename==NULL) {
|
||||
PyErr_SetString(PyExc_SystemError, "Could not access sys._getframe().f_code.co_filename");
|
||||
Py_DECREF(frame);
|
||||
return;
|
||||
}
|
||||
|
||||
*filename = _PyUnicode_AsString(co_filename);
|
||||
Py_DECREF(co_filename);
|
||||
}
|
||||
|
||||
if (lineno) {
|
||||
f_lineno= PyObject_GetAttrString(frame, "f_lineno");
|
||||
if (f_lineno==NULL) {
|
||||
PyErr_SetString(PyExc_SystemError, "Could not access sys._getframe().f_lineno");
|
||||
Py_DECREF(frame);
|
||||
return;
|
||||
}
|
||||
|
||||
*lineno = (int)PyLong_AsSsize_t(f_lineno);
|
||||
Py_DECREF(f_lineno);
|
||||
}
|
||||
}
|
||||
|
||||
/* Would be nice if python had this built in */
|
||||
PyObject *PyObject_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...)
|
||||
{
|
||||
Py_ssize_t i;
|
||||
PyObject *item= o;
|
||||
char *attr;
|
||||
|
||||
va_list vargs;
|
||||
|
||||
va_start(vargs, n);
|
||||
for (i=0; i<n; i++) {
|
||||
attr = va_arg(vargs, char *);
|
||||
item = PyObject_GetAttrString(item, attr);
|
||||
|
||||
if (item)
|
||||
Py_DECREF(item);
|
||||
else /* python will set the error value here */
|
||||
break;
|
||||
|
||||
}
|
||||
va_end(vargs);
|
||||
|
||||
Py_INCREF(item); /* final value has is increfed, to match PyObject_GetAttrString */
|
||||
return item;
|
||||
}
|
||||
|
@ -37,3 +37,6 @@ int BPY_flag_from_seq(BPY_flag_def *flagdef, PyObject *seq, int *flag);
|
||||
void PyObSpit(char *name, PyObject *var);
|
||||
void PyLineSpit(void);
|
||||
void BPY_getFileAndNum(char **filename, int *lineno);
|
||||
|
||||
/* own python like utility function */
|
||||
PyObject *PyObject_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...);
|
||||
|
Loading…
Reference in New Issue
Block a user