From 70f011bbcea9aee222e43895fea503b26d3d566a Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 7 Aug 2009 16:20:19 +0000 Subject: [PATCH] bpy_context_set and bpy_context_clear to replace a number of functions (some were not always called causing bugs). fix for a leak when trying to run a text with a syntax error too. --- source/blender/python/intern/bpy_interface.c | 77 +++++++++++++------ .../blender/python/intern/bpy_operator_wrap.c | 9 +-- source/blender/python/intern/bpy_rna.c | 7 +- source/blender/python/intern/bpy_util.h | 4 + 4 files changed, 63 insertions(+), 34 deletions(-) diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 707c5769357..ed9dbdf2868 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -45,6 +45,50 @@ #include "../generic/BGL.h" +/* for internal use, when starting and ending python scripts */ + +/* incase a python script triggers another python call, stop bpy_context_clear from invalidating */ +static int py_call_level= 0; + +void bpy_context_set(bContext *C, PyGILState_STATE *gilstate) +{ + py_call_level++; + + if(gilstate) + *gilstate = PyGILState_Ensure(); + + if(py_call_level==1) { + + BPY_update_modules(); /* can give really bad results if this isnt here */ + + if(C) { // XXX - should always be true. + BPy_SetContext(C); + bpy_import_main_set(CTX_data_main(C)); + } + else { + fprintf(stderr, "ERROR: Python context called with a NULL Context. this should not happen!\n"); + } + } +} + +void bpy_context_clear(bContext *C, PyGILState_STATE *gilstate) +{ + py_call_level--; + + if(gilstate) + PyGILState_Release(*gilstate); + + if(py_call_level < 0) { + fprintf(stderr, "ERROR: Python context internal state bug. this should not happen!\n"); + } + else if(py_call_level==0) { + // XXX - Calling classes currently wont store the context :\, cant set NULL because of this. but this is very flakey still. + //BPy_SetContext(NULL); + //bpy_import_main_set(NULL); + } +} + + void BPY_free_compiled_text( struct Text *text ) { if( text->compiled ) { @@ -106,9 +150,6 @@ static PyObject *CreateGlobalDictionary( bContext *C ) PyDict_SetItemString( dict, "__name__", item ); Py_DECREF(item); - // XXX - evil, need to access context - BPy_SetContext(C); - // XXX - put somewhere more logical { PyMethodDef *ml; @@ -224,19 +265,14 @@ void BPY_end_python( void ) /* Can run a file or text block */ int BPY_run_python_script( bContext *C, const char *fn, struct Text *text, struct ReportList *reports) { - PyObject *py_dict, *py_result; + PyObject *py_dict, *py_result= NULL; PyGILState_STATE gilstate; if (fn==NULL && text==NULL) { return 0; } - //BPY_start_python(); - - gilstate = PyGILState_Ensure(); - - BPY_update_modules(); /* can give really bad results if this isnt here */ - bpy_import_main_set(CTX_data_main(C)); + bpy_context_set(C, &gilstate); py_dict = CreateGlobalDictionary(C); @@ -251,13 +287,11 @@ int BPY_run_python_script( bContext *C, const char *fn, struct Text *text, struc MEM_freeN( buf ); if( PyErr_Occurred( ) ) { - BPy_errors_to_report(reports); BPY_free_compiled_text( text ); - PyGILState_Release(gilstate); - return 0; } } - py_result = PyEval_EvalCode( text->compiled, py_dict, py_dict ); + if(text->compiled) + py_result = PyEval_EvalCode( text->compiled, py_dict, py_dict ); } else { #if 0 @@ -287,10 +321,9 @@ int BPY_run_python_script( bContext *C, const char *fn, struct Text *text, struc } Py_DECREF(py_dict); - PyGILState_Release(gilstate); - bpy_import_main_set(NULL); - //BPY_end_python(); + bpy_context_clear(C, &gilstate); + return py_result ? 1:0; } @@ -473,12 +506,7 @@ void BPY_run_ui_scripts(bContext *C, int reload) PyGILState_STATE gilstate; PyObject *sys_path; - gilstate = PyGILState_Ensure(); - - // XXX - evil, need to access context - BPy_SetContext(C); - bpy_import_main_set(CTX_data_main(C)); - + bpy_context_set(C, &gilstate); sys_path= PySys_GetObject("path"); /* borrow */ PyList_Insert(sys_path, 0, Py_None); /* place holder, resizes the list */ @@ -537,9 +565,8 @@ void BPY_run_ui_scripts(bContext *C, int reload) PyList_SetSlice(sys_path, 0, 1, NULL); /* remove the first item */ - bpy_import_main_set(NULL); + bpy_context_clear(C, &gilstate); - 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 080d2e8ce6a..7a92c747bd3 100644 --- a/source/blender/python/intern/bpy_operator_wrap.c +++ b/source/blender/python/intern/bpy_operator_wrap.c @@ -93,11 +93,9 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve PointerRNA ptr_event; PyObject *py_operator; - PyGILState_STATE gilstate = PyGILState_Ensure(); + PyGILState_STATE gilstate; - 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. + bpy_context_set(C, &gilstate); args = PyTuple_New(1); PyTuple_SET_ITEM(args, 0, PyObject_GetAttrString(py_class, "__rna__")); // need to use an rna instance as the first arg @@ -221,8 +219,7 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve } #endif - PyGILState_Release(gilstate); - bpy_import_main_set(NULL); + bpy_context_clear(C, &gilstate); return ret_flag; } diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 27bfb89b963..20164edc95a 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -2918,9 +2918,10 @@ static int bpy_class_call(PointerRNA *ptr, FunctionRNA *func, ParameterList *par void *retdata= NULL; int err= 0, i, flag; - PyGILState_STATE gilstate = PyGILState_Ensure(); + PyGILState_STATE gilstate; - BPY_update_modules(); // XXX - the RNA pointers can change so update before running, would like a nicer solution for this. + bContext *C= BPy_GetContext(); // XXX - NEEDS FIXING, QUITE BAD. + bpy_context_set(C, &gilstate); py_class= RNA_struct_py_type_get(ptr->type); @@ -2996,7 +2997,7 @@ static int bpy_class_call(PointerRNA *ptr, FunctionRNA *func, ParameterList *par PyErr_Clear(); } - PyGILState_Release(gilstate); + bpy_context_clear(C, &gilstate); return err; } diff --git a/source/blender/python/intern/bpy_util.h b/source/blender/python/intern/bpy_util.h index 470dd4c2a45..df204b7b90d 100644 --- a/source/blender/python/intern/bpy_util.h +++ b/source/blender/python/intern/bpy_util.h @@ -82,4 +82,8 @@ int BPy_errors_to_report(struct ReportList *reports); struct bContext *BPy_GetContext(void); void BPy_SetContext(struct bContext *C); +extern void bpy_context_set(struct bContext *C, PyGILState_STATE *gilstate); +extern void bpy_context_clear(struct bContext *C, PyGILState_STATE *gilstate); + + #endif