diff --git a/release/scripts/op/console_python.py b/release/scripts/op/console_python.py index cabc741c701..3c6e52e28cd 100644 --- a/release/scripts/op/console_python.py +++ b/release/scripts/op/console_python.py @@ -22,6 +22,9 @@ import bpy language_id = 'python' +# store our own __main__ module, not 100% needed +# but python expects this in some places +_BPY_MAIN_OWN = True def add_scrollback(text, text_type): for l in text.split('\n'): @@ -63,12 +66,25 @@ def get_console(console_id): # XXX, bug in python 3.1.2 ? (worked in 3.1.1) # seems there is no way to clear StringIO objects for writing, have to make new ones each time. - import io - stdout = io.StringIO() - stderr = io.StringIO() + # import io + # stdout = io.StringIO() + # stderr = io.StringIO() else: - namespace = {"__builtins__": __builtins__, "bpy": bpy, "C": bpy.context} + if _BPY_MAIN_OWN: + import types + bpy_main_mod = types.ModuleType("__main__") + namespace = bpy_main_mod.__dict__ + else: + namespace = {} + + namespace["__builtins__"] = sys.modules["builtins"] + namespace["bpy"] = bpy + namespace["C"] = bpy.context + console = InteractiveConsole(locals=namespace, filename="") + + if _BPY_MAIN_OWN: + console._bpy_main_mod = bpy_main_mod import io stdout = io.StringIO() @@ -105,6 +121,10 @@ def execute(context): stdin_backup = sys.stdin sys.stdin = None + if _BPY_MAIN_OWN: + main_mod_back = sys.modules["__main__"] + sys.modules["__main__"] = console._bpy_main_mod + # incase exception happens line = "" # incase of encodingf error is_multiline = False @@ -121,6 +141,8 @@ def execute(context): import traceback stderr.write(traceback.format_exc()) + if _BPY_MAIN_OWN: + sys.modules["__main__"] = main_mod_back stdout.seek(0) stderr.seek(0) diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 13b8cd4036a..83f407bab67 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -149,11 +149,12 @@ void BPY_update_modules( void ) /***************************************************************************** * Description: This function creates a new Python dictionary object. *****************************************************************************/ -static PyObject *CreateGlobalDictionary( bContext *C, const char *filename ) +static PyObject *CreateGlobalDictionary(bContext *C, const char *filename, PyObject *main_ns_orig) { PyObject *item; PyObject *dict; -#if 1 + + /* important we use the dict from __main__, this is what python expects * for 'pickle' to work as well as strings like this... @@ -161,6 +162,7 @@ static PyObject *CreateGlobalDictionary( bContext *C, const char *filename ) >> print(__import__("__main__").foo) */ dict= PyModule_GetDict(PyImport_AddModule("__main__")); + PyDict_Merge(main_ns_orig, dict, 1); PyDict_Clear(dict); Py_INCREF(dict); @@ -168,12 +170,8 @@ static PyObject *CreateGlobalDictionary( bContext *C, const char *filename ) * print's many less items when printing, the modules __dict__ * this is how python works so better follow. */ PyDict_SetItemString(dict, "__builtins__", PyImport_AddModule("builtins")); -#else - /* otherwise this works for 99% of cases, from 2.4x */ - dict = PyDict_New(); - PyDict_SetItemString( dict, "__builtins__", PyEval_GetBuiltins()); -#endif - + + item = PyUnicode_FromString( "__main__" ); PyDict_SetItemString( dict, "__name__", item ); Py_DECREF(item); @@ -188,6 +186,13 @@ static PyObject *CreateGlobalDictionary( bContext *C, const char *filename ) return dict; } +static void CreateGlobalDictionary_Restore(PyObject *main_ns_orig) +{ + PyObject *main_ns= PyModule_GetDict(PyImport_AddModule("__main__")); + PyDict_Clear(main_ns); + PyDict_Merge(main_ns, main_ns_orig, 1); +} + /* must be called before Py_Initialize */ void BPY_start_python_path(void) { @@ -341,6 +346,7 @@ void BPY_end_python( void ) int BPY_run_python_script( bContext *C, const char *fn, struct Text *text, struct ReportList *reports) { PyObject *py_dict, *py_result= NULL; + PyObject *main_ns_orig= PyDict_New(); PyGILState_STATE gilstate; if (fn==NULL && text==NULL) { @@ -352,7 +358,7 @@ int BPY_run_python_script( bContext *C, const char *fn, struct Text *text, struc if (text) { char fn_dummy[FILE_MAXDIR]; bpy_text_filename_get(fn_dummy, text); - py_dict = CreateGlobalDictionary(C, fn_dummy); + py_dict = CreateGlobalDictionary(C, fn_dummy, main_ns_orig); if( !text->compiled ) { /* if it wasn't already compiled, do it now */ char *buf = txt_to_buf( text ); @@ -373,7 +379,7 @@ int BPY_run_python_script( bContext *C, const char *fn, struct Text *text, struc else { FILE *fp= fopen(fn, "r"); - py_dict = CreateGlobalDictionary(C, fn); + py_dict = CreateGlobalDictionary(C, fn, main_ns_orig); if(fp) { #ifdef _WIN32 @@ -408,9 +414,8 @@ int BPY_run_python_script( bContext *C, const char *fn, struct Text *text, struc Py_DECREF( py_result ); } - /* so __main__ module isnt left with an invalid __file__ variable which could be confusing */ - if (PyDict_DelItemString(py_dict, "__file__")) - PyErr_Clear(); + CreateGlobalDictionary_Restore(main_ns_orig); + Py_DECREF(main_ns_orig); Py_DECREF(py_dict); @@ -562,6 +567,7 @@ int BPY_eval_button(bContext *C, const char *expr, double *value) { PyGILState_STATE gilstate; PyObject *dict, *mod, *retval; + PyObject *main_ns_orig= PyDict_New(); int error_ret = 0; if (!value || !expr) return -1; @@ -573,7 +579,7 @@ int BPY_eval_button(bContext *C, const char *expr, double *value) bpy_context_set(C, &gilstate); - dict= CreateGlobalDictionary(C, NULL); + dict= CreateGlobalDictionary(C, NULL, main_ns_orig); mod = PyImport_ImportModule("math"); if (mod) { @@ -623,6 +629,9 @@ int BPY_eval_button(bContext *C, const char *expr, double *value) BPy_errors_to_report(CTX_wm_reports(C)); } + CreateGlobalDictionary_Restore(main_ns_orig); + Py_DECREF(main_ns_orig); + Py_DECREF(dict); bpy_context_clear(C, &gilstate); @@ -633,6 +642,7 @@ int BPY_eval_string(bContext *C, const char *expr) { PyGILState_STATE gilstate; PyObject *dict, *retval; + PyObject *main_ns_orig= PyDict_New(); int error_ret = 0; if (!expr) return -1; @@ -643,7 +653,7 @@ int BPY_eval_string(bContext *C, const char *expr) bpy_context_set(C, &gilstate); - dict= CreateGlobalDictionary(C, NULL); + dict= CreateGlobalDictionary(C, NULL, main_ns_orig); retval = PyRun_String(expr, Py_eval_input, dict, dict); @@ -656,6 +666,9 @@ int BPY_eval_string(bContext *C, const char *expr) Py_DECREF(retval); } + CreateGlobalDictionary_Restore(main_ns_orig); + Py_DECREF(main_ns_orig); + Py_DECREF(dict); bpy_context_clear(C, &gilstate);