merge with trunk at r27259 and commit of a patch by anthony jones to fix msvc (though...
[blender-staging.git] / source / blender / python / intern / bpy_interface.c
index ac8acc2c07cfe7df523f94f856f79cb5b7fa38c3..02eebde8a137a0dc5643301c4c2527255811e25a 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  * Contributor(s): Michel Selten, Willian P. Germano, Stephen Swaney,
  * Chris Keith, Chris Want, Ken Hughes, Campbell Barton
 #include <string.h>
 #include <sys/stat.h>
 
-#ifndef WIN32
-#include <dirent.h>
-#else
-#include "BLI_winstuff.h"
-#endif
 
 /* grr, python redefines */
 #ifdef _POSIX_C_SOURCE
 #include "compile.h"           /* for the PyCodeObject */
 #include "eval.h"              /* for PyEval_EvalCode */
 
+#include "bpy.h"
 #include "bpy_rna.h"
-#include "bpy_operator.h"
-#include "bpy_ui.h"
 #include "bpy_util.h"
 
-#include "DNA_anim_types.h"
+#ifndef WIN32
+#include <dirent.h>
+#else
+#include "BLI_winstuff.h"
+#endif
+
 #include "DNA_space_types.h"
 #include "DNA_text_types.h"
 
 #include "MEM_guardedalloc.h"
 
-#include "BLI_util.h"
+#include "BLI_storage.h"
 #include "BLI_fileops.h"
 #include "BLI_string.h"
+#include "BLI_path_util.h"
 
 #include "BKE_context.h"
-#include "BKE_fcurve.h"
 #include "BKE_text.h"
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_global.h" /* only for script checking */
 
 #include "BPY_extern.h"
 
 #include "../generic/bpy_internal_import.h" // our own imports
-/* external util modules */
-
-#include "../generic/Mathutils.h"
-#include "../generic/Geometry.h"
-#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;
-
+BPy_StructRNA *bpy_context_module= NULL; /* for fast access */
 
 // only for tests
 #define TIME_PY_RUN
@@ -98,8 +94,6 @@ void bpy_context_set(bContext *C, PyGILState_STATE *gilstate)
 
        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));
@@ -108,6 +102,8 @@ void bpy_context_set(bContext *C, PyGILState_STATE *gilstate)
                        fprintf(stderr, "ERROR: Python context called with a NULL Context. this should not happen!\n");
                }
 
+               BPY_update_modules(); /* can give really bad results if this isnt here */
+
 #ifdef TIME_PY_RUN
                if(bpy_timer_count==0) {
                        /* record time from the beginning */
@@ -145,7 +141,6 @@ void bpy_context_clear(bContext *C, PyGILState_STATE *gilstate)
        }
 }
 
-
 void BPY_free_compiled_text( struct Text *text )
 {
        if( text->compiled ) {
@@ -154,33 +149,6 @@ void BPY_free_compiled_text( struct Text *text )
        }
 }
 
-/*****************************************************************************
-* Description: Creates the bpy module and adds it to sys.modules for importing
-*****************************************************************************/
-static void bpy_init_modules( void )
-{
-       PyObject *mod;
-       
-       mod = PyModule_New("bpy");
-       
-       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() ); /* ops is now a python module that does the conversion from SOME_OT_foo -> some.foo */
-       PyModule_AddObject( mod, "ui", BPY_ui_module() ); // XXX very experimental, consider this a test, especially PyCObject is not meant to be permanent
-       
-       /* add the module so we can import it */
-       PyDict_SetItemString(PySys_GetObject("modules"), "bpy", mod);
-       Py_DECREF(mod);
-
-
-       /* stand alone utility modules not related to blender directly */
-       Geometry_Init();
-       Mathutils_Init();
-       BGL_Init();
-}
-
 void BPY_update_modules( void )
 {
 #if 0 // slow, this runs all the time poll, draw etc 100's of time a sec.
@@ -191,37 +159,30 @@ void BPY_update_modules( void )
 
        /* refreshes the main struct */
        BPY_update_rna_module();
-
+       bpy_context_module->ptr.data= (void *)BPy_GetContext();
 }
 
 /*****************************************************************************
 * Description: This function creates a new Python dictionary object.
 *****************************************************************************/
-static PyObject *CreateGlobalDictionary( bContext *C )
+static PyObject *CreateGlobalDictionary( bContext *C, const char *filename )
 {
        PyObject *mod;
+       PyObject *item;
        PyObject *dict = PyDict_New(  );
-       PyObject *item = PyUnicode_FromString( "__main__" );
        PyDict_SetItemString( dict, "__builtins__", PyEval_GetBuiltins(  ) );
+
+       item = PyUnicode_FromString( "__main__" );
        PyDict_SetItemString( dict, "__name__", item );
        Py_DECREF(item);
        
-       // XXX - put somewhere more logical
-       {
-               PyMethodDef *ml;
-               static PyMethodDef bpy_prop_meths[] = {
-                       {"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}
-               };
-               
-               for(ml = bpy_prop_meths; ml->ml_name; ml++) {
-                       PyDict_SetItemString( dict, ml->ml_name, PyCFunction_New(ml, NULL));
-               }
+       /* __file__ only for nice UI'ness */
+       if(filename) {
+               PyObject *item = PyUnicode_FromString( filename );
+               PyDict_SetItemString( dict, "__file__", item );
+               Py_DECREF(item);
        }
-       
+
        /* add bpy to global namespace */
        mod= PyImport_ImportModuleLevel("bpy", NULL, NULL, NULL, 0);
        PyDict_SetItemString( dict, "bpy", mod );
@@ -230,26 +191,10 @@ static PyObject *CreateGlobalDictionary( bContext *C )
        return dict;
 }
 
-/* Use this so we can include our own python bundle */
-#if 0
-wchar_t* Py_GetPath(void)
-{
-       int i;
-       static wchar_t py_path[FILE_MAXDIR] = L"";
-       char *dirname= BLI_gethome_folder("python");
-       if(dirname) {
-               i= mbstowcs(py_path, dirname, FILE_MAXDIR);
-               printf("py path %s, %d\n", dirname, i);
-       }
-       return py_path;
-}
-#endif
-
-
 /* must be called before Py_Initialize */
 void BPY_start_python_path(void)
 {
-       char *py_path_bundle= BLI_gethome_folder("python");
+       char *py_path_bundle= BLI_gethome_folder("python", BLI_GETHOME_ALL);
 
        if(py_path_bundle==NULL)
                return;
@@ -257,11 +202,46 @@ void BPY_start_python_path(void)
        /* set the environment path */
        printf("found bundled python: %s\n", py_path_bundle);
 
-       BLI_setenv("PYTHONHOME", py_path_bundle);
-       BLI_setenv("PYTHONPATH", py_path_bundle);
+#ifdef __APPLE__
+       /* OSX allow file/directory names to contain : character (represented as / in the Finder)
+        but current Python lib (release 3.1.1) doesn't handle these correctly */
+       if(strchr(py_path_bundle, ':'))
+               printf("Warning : Blender application is located in a path containing : or / chars\
+                          \nThis may make python import function fail\n");
+#endif
+       
+#ifdef _WIN32
+       /* cmake/MSVC debug build crashes without this, why only
+          in this case is unknown.. */
+       {
+               char *envpath = getenv("PYTHONPATH");
+
+               if(envpath && envpath[0]) {
+                       char *newenvpath = BLI_sprintfN("%s;%s", py_path_bundle, envpath);
+                       BLI_setenv("PYTHONPATH", newenvpath);
+                       MEM_freeN(newenvpath);
+               }
+               else
+                       BLI_setenv("PYTHONPATH", py_path_bundle);       
+       }
+#endif
+
+       {
+               static wchar_t py_path_bundle_wchar[FILE_MAXDIR];
+
+               mbstowcs(py_path_bundle_wchar, py_path_bundle, FILE_MAXDIR);
+               Py_SetPythonHome(py_path_bundle_wchar);
+       }
 }
 
 
+
+void BPY_set_context(bContext *C)
+{
+       BPy_SetContext(C);
+}
+
+/* call BPY_set_context first */
 void BPY_start_python( int argc, char **argv )
 {
        PyThreadState *py_tstate = NULL;
@@ -270,15 +250,32 @@ void BPY_start_python( int argc, char **argv )
 
        Py_Initialize(  );
        
+       /*convert argv to wchar_t*/
        // PySys_SetArgv( argc, argv); // broken in py3, not a huge deal
+       
+       /*temporarily set argv*/
        /* sigh, why do python guys not have a char** version anymore? :( */
        {
                int i;
+#if 0
                PyObject *py_argv= PyList_New(argc);
-
                for (i=0; i<argc; i++)
                        PyList_SET_ITEM(py_argv, i, PyUnicode_FromString(argv[i]));
 
+#else  // should fix bug #20021 - utf path name problems
+               PyObject *py_argv= PyList_New(0);
+               for (i=0; i<argc; i++) {
+                       PyObject *item= PyUnicode_Decode(argv[i], strlen(argv[i]), Py_FileSystemDefaultEncoding, NULL);
+                       if(item==NULL) { // should never happen
+                               PyErr_Print();
+                               PyErr_Clear();
+                       }
+                       else {
+                               PyList_Append(py_argv, item);
+                               Py_DECREF(item);
+                       }
+               }
+#endif
                PySys_SetObject("argv", py_argv);
                Py_DECREF(py_argv);
        }
@@ -288,7 +285,7 @@ void BPY_start_python( int argc, char **argv )
        
        
        /* bpy.* and lets us import it */
-       bpy_init_modules(); 
+       BPy_init_modules();
 
        { /* our own import and reload functions */
                PyObject *item;
@@ -351,7 +348,7 @@ int BPY_run_python_script( bContext *C, const char *fn, struct Text *text, struc
        
        bpy_context_set(C, &gilstate);
        
-       py_dict = CreateGlobalDictionary(C);
+       py_dict = CreateGlobalDictionary(C, text?text->id.name+2:fn);
 
        if (text) {
                
@@ -371,24 +368,32 @@ int BPY_run_python_script( bContext *C, const char *fn, struct Text *text, struc
                        py_result =  PyEval_EvalCode( text->compiled, py_dict, py_dict );
                
        } else {
-#if 0
-               char *pystring;
-               pystring= malloc(strlen(fn) + 32);
-               pystring[0]= '\0';
-               sprintf(pystring, "exec(open(r'%s').read())", fn);
-               py_result = PyRun_String( pystring, Py_file_input, py_dict, py_dict );
-               free(pystring);
-#else
                FILE *fp= fopen(fn, "r");               
                if(fp) {
+#ifdef _WIN32
+                       /* Previously we used PyRun_File to run directly the code on a FILE 
+                        * object, but as written in the Python/C API Ref Manual, chapter 2,
+                        * 'FILE structs for different C libraries can be different and 
+                        * incompatible'.
+                        * So now we load the script file data to a buffer */
+                       char *pystring;
+
+                       fclose(fp);
+
+                       pystring= MEM_mallocN(strlen(fn) + 32, "pystring");
+                       pystring[0]= '\0';
+                       sprintf(pystring, "exec(open(r'%s').read())", fn);
+                       py_result = PyRun_String( pystring, Py_file_input, py_dict, py_dict );
+                       MEM_freeN(pystring);
+#else
                        py_result = PyRun_File(fp, fn, Py_file_input, py_dict, py_dict);
                        fclose(fp);
+#endif
                }
                else {
                        PyErr_Format(PyExc_SystemError, "Python file \"%s\" could not be opened: %s", fn, strerror(errno));
                        py_result= NULL;
                }
-#endif
        }
        
        if (!py_result) {
@@ -488,7 +493,9 @@ int BPY_run_script_space_listener(bContext *C, SpaceScript * sc)
 
 void BPY_DECREF(void *pyob_ptr)
 {
+       PyGILState_STATE gilstate = PyGILState_Ensure();
        Py_DECREF((PyObject *)pyob_ptr);
+       PyGILState_Release(gilstate);
 }
 
 #if 0
@@ -546,319 +553,34 @@ int BPY_run_python_script_space(const char *modulename, const char *func)
 #include "PIL_time.h"
 #endif
 
-/* for use by BPY_run_ui_scripts only */
-static int bpy_import_module(char *modname, int reload)
-{
-       PyObject *mod= PyImport_ImportModuleLevel(modname, NULL, NULL, NULL, 0);
-       if (mod) {
-               if (reload) {
-                       PyObject *mod_orig= mod;
-                       mod= PyImport_ReloadModule(mod);
-                       Py_DECREF(mod_orig);
-               }
-       }
 
-       if(mod) {
-               Py_DECREF(mod); /* could be NULL from reloading */
-               return 0;
-       } else {
-               return -1;
-       }
-}
-
-/* XXX this is temporary, need a proper script registration system for 2.5 */
-void BPY_run_ui_scripts(bContext *C, int reload)
+int BPY_button_eval(bContext *C, char *expr, double *value)
 {
-#ifdef TIME_REGISTRATION
-       double time = PIL_check_seconds_timer();
-#endif
-       DIR *dir; 
-       struct dirent *de;
-       char *file_extension;
-       char *dirname;
-       char path[FILE_MAX];
-       char *dirs[] = {"ui", "io", NULL};
-       int a, err;
-       
        PyGILState_STATE gilstate;
-       PyObject *sys_path;
-
-       bpy_context_set(C, &gilstate);
-
-       sys_path= PySys_GetObject("path"); /* borrow */
-       PyList_Insert(sys_path, 0, Py_None); /* place holder, resizes the list */
-
-       for(a=0; dirs[a]; a++) {
-               dirname= BLI_gethome_folder(dirs[a]);
-
-               if(!dirname)
-                       continue;
-
-               dir = opendir(dirname);
-
-               if(!dir)
-                       continue;
-               
-               /* set the first dir in the sys.path for fast importing of modules */
-               PyList_SetItem(sys_path, 0, PyUnicode_FromString(dirname)); /* steals the ref */
-                       
-               while((de = readdir(dir)) != NULL) {
-                       /* We could stat the file but easier just to let python
-                        * import it and complain if theres a problem */
-                       err = 0;
-
-                       if (de->d_name[0] == '.') {
-                               /* do nothing, probably .svn */
-                       }
-                       else if ((file_extension = strstr(de->d_name, ".py"))) {
-                               /* normal py files? */
-                               if(file_extension && file_extension[3] == '\0') {
-                                       de->d_name[(file_extension - de->d_name)] = '\0';
-                                       err= bpy_import_module(de->d_name, reload);
-                               }
-                       }
-#ifndef __linux__
-                       else if( BLI_join_dirfile(path, dirname, de->d_name), S_ISDIR(BLI_exist(path))) {
-#else
-                       else if(de->d_type==DT_DIR) {
-                               BLI_join_dirfile(path, dirname, de->d_name);
-#endif
-                               /* support packages */
-                               BLI_join_dirfile(path, path, "__init__.py");
-
-                               if(BLI_exists(path)) {
-                                       err= bpy_import_module(de->d_name, reload);
-                               }
-                       }
-
-                       if(err==-1) {
-                               BPy_errors_to_report(NULL);
-                               fprintf(stderr, "unable to import %s/%s\n", dirname, de->d_name);
-                       }
-               }
-
-               closedir(dir);
-       }
-       
-       PyList_SetSlice(sys_path, 0, 1, NULL); /* remove the first item */
-
-       bpy_context_clear(C, &gilstate);
+       PyObject *dict, *mod, *retval;
+       int error_ret = 0;
        
-#ifdef TIME_REGISTRATION
-       printf("script time %f\n", (PIL_check_seconds_timer()-time));
-#endif
-
-       /* reset the timer so as not to take loading into the stats */
-       bpy_timer_count = 0;
-}
-
-/* ****************************************** */
-/* Drivers - PyExpression Evaluation */
+       if (!value || !expr) return -1;
 
-/* for pydrivers (drivers using one-line Python expressions to express relationships between targets) */
-PyObject *bpy_pydriver_Dict = NULL;
+       if(expr[0]=='\0') {
+               *value= 0.0;
+               return error_ret;
+       }
 
-/* For faster execution we keep a special dictionary for pydrivers, with
- * the needed modules and aliases. 
- */
-static int bpy_pydriver_create_dict(void)
-{
-       PyObject *d, *mod;
+       bpy_context_set(C, &gilstate);
        
-       /* validate namespace for driver evaluation */
-       if (bpy_pydriver_Dict) return -1;
-
-       d = PyDict_New();
-       if (d == NULL) 
-               return -1;
-       else
-               bpy_pydriver_Dict = d;
-
-       /* import some modules: builtins, bpy, math, (Blender.noise )*/
-       PyDict_SetItemString(d, "__builtins__", PyEval_GetBuiltins());
+       dict= CreateGlobalDictionary(C, NULL);
 
        mod = PyImport_ImportModule("math");
        if (mod) {
-               PyDict_Merge(d, PyModule_GetDict(mod), 0); /* 0 - dont overwrite existing values */
-               
-               /* Only keep for backwards compat! - just import all math into root, they are standard */
-               PyDict_SetItemString(d, "math", mod);
-               PyDict_SetItemString(d, "m", mod);
-               Py_DECREF(mod);
-       } 
-       
-       /* add bpy to global namespace */
-       mod= PyImport_ImportModuleLevel("bpy", NULL, NULL, NULL, 0);
-       if (mod) {
-               PyDict_SetItemString(bpy_pydriver_Dict, "bpy", mod);
+               PyDict_Merge(dict, PyModule_GetDict(mod), 0); /* 0 - dont overwrite existing values */
                Py_DECREF(mod);
        }
-       
-       
-#if 0 // non existant yet
-       mod = PyImport_ImportModule("Blender.Noise");
-       if (mod) {
-               PyDict_SetItemString(d, "noise", mod);
-               PyDict_SetItemString(d, "n", mod);
-               Py_DECREF(mod);
-       } else {
+       else { /* highly unlikely but possibly */
+               PyErr_Print();
                PyErr_Clear();
        }
        
-       /* If there's a Blender text called pydrivers.py, import it.
-        * Users can add their own functions to this module. 
-        */
-       if (G.f & G_DOSCRIPTLINKS) {
-               mod = importText("pydrivers"); /* can also use PyImport_Import() */
-               if (mod) {
-                       PyDict_SetItemString(d, "pydrivers", mod);
-                       PyDict_SetItemString(d, "p", mod);
-                       Py_DECREF(mod);
-               } else {
-                       PyErr_Clear();
-               }
-       }
-#endif // non existant yet
-       
-       return 0;
-}
-
-/* Update function, it gets rid of pydrivers global dictionary, forcing
- * BPY_pydriver_eval to recreate it. This function is used to force
- * reloading the Blender text module "pydrivers.py", if available, so
- * updates in it reach pydriver evaluation. 
- */
-void BPY_pydriver_update(void)
-{
-       PyGILState_STATE gilstate = PyGILState_Ensure();
-
-       if (bpy_pydriver_Dict) { /* free the global dict used by pydrivers */
-               PyDict_Clear(bpy_pydriver_Dict);
-               Py_DECREF(bpy_pydriver_Dict);
-               bpy_pydriver_Dict = NULL;
-       }
-
-       PyGILState_Release(gilstate);
-
-       return;
-}
-
-/* error return function for BPY_eval_pydriver */
-static float pydriver_error(ChannelDriver *driver) 
-{
-       if (bpy_pydriver_Dict) { /* free the global dict used by pydrivers */
-               PyDict_Clear(bpy_pydriver_Dict);
-               Py_DECREF(bpy_pydriver_Dict);
-               bpy_pydriver_Dict = NULL;
-       }
-
-       driver->flag |= DRIVER_FLAG_INVALID; /* py expression failed */
-       fprintf(stderr, "\nError in Driver: The following Python expression failed:\n\t'%s'\n\n", driver->expression);
-       
-       BPy_errors_to_report(NULL); // TODO - reports
-
-       return 0.0f;
-}
-
-/* This evals py driver expressions, 'expr' is a Python expression that
- * should evaluate to a float number, which is returned. 
- */
-float BPY_pydriver_eval (ChannelDriver *driver)
-{
-       PyObject *driver_vars=NULL;
-       PyObject *retval;
-       PyGILState_STATE gilstate;
-       
-       DriverTarget *dtar;
-       float result = 0.0f; /* default return */
-       char *expr = NULL;
-       short targets_ok= 1;
-       
-       /* sanity checks - should driver be executed? */
-       if ((driver == NULL) /*|| (G.f & G_DOSCRIPTLINKS)==0*/) 
-               return result;
-       
-       /* get the py expression to be evaluated */
-       expr = driver->expression; 
-       if ((expr == NULL) || (expr[0]=='\0')) 
-               return result;
-
-       gilstate = PyGILState_Ensure();
-       
-       /* init global dictionary for py-driver evaluation settings */
-       if (!bpy_pydriver_Dict) {
-               if (bpy_pydriver_create_dict() != 0) {
-                       fprintf(stderr, "Pydriver error: couldn't create Python dictionary");
-                       PyGILState_Release(gilstate);
-                       return result;
-               }
-       }
-       
-       /* add target values to a dict that will be used as '__locals__' dict */
-       driver_vars = PyDict_New(); // XXX do we need to decref this?
-       for (dtar= driver->targets.first; dtar; dtar= dtar->next) {
-               PyObject *driver_arg = NULL;
-               float tval = 0.0f;
-               
-               /* try to get variable value */
-               tval= driver_get_target_value(driver, dtar);
-               driver_arg= PyFloat_FromDouble((double)tval);
-               
-               /* try to add to dictionary */
-               if (PyDict_SetItemString(driver_vars, dtar->name, driver_arg)) {
-                       /* this target failed - bad name */
-                       if (targets_ok) {
-                               /* first one - print some extra info for easier identification */
-                               fprintf(stderr, "\nBPY_pydriver_eval() - Error while evaluating PyDriver:\n");
-                               targets_ok= 0;
-                       }
-                       
-                       fprintf(stderr, "\tBPY_pydriver_eval() - couldn't add variable '%s' to namespace \n", dtar->name);
-                       BPy_errors_to_report(NULL); // TODO - reports
-               }
-       }
-       
-       /* execute expression to get a value */
-       retval = PyRun_String(expr, Py_eval_input, bpy_pydriver_Dict, driver_vars);
-       
-       /* decref the driver vars first...  */
-       Py_DECREF(driver_vars);
-       
-       /* process the result */
-       if (retval == NULL) {
-               result = pydriver_error(driver);
-               PyGILState_Release(gilstate);
-               return result;
-       }
-
-       result = (float)PyFloat_AsDouble(retval);
-       Py_DECREF(retval);
-       
-       if ((result == -1) && PyErr_Occurred()) {
-               result = pydriver_error(driver);
-               PyGILState_Release(gilstate);
-               return result;
-       }
-       
-       /* all fine, make sure the "invalid expression" flag is cleared */
-       driver->flag &= ~DRIVER_FLAG_INVALID;
-
-       PyGILState_Release(gilstate);
-
-       return result;
-}
-
-int BPY_button_eval(bContext *C, char *expr, double *value)
-{
-       PyGILState_STATE gilstate;
-       PyObject *dict, *retval;
-       int error_ret = 0;
-       
-       if (!value || !expr || expr[0]=='\0') return -1;
-       
-       bpy_context_set(C, &gilstate);
-       
-       dict= CreateGlobalDictionary(C);
        retval = PyRun_String(expr, Py_eval_input, dict, dict);
        
        if (retval == NULL) {
@@ -900,3 +622,99 @@ int BPY_button_eval(bContext *C, char *expr, double *value)
        return error_ret;
 }
 
+void BPY_load_user_modules(bContext *C)
+{
+       PyGILState_STATE gilstate;
+       Main *bmain= CTX_data_main(C);
+       Text *text;
+
+       /* can happen on file load */
+       if(bmain==NULL)
+               return;
+
+       bpy_context_set(C, &gilstate);
+
+       for(text=CTX_data_main(C)->text.first; text; text= text->id.next) {
+               if(text->flags & TXT_ISSCRIPT && BLI_testextensie(text->id.name+2, ".py")) {
+                       if(!(G.f & G_SCRIPT_AUTOEXEC)) {
+                               printf("scripts disabled for \"%s\", skipping '%s'\n", bmain->name, text->id.name+2);
+                       }
+                       else {
+                               PyObject *module= bpy_text_import(text);
+
+                               if (module==NULL) {
+                                       PyErr_Print();
+                                       PyErr_Clear();
+                               }
+                               else {
+                                       Py_DECREF(module);
+                               }
+                       }
+               }
+       }
+       bpy_context_clear(C, &gilstate);
+}
+
+int BPY_context_get(bContext *C, const char *member, bContextDataResult *result)
+{
+       PyObject *pyctx= (PyObject *)CTX_py_dict_get(C);
+       PyObject *item= PyDict_GetItemString(pyctx, member);
+       PointerRNA *ptr= NULL;
+       int done= 0;
+
+       if(item==NULL) {
+               /* pass */
+       }
+       else if(item==Py_None) {
+               /* pass */
+       }
+       else if(BPy_StructRNA_Check(item)) {
+               ptr= &(((BPy_StructRNA *)item)->ptr);
+
+               //result->ptr= ((BPy_StructRNA *)item)->ptr;
+               CTX_data_pointer_set(result, ptr->id.data, ptr->type, ptr->data);
+               done= 1;
+       }
+       else if (PySequence_Check(item)) {
+               PyObject *seq_fast= PySequence_Fast(item, "bpy_context_get sequence conversion");
+               if (seq_fast==NULL) {
+                       PyErr_Print();
+                       PyErr_Clear();
+               }
+               else {
+                       int len= PySequence_Fast_GET_SIZE(seq_fast);
+                       int i;
+                       for(i = 0; i < len; i++) {
+                               PyObject *list_item= PySequence_Fast_GET_ITEM(seq_fast, i);
+
+                               if(BPy_StructRNA_Check(list_item)) {
+                                       /*
+                                       CollectionPointerLink *link= MEM_callocN(sizeof(CollectionPointerLink), "bpy_context_get");
+                                       link->ptr= ((BPy_StructRNA *)item)->ptr;
+                                       BLI_addtail(&result->list, link);
+                                       */
+                                       ptr= &(((BPy_StructRNA *)list_item)->ptr);
+                                       CTX_data_list_add(result, ptr->id.data, ptr->type, ptr->data);
+                               }
+                               else {
+                                       printf("List item not a valid type\n");
+                               }
+
+                       }
+                       Py_DECREF(seq_fast);
+
+                       done= 1;
+               }
+       }
+
+       if(done==0) {
+               if (item)       printf("Context '%s' not a valid type\n", member);
+               else            printf("Context '%s' not found\n", member);
+       }
+       else {
+               printf("Context '%s' found\n", member);
+       }
+
+       return done;
+}
+