From 9d922b4c24538d53aed9b0661804652455f8a3b7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 11 Apr 2009 05:46:40 +0000 Subject: Changed the script UI registration to import rather then run each python script, this means it caches the compiled pyc files after importing fro the first time. My times for importing 501 buttons_objects.py files were. - running each as a script 1.9sec - importing for the first time 1.8sec - importing a second time (using pyc files) 0.57sec Also added "bpy" to sys.modules so it can be imported. --- source/blender/python/BPY_extern.h | 2 +- source/blender/python/intern/bpy_interface.c | 120 +++++++++++++++------ source/blender/python/intern/bpy_operator.c | 2 +- source/blender/python/intern/bpy_operator.h | 2 +- source/blender/python/intern/bpy_rna.c | 21 ++-- source/creator/creator.c | 2 +- source/gameengine/GameLogic/SCA_KeyboardSensor.cpp | 10 +- 7 files changed, 110 insertions(+), 49 deletions(-) (limited to 'source') diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h index f46ef0fa670..bb22432d90f 100644 --- a/source/blender/python/BPY_extern.h +++ b/source/blender/python/BPY_extern.h @@ -99,7 +99,7 @@ extern "C" { /* 2.5 UI Scripts */ int BPY_run_python_script( struct bContext *C, const char *filename, struct Text *text ); // 2.5 working int BPY_run_script_space_draw(struct bContext *C, struct SpaceScript * sc); // 2.5 working - void BPY_run_ui_scripts(struct bContext *C); + void BPY_run_ui_scripts(void); // int BPY_run_script_space_listener(struct bContext *C, struct SpaceScript * sc, struct ARegion *ar, struct wmNotifier *wmn); // 2.5 working diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 667dd14283f..db82b740a15 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,35 +40,42 @@ 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() ); */ PyModule_AddObject( mod, "types", BPY_rna_types() ); - PyModule_AddObject( mod, "ops", BPY_operator_module(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); +} + +/***************************************************************************** +* 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 +91,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 +110,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 +320,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 +351,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.c b/source/blender/python/intern/bpy_operator.c index 29ec3376765..3e403ea1aad 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -262,7 +262,7 @@ static PyObject *pyop_base_rna(PyObject *self, PyObject *pyname) PyTypeObject pyop_base_Type = {NULL}; -PyObject *BPY_operator_module( bContext *C ) +PyObject *BPY_operator_module( void ) { pyop_base_Type.tp_name = "OperatorBase"; pyop_base_Type.tp_basicsize = sizeof( BPy_OperatorBase ); diff --git a/source/blender/python/intern/bpy_operator.h b/source/blender/python/intern/bpy_operator.h index 8eb0b887baa..c4741f936bf 100644 --- a/source/blender/python/intern/bpy_operator.h +++ b/source/blender/python/intern/bpy_operator.h @@ -40,7 +40,7 @@ typedef struct { PyObject_HEAD /* required python macro */ } BPy_OperatorBase; -PyObject *BPY_operator_module(bContext *C ); +PyObject *BPY_operator_module(void); /* fill in properties from a python dict */ int PYOP_props_from_dict(PointerRNA *ptr, PyObject *kw); diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 3dc7456de61..3f70d914801 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -1526,10 +1526,13 @@ PyObject* pyrna_struct_Subtype(PointerRNA *ptr) - myClass = type(name='myClass', bases=(myBase,), dict={'some':'value'}) */ char name[256], *nameptr; + const char *descr= RNA_struct_ui_description(ptr); PyObject *args = PyTuple_New(3); PyObject *bases = PyTuple_New(1); PyObject *dict = PyDict_New(); + PyObject *item; + nameptr= RNA_property_string_get_alloc(ptr, nameprop, name, sizeof(name)); @@ -1544,6 +1547,12 @@ PyObject* pyrna_struct_Subtype(PointerRNA *ptr) PyTuple_SET_ITEM(args, 1, bases); // arg 3 - add an instance of the rna + if(descr) { + item= PyUnicode_FromString(descr); + PyDict_SetItemString(dict, "__doc__", item); + Py_DECREF(item); + } + PyTuple_SET_ITEM(args, 2, dict); // fill with useful subclass things! if (PyErr_Occurred()) { @@ -1552,23 +1561,19 @@ PyObject* pyrna_struct_Subtype(PointerRNA *ptr) } newclass = PyObject_CallObject((PyObject *)&PyType_Type, args); - // Set this later - + Py_DECREF(args); if (newclass) { - PyObject *rna; RNA_struct_py_type_set(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 */ - rna = pyrna_struct_CreatePyObject(ptr); - PyDict_SetItemString(((PyTypeObject *)newclass)->tp_dict, "__rna__", rna); - Py_DECREF(rna); + item = pyrna_struct_CreatePyObject(ptr); + PyDict_SetItemString(((PyTypeObject *)newclass)->tp_dict, "__rna__", item); + Py_DECREF(item); /* done with rna instance */ } - Py_DECREF(args); - if (name != nameptr) MEM_freeN(nameptr); } diff --git a/source/creator/creator.c b/source/creator/creator.c index 082f2395b3f..cb1fc18248f 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -529,7 +529,7 @@ int main(int argc, char **argv) */ BPY_post_start_python(); - BPY_run_ui_scripts(C); + BPY_run_ui_scripts(); #endif #ifdef WITH_QUICKTIME diff --git a/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp b/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp index 324e5eae98a..ca30382b8c0 100644 --- a/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp +++ b/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp @@ -148,7 +148,7 @@ bool SCA_KeyboardSensor::Evaluate(CValue* eventval) bool justreleased = false; bool active = false; - for (int i=SCA_IInputDevice::KX_BEGINKEY ; i< SCA_IInputDevice::KX_ENDKEY;i++) + for (int i=SCA_IInputDevice::KX_BEGINKEY ; i<= SCA_IInputDevice::KX_ENDKEY;i++) { const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i); switch (inevent.m_status) @@ -528,7 +528,7 @@ void SCA_KeyboardSensor::LogKeystrokes(void) int index = 0; /* Check on all keys whether they were pushed. This does not * untangle the ordering, so don't type too fast :) */ - for (int i=SCA_IInputDevice::KX_BEGINKEY ; i< SCA_IInputDevice::KX_ENDKEY;i++) + for (int i=SCA_IInputDevice::KX_BEGINKEY ; i<= SCA_IInputDevice::KX_ENDKEY;i++) { const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i); if (inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED) //NO_INPUTSTATUS) @@ -663,7 +663,7 @@ PyObject* SCA_KeyboardSensor::PyGetPressedKeys(PyObject* self, PyObject* args, P int index = 0; - for (int i=SCA_IInputDevice::KX_BEGINKEY ; i< SCA_IInputDevice::KX_ENDKEY;i++) + for (int i=SCA_IInputDevice::KX_BEGINKEY ; i<= SCA_IInputDevice::KX_ENDKEY;i++) { const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i); if ((inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED) @@ -704,7 +704,7 @@ SCA_IInputDevice* inputdev = m_pKeyboardMgr->GetInputDevice(); { int index = 0; - for (int i=SCA_IInputDevice::KX_BEGINKEY ; i< SCA_IInputDevice::KX_ENDKEY;i++) + for (int i=SCA_IInputDevice::KX_BEGINKEY ; i<= SCA_IInputDevice::KX_ENDKEY;i++) { const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i); if ( (inevent.m_status == SCA_InputEvent::KX_ACTIVE) @@ -737,7 +737,7 @@ KX_PYMETHODDEF_DOC_NOARGS(SCA_KeyboardSensor, getEventList, PyObject* resultlist = PyList_New(0); - for (int i=SCA_IInputDevice::KX_BEGINKEY ; i< SCA_IInputDevice::KX_ENDKEY;i++) + for (int i=SCA_IInputDevice::KX_BEGINKEY ; i<= SCA_IInputDevice::KX_ENDKEY;i++) { const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i); if (inevent.m_status != SCA_InputEvent::KX_NO_INPUTSTATUS) -- cgit v1.2.3