From 3f98b7ac35cbac648face4334402e1c3b707ed0c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 11 Apr 2009 16:17:39 +0000 Subject: Added back importing UI scripts rather then running, The bug was todo with bpy.data and bpy.types becoming invalid, temporary fix is to re-assign them to the bpy module before running python operators or panels. will look into a nicer way to get this working. --- source/blender/python/intern/bpy_interface.c | 125 +++++++++++++++++------ source/blender/python/intern/bpy_operator_wrap.c | 4 + source/blender/python/intern/bpy_panel_wrap.c | 4 + source/blender/python/intern/bpy_rna.c | 21 ++-- source/blender/python/intern/bpy_util.h | 3 + 5 files changed, 116 insertions(+), 41 deletions(-) (limited to 'source/blender/python/intern') diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index c9485e0f22a..f6273c6381b 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -26,6 +26,7 @@ #include "MEM_guardedalloc.h" #include "BLI_util.h" +#include "BLI_string.h" #include "BKE_context.h" #include "BKE_text.h" @@ -39,22 +40,13 @@ void BPY_free_compiled_text( struct Text *text ) } /***************************************************************************** -* Description: This function creates a new Python dictionary object. +* Description: Creates the bpy module and adds it to sys.modules for importing *****************************************************************************/ - -static PyObject *CreateGlobalDictionary( bContext *C ) +static void bpy_init_modules( void ) { PyObject *mod; - PyObject *dict = PyDict_New( ); - PyObject *item = PyUnicode_FromString( "__main__" ); - PyDict_SetItemString( dict, "__builtins__", PyEval_GetBuiltins( ) ); - PyDict_SetItemString( dict, "__name__", item ); - Py_DECREF(item); - /* add bpy to global namespace */ mod = PyModule_New("bpy"); - PyDict_SetItemString( dict, "bpy", mod ); - Py_DECREF(mod); PyModule_AddObject( mod, "data", BPY_rna_module() ); /* PyModule_AddObject( mod, "doc", BPY_rna_doc() ); */ @@ -62,12 +54,35 @@ static PyObject *CreateGlobalDictionary( bContext *C ) 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 + /* add the module so we can import it */ + PyDict_SetItemString(PySys_GetObject("modules"), "bpy", mod); + Py_DECREF(mod); +} + +void BPY_update_modules( void ) +{ + PyObject *mod= PyImport_ImportModuleLevel("bpy", NULL, NULL, NULL, 0); + PyModule_AddObject( mod, "data", BPY_rna_module() ); + PyModule_AddObject( mod, "types", BPY_rna_types() ); +} + +/***************************************************************************** +* Description: This function creates a new Python dictionary object. +*****************************************************************************/ +static PyObject *CreateGlobalDictionary( bContext *C ) +{ + PyObject *mod; + PyObject *dict = PyDict_New( ); + PyObject *item = PyUnicode_FromString( "__main__" ); + PyDict_SetItemString( dict, "__builtins__", PyEval_GetBuiltins( ) ); + PyDict_SetItemString( dict, "__name__", item ); + Py_DECREF(item); + // XXX - evil, need to access context item = PyCObject_FromVoidPtr( C, NULL ); PyDict_SetItemString( dict, "__bpy_context__", item ); Py_DECREF(item); - // XXX - put somewhere more logical { PyMethodDef *ml; @@ -83,13 +98,18 @@ static PyObject *CreateGlobalDictionary( bContext *C ) } } + /* add bpy to global namespace */ + mod= PyImport_ImportModuleLevel("bpy", NULL, NULL, NULL, 0); + PyDict_SetItemString( dict, "bpy", mod ); + Py_DECREF(mod); + return dict; } void BPY_start_python( void ) { PyThreadState *py_tstate = NULL; - + Py_Initialize( ); //PySys_SetArgv( argc_copy, argv_copy ); @@ -97,7 +117,10 @@ void BPY_start_python( void ) /* Initialize thread support (also acquires lock) */ PyEval_InitThreads(); - // todo - sys paths - our own imports + + /* bpy.* and lets us import it */ + bpy_init_modules(); + py_tstate = PyGILState_GetThisThreadState(); PyEval_ReleaseThread(py_tstate); @@ -304,16 +327,30 @@ int BPY_run_python_script_space(const char *modulename, const char *func) } #endif +// #define TIME_REGISTRATION + +#ifdef TIME_REGISTRATION +#include "PIL_time.h" +#endif + /* XXX this is temporary, need a proper script registration system for 2.5 */ -void BPY_run_ui_scripts(bContext *C) +void BPY_run_ui_scripts(void) { +#ifdef TIME_REGISTRATION + double time = PIL_check_seconds_timer(); +#endif DIR *dir; struct dirent *de; - struct stat status; char *file_extension; char path[FILE_MAX]; char *dirname= BLI_gethome_folder("ui"); - + int filelen; /* filename length */ + + PyGILState_STATE gilstate; + PyObject *mod; + PyObject *sys_path_orig; + PyObject *sys_path_new; + if(!dirname) return; @@ -321,23 +358,49 @@ void BPY_run_ui_scripts(bContext *C) if(!dir) return; - - if (dir != NULL) { - while((de = readdir(dir)) != NULL) { - BLI_make_file_string("/", path, dirname, de->d_name); + + gilstate = PyGILState_Ensure(); + + /* backup sys.path */ + sys_path_orig= PySys_GetObject("path"); + Py_INCREF(sys_path_orig); /* dont free it */ + + sys_path_new= PyList_New(1); + PyList_SET_ITEM(sys_path_new, 0, PyUnicode_FromString(dirname)); + PySys_SetObject("path", sys_path_new); + Py_DECREF(sys_path_new); + + + while((de = readdir(dir)) != NULL) { + /* We could stat the file but easier just to let python + * import it and complain if theres a problem */ + + file_extension = strstr(de->d_name, ".py"); + + if(file_extension && *(file_extension + 3) == '\0') { + filelen = strlen(de->d_name); + BLI_strncpy(path, de->d_name, filelen-2); /* cut off the .py on copy */ - stat(path, &status); - - /* run if it is a .py file */ - if(S_ISREG(status.st_mode)) { - file_extension = strstr(de->d_name, ".py"); - - if(file_extension && *(file_extension + 3) == '\0') - BPY_run_python_script(C, path, NULL); + mod= PyImport_ImportModuleLevel(path, NULL, NULL, NULL, 0); + if (mod) { + Py_DECREF(mod); } + else { + PyErr_Print(); + fprintf(stderr, "unable to import \"%s\" %s/%s\n", path, dirname, de->d_name); + } + } - - closedir(dir); } + + closedir(dir); + + PySys_SetObject("path", sys_path_orig); + Py_DECREF(sys_path_orig); + + PyGILState_Release(gilstate); +#ifdef TIME_REGISTRATION + printf("script time %f\n", (PIL_check_seconds_timer()-time)); +#endif } diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c index 1db1f547fa6..02a87450a06 100644 --- a/source/blender/python/intern/bpy_operator_wrap.c +++ b/source/blender/python/intern/bpy_operator_wrap.c @@ -181,6 +181,8 @@ static struct BPY_flag_def pyop_ret_flags[] = { #define PYOP_INVOKE 2 #define PYOP_POLL 3 +extern void BPY_update_modules( void ); //XXX temp solution + static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *event) { PyObject *py_class = op->type->pyop_data; @@ -189,6 +191,8 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve int ret_flag= (mode==PYOP_POLL ? 0:OPERATOR_CANCELLED); PyGILState_STATE gilstate = PyGILState_Ensure(); + + BPY_update_modules(); // XXX - the RNA pointers can change so update before running, would like a nicer solutuon for this. args = PyTuple_New(1); PyTuple_SET_ITEM(args, 0, PyObject_GetAttrString(py_class, "__rna__")); // need to use an rna instance as the first arg diff --git a/source/blender/python/intern/bpy_panel_wrap.c b/source/blender/python/intern/bpy_panel_wrap.c index bc85e5bdced..8cdac286f8d 100644 --- a/source/blender/python/intern/bpy_panel_wrap.c +++ b/source/blender/python/intern/bpy_panel_wrap.c @@ -44,6 +44,8 @@ #define PYPANEL_DRAW 1 #define PYPANEL_POLL 2 +extern void BPY_update_modules( void ); //XXX temp solution + static int PyPanel_generic(int mode, const bContext *C, Panel *pnl) { PyObject *py_class= (PyObject *)(pnl->type->py_data); @@ -55,6 +57,8 @@ static int PyPanel_generic(int mode, const bContext *C, Panel *pnl) PyGILState_STATE gilstate = PyGILState_Ensure(); + BPY_update_modules(); // XXX - the RNA pointers can change so update before running, would like a nicer solutuon for this. + args = PyTuple_New(1); RNA_pointer_create(&CTX_wm_screen(C)->id, pnl->type->srna, pnl, &panelptr); PyTuple_SET_ITEM(args, 0, pyrna_struct_CreatePyObject(&panelptr)); diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index c7c4a5ef489..d2d9364e7df 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -1714,21 +1714,22 @@ static PyObject *pyrna_basetype_dir(BPy_BaseTypeRNA *self) return list; } -PyTypeObject pyrna_basetype_Type; +PyTypeObject pyrna_basetype_Type = BLANK_PYTHON_TYPE; PyObject *BPY_rna_types(void) { BPy_BaseTypeRNA *self; - memset(&pyrna_basetype_Type, 0, sizeof(pyrna_basetype_Type)); - 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; + if ((pyrna_basetype_Type.tp_flags & Py_TPFLAGS_READY)==0) { + 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 ); diff --git a/source/blender/python/intern/bpy_util.h b/source/blender/python/intern/bpy_util.h index e2bea331b0e..9ce7a17b9e3 100644 --- a/source/blender/python/intern/bpy_util.h +++ b/source/blender/python/intern/bpy_util.h @@ -67,4 +67,7 @@ int BPY_class_validate(const char *class_type, PyObject *class, PyObject *base_c char *BPy_enum_as_string(struct EnumPropertyItem *item); + +#define BLANK_PYTHON_TYPE {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} + #endif -- cgit v1.2.3