2.5 Python

Merging changes made by Arystanbek in the soc-2009-kazanbas branch,
plus some things modified and added by me.

* Operator exec is called execute in python now, due to conflicts
  with python exec keyword.
* Operator invoke/execute now get context argument.
* Fix crash executing operators due to bpy_import_main_set not being
  set with Main pointer.
* The bpy.props module now has the FloatProperty/IntProperty/
  StringProperty/BoolProperty functions to define RNA properties for
  operators.
* Operators now have an __operator__ property to get the actual RNA
  operator pointers, this is only temporary though.
* bpy.ops.add now allows the operator to be already registered, it
  will simply overwrite the existing one.
* Both the ui and io directories are now scanned and run on startup.
This commit is contained in:
Brecht Van Lommel
2009-06-18 19:51:22 +00:00
parent 4cd24cf058
commit 94dbb3bbdd
6 changed files with 197 additions and 85 deletions

View File

@@ -468,25 +468,15 @@ if env['OURPLATFORM']!='darwin':
dotblenderinstall.append(env.Install(dir=td, source=srcfile))
if env['WITH_BF_PYTHON']:
#-- .blender/scripts
scriptpath='release/scripts'
#-- .blender/scripts, .blender/ui, .blender/io
scriptpaths=['release/scripts', 'release/ui', 'release/io']
for scriptpath in scriptpaths:
for dp, dn, df in os.walk(scriptpath):
if 'CVS' in dn:
dn.remove('CVS')
if '.svn' in dn:
dn.remove('.svn')
dir=env['BF_INSTALLDIR']+'/.blender/scripts'+dp[len(scriptpath):]
source=[dp+os.sep+f for f in df]
scriptinstall.append(env.Install(dir=dir,source=source))
#-- .blender/ui
scriptpath='release/ui'
for dp, dn, df in os.walk(scriptpath):
if 'CVS' in dn:
dn.remove('CVS')
if '.svn' in dn:
dn.remove('.svn')
dir=env['BF_INSTALLDIR']+'/.blender/ui'+dp[len(scriptpath):]
dir=env['BF_INSTALLDIR']+'/.blender/'+os.path.basename(scriptpath)+dp[len(scriptpath):]
source=[dp+os.sep+f for f in df]
scriptinstall.append(env.Install(dir=dir,source=source))

View File

@@ -59,6 +59,7 @@ static void bpy_init_modules( void )
PyModule_AddObject( mod, "data", BPY_rna_module() );
/* PyModule_AddObject( mod, "doc", BPY_rna_doc() ); */
PyModule_AddObject( mod, "types", BPY_rna_types() );
PyModule_AddObject( mod, "props", BPY_rna_props() );
PyModule_AddObject( mod, "ops", BPY_operator_module() );
PyModule_AddObject( mod, "ui", BPY_ui_module() ); // XXX very experemental, consider this a test, especially PyCObject is not meant to be perminant
@@ -103,6 +104,7 @@ static PyObject *CreateGlobalDictionary( bContext *C )
{"FloatProperty", (PyCFunction)BPy_FloatProperty, METH_VARARGS|METH_KEYWORDS, ""},
{"IntProperty", (PyCFunction)BPy_IntProperty, METH_VARARGS|METH_KEYWORDS, ""},
{"BoolProperty", (PyCFunction)BPy_BoolProperty, METH_VARARGS|METH_KEYWORDS, ""},
{"StringProperty", (PyCFunction)BPy_StringProperty, METH_VARARGS|METH_KEYWORDS, ""},
{NULL, NULL, 0, NULL}
};
@@ -369,24 +371,32 @@ void BPY_run_ui_scripts(bContext *C, int reload)
DIR *dir;
struct dirent *de;
char *file_extension;
char *dirname;
char path[FILE_MAX];
char *dirname= BLI_gethome_folder("ui");
int filelen; /* filename length */
char *dirs[] = {"io", "ui", NULL};
int a, filelen; /* filename length */
PyGILState_STATE gilstate;
PyObject *mod;
PyObject *sys_path_orig;
PyObject *sys_path_new;
gilstate = PyGILState_Ensure();
// XXX - evil, need to access context
BPy_SetContext(C);
bpy_import_main_set(CTX_data_main(C));
for(a=0; dirs[a]; a++) {
dirname= BLI_gethome_folder(dirs[a]);
if(!dirname)
return;
continue;
dir = opendir(dirname);
if(!dir)
return;
gilstate = PyGILState_Ensure();
continue;
/* backup sys.path */
sys_path_orig= PySys_GetObject("path");
@@ -397,10 +407,6 @@ void BPY_run_ui_scripts(bContext *C, int reload)
PySys_SetObject("path", sys_path_new);
Py_DECREF(sys_path_new);
// XXX - evil, need to access context
BPy_SetContext(C);
bpy_import_main_set(CTX_data_main(C));
while((de = readdir(dir)) != NULL) {
/* We could stat the file but easier just to let python
* import it and complain if theres a problem */
@@ -426,6 +432,7 @@ void BPY_run_ui_scripts(bContext *C, int reload)
BPy_errors_to_report(NULL); // TODO - reports
fprintf(stderr, "unable to import \"%s\" %s/%s\n", path, dirname, de->d_name);
}
}
}
@@ -433,6 +440,7 @@ void BPY_run_ui_scripts(bContext *C, int reload)
PySys_SetObject("path", sys_path_orig);
Py_DECREF(sys_path_orig);
}
bpy_import_main_set(NULL);

View File

@@ -40,6 +40,8 @@
#include "bpy_compat.h"
#include "bpy_util.h"
#include "../generic/bpy_internal_import.h" // our own imports
#define PYOP_ATTR_PROP "__props__"
#define PYOP_ATTR_UINAME "__label__"
#define PYOP_ATTR_IDNAME "__name__" /* use pythons class name */
@@ -177,10 +179,13 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
PyObject *ret= NULL, *py_class_instance, *item= NULL;
int ret_flag= (mode==PYOP_POLL ? 0:OPERATOR_CANCELLED);
PointerRNA ptr_context;
PyObject *py_context;
PointerRNA ptr_operator;
PyObject *py_operator;
PyGILState_STATE gilstate = PyGILState_Ensure();
bpy_import_main_set(CTX_data_main(C));
BPY_update_modules(); // XXX - the RNA pointers can change so update before running, would like a nicer solutuon for this.
args = PyTuple_New(1);
@@ -214,19 +219,28 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
RNA_property_collection_end(&iter);
}
/* set operator pointer RNA as instance "__operator__" attribute */
RNA_pointer_create(NULL, &RNA_Operator, op, &ptr_operator);
py_operator= pyrna_struct_CreatePyObject(&ptr_operator);
PyObject_SetAttrString(py_class_instance, "__operator__", py_operator);
Py_DECREF(py_operator);
RNA_pointer_create(NULL, &RNA_Context, C, &ptr_context);
if (mode==PYOP_INVOKE) {
item= PyObject_GetAttrString(py_class, "invoke");
args = PyTuple_New(2);
PyTuple_SET_ITEM(args, 1, pyop_dict_from_event(event));
args = PyTuple_New(3);
// PyTuple_SET_ITEM "steals" object reference, it is
// an object passed shouldn't be DECREF'ed
PyTuple_SET_ITEM(args, 1, pyrna_struct_CreatePyObject(&ptr_context));
PyTuple_SET_ITEM(args, 2, pyop_dict_from_event(event));
}
else if (mode==PYOP_EXEC) {
item= PyObject_GetAttrString(py_class, "exec");
item= PyObject_GetAttrString(py_class, "execute");
args = PyTuple_New(2);
RNA_pointer_create(NULL, &RNA_Context, C, &ptr_context);
py_context = pyrna_struct_CreatePyObject(&ptr_context);
PyTuple_SET_ITEM(args, 1, py_context);
PyTuple_SET_ITEM(args, 1, pyrna_struct_CreatePyObject(&ptr_context));
}
else if (mode==PYOP_POLL) {
item= PyObject_GetAttrString(py_class, "poll");
@@ -259,6 +273,7 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
/* the returned value could not be converted into a flag */
BPy_errors_to_report(op->reports);
ret_flag = OPERATOR_CANCELLED;
}
/* there is no need to copy the py keyword dict modified by
* pyot->py_invoke(), back to the operator props since they are just
@@ -271,7 +286,34 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
Py_DECREF(ret);
}
/* print operator return value */
if (mode != PYOP_POLL) {
char flag_str[100];
char class_name[100];
BPY_flag_def *flag_def = pyop_ret_flags;
strcpy(flag_str, "");
while(flag_def->name) {
if (ret_flag & flag_def->flag) {
if(flag_str[1])
sprintf(flag_str, "%s | %s", flag_str, flag_def->name);
else
strcpy(flag_str, flag_def->name);
}
flag_def++;
}
/* get class name */
item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME);
Py_DECREF(item);
strcpy(class_name, _PyUnicode_AsString(item));
fprintf(stderr, "%s's %s returned %s\n", class_name, mode == PYOP_EXEC ? "execute" : "invoke", flag_str);
}
PyGILState_Release(gilstate);
bpy_import_main_set(NULL);
return ret_flag;
}
@@ -321,7 +363,7 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata)
/* api callbacks, detailed checks dont on adding */
if (PyObject_HasAttrString(py_class, "invoke"))
ot->invoke= PYTHON_OT_invoke;
if (PyObject_HasAttrString(py_class, "exec"))
if (PyObject_HasAttrString(py_class, "execute"))
ot->exec= PYTHON_OT_exec;
if (PyObject_HasAttrString(py_class, "poll"))
ot->poll= PYTHON_OT_poll;
@@ -374,6 +416,7 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata)
PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class)
{
PyObject *base_class, *item;
wmOperatorType *ot;
char *idname= NULL;
@@ -384,8 +427,8 @@ PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class)
{PYOP_ATTR_UINAME, 's', 0, BPY_CLASS_ATTR_OPTIONAL},
{PYOP_ATTR_PROP, 'l', 0, BPY_CLASS_ATTR_OPTIONAL},
{PYOP_ATTR_DESCRIPTION, 's', 0, BPY_CLASS_ATTR_NONE_OK},
{"exec", 'f', 2, BPY_CLASS_ATTR_OPTIONAL},
{"invoke", 'f', 2, BPY_CLASS_ATTR_OPTIONAL},
{"execute", 'f', 2, BPY_CLASS_ATTR_OPTIONAL},
{"invoke", 'f', 3, BPY_CLASS_ATTR_OPTIONAL},
{"poll", 'f', 2, BPY_CLASS_ATTR_OPTIONAL},
{NULL, 0, 0, 0}
};
@@ -404,9 +447,10 @@ PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class)
Py_DECREF(item);
idname = _PyUnicode_AsString(item);
if (WM_operatortype_find(idname)) {
PyErr_Format( PyExc_AttributeError, "Operator alredy exists with this name \"%s\"", idname);
return NULL;
/* remove if it already exists */
if ((ot=WM_operatortype_find(idname))) {
Py_XDECREF((PyObject*)ot->pyop_data);
WM_operatortype_remove(idname);
}
/* If we have properties set, check its a list of dicts */

View File

@@ -1760,7 +1760,44 @@ PyObject *BPY_rna_types(void)
return (PyObject *)self;
}
static struct PyMethodDef props_methods[] = {
{"FloatProperty", (PyCFunction)BPy_FloatProperty, METH_VARARGS|METH_KEYWORDS, ""},
{"IntProperty", (PyCFunction)BPy_IntProperty, METH_VARARGS|METH_KEYWORDS, ""},
{"BoolProperty", (PyCFunction)BPy_BoolProperty, METH_VARARGS|METH_KEYWORDS, ""},
{"StringProperty", (PyCFunction)BPy_StringProperty, METH_VARARGS|METH_KEYWORDS, ""},
{NULL, NULL, 0, NULL}
};
#if PY_VERSION_HEX >= 0x03000000
static struct PyModuleDef props_module = {
PyModuleDef_HEAD_INIT,
"bpyprops",
"",
-1,/* multiple "initialization" just copies the module dict. */
props_methods,
NULL, NULL, NULL, NULL
};
#endif
PyObject *BPY_rna_props( void )
{
PyObject *submodule, *mod;
#if PY_VERSION_HEX >= 0x03000000
submodule= PyModule_Create(&props_module);
#else /* Py2.x */
submodule= Py_InitModule3( "bpy.props", props_methods, "" );
#endif
mod = PyModule_New("props");
PyModule_AddObject( submodule, "props", mod );
/* INCREF since its its assumed that all these functions return the
* module with a new ref like PyDict_New, since they are passed to
* PyModule_AddObject which steals a ref */
Py_INCREF(submodule);
return submodule;
}
/* Orphan functions, not sure where they should go */
@@ -1780,7 +1817,7 @@ PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
return NULL;
}
if (self) {
if (self && PyCObject_Check(self)) {
StructRNA *srna = PyCObject_AsVoidPtr(self);
RNA_def_float(srna, id, def, min, max, name, description, soft_min, soft_max);
Py_RETURN_NONE;
@@ -1807,7 +1844,7 @@ PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
return NULL;
}
if (self) {
if (self && PyCObject_Check(self)) {
StructRNA *srna = PyCObject_AsVoidPtr(self);
RNA_def_int(srna, id, def, min, max, name, description, soft_min, soft_max);
Py_RETURN_NONE;
@@ -1834,7 +1871,7 @@ PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
return NULL;
}
if (self) {
if (self && PyCObject_Check(self)) {
StructRNA *srna = PyCObject_AsVoidPtr(self);
RNA_def_boolean(srna, id, def, name, description);
Py_RETURN_NONE;
@@ -1847,6 +1884,33 @@ PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
}
}
PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw)
{
static char *kwlist[] = {"attr", "name", "description", "maxlen", "default", NULL};
char *id, *name="", *description="", *def="";
int maxlen=0;
if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssis:StringProperty", kwlist, &id, &name, &description, &maxlen, &def))
return NULL;
if (PyTuple_Size(args) > 0) {
PyErr_SetString(PyExc_ValueError, "all args must be keywors"); // TODO - py3 can enforce this.
return NULL;
}
if (self && PyCObject_Check(self)) {
StructRNA *srna = PyCObject_AsVoidPtr(self);
RNA_def_string(srna, id, def, maxlen, name, description);
Py_RETURN_NONE;
} else {
PyObject *ret = PyTuple_New(2);
PyTuple_SET_ITEM(ret, 0, PyCObject_FromVoidPtr((void *)BPy_StringProperty, NULL));
PyTuple_SET_ITEM(ret, 1, kw);
Py_INCREF(kw);
return ret;
}
}
/*-------------------- Type Registration ------------------------*/
static int rna_function_arg_count(FunctionRNA *func)

View File

@@ -63,6 +63,7 @@ typedef struct {
PyObject *BPY_rna_module( void );
/*PyObject *BPY_rna_doc( void );*/
PyObject *BPY_rna_types( void );
PyObject *BPY_rna_props( void );
PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr );
PyObject *pyrna_prop_CreatePyObject( PointerRNA *ptr, PropertyRNA *prop );
@@ -76,6 +77,7 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop);
PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw);
/* function for registering types */
PyObject *pyrna_basetype_register(PyObject *self, PyObject *args);

View File

@@ -81,6 +81,7 @@ int BPY_flag_from_seq(BPY_flag_def *flagdef, PyObject *seq, int *flag)
char *cstring;
PyObject *item;
BPY_flag_def *fd;
*flag = 0;
if (PySequence_Check(seq)) {
i= PySequence_Length(seq);
@@ -108,6 +109,9 @@ int BPY_flag_from_seq(BPY_flag_def *flagdef, PyObject *seq, int *flag)
error_val= 1;
}
if (*flag == 0)
error_val = 1;
if (error_val) {
char *buf = bpy_flag_error_str(flagdef);
PyErr_SetString(PyExc_AttributeError, buf);