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 9a14717b060f58f12b21123e8e5700653c61bd41..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
@@ -38,9 +38,8 @@
 #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"
 
 #ifndef WIN32
 #include "BLI_winstuff.h"
 #endif
 
-#include "DNA_anim_types.h"
 #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_global.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"
-#include "../generic/IDProp.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
@@ -151,18 +141,6 @@ void bpy_context_clear(bContext *C, PyGILState_STATE *gilstate)
        }
 }
 
-static void bpy_import_test(char *modname)
-{
-       PyObject *mod= PyImport_ImportModuleLevel(modname, NULL, NULL, NULL, 0);
-       if(mod) {
-               Py_DECREF(mod);
-       }
-       else {
-               PyErr_Print();
-               PyErr_Clear();
-       }       
-}
-
 void BPY_free_compiled_text( struct Text *text )
 {
        if( text->compiled ) {
@@ -171,62 +149,6 @@ void BPY_free_compiled_text( struct Text *text )
        }
 }
 
-/*****************************************************************************
-* Description: Creates the bpy module and adds it to sys.modules for importing
-*****************************************************************************/
-static BPy_StructRNA *bpy_context_module= NULL; /* for fast access */
-static void bpy_init_modules( void )
-{
-       PyObject *mod;
-
-       /* Needs to be first since this dir is needed for future modules */
-       char *modpath= BLI_gethome_folder("scripts/modules", BLI_GETHOME_ALL);
-       if(modpath) {
-               PyObject *sys_path= PySys_GetObject("path"); /* borrow */
-               PyObject *py_modpath= PyUnicode_FromString(modpath);
-               PyList_Insert(sys_path, 0, py_modpath); /* add first */
-               Py_DECREF(py_modpath);
-       }
-       
-       /* stand alone utility modules not related to blender directly */
-       Geometry_Init();
-       Mathutils_Init();
-       BGL_Init();
-       IDProp_Init_Types();
-
-
-       mod = PyModule_New("_bpy");
-
-       /* add the module so we can import it */
-       PyDict_SetItemString(PySys_GetObject("modules"), "_bpy", mod);
-       Py_DECREF(mod);
-
-       /* run first, initializes rna types */
-       BPY_rna_init();
-
-       PyModule_AddObject( mod, "types", BPY_rna_types() ); /* needs to be first so bpy_types can run */
-       bpy_import_test("bpy_types");
-       PyModule_AddObject( mod, "data", BPY_rna_module() ); /* imports bpy_types by running this */
-       bpy_import_test("bpy_types");
-       /* PyModule_AddObject( mod, "doc", BPY_rna_doc() ); */
-       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
-
-
-
-       /* bpy context */
-       {
-               bpy_context_module= ( BPy_StructRNA * ) PyObject_NEW( BPy_StructRNA, &pyrna_struct_Type );
-               RNA_pointer_create(NULL, &RNA_Context, NULL, &bpy_context_module->ptr);
-
-               PyModule_AddObject(mod, "context", (PyObject *)bpy_context_module);
-       }
-
-       /* add our own modules dir, this is a python package */
-       bpy_import_test("bpy");
-}
-
 void BPY_update_modules( void )
 {
 #if 0 // slow, this runs all the time poll, draw etc 100's of time a sec.
@@ -280,9 +202,28 @@ void BPY_start_python_path(void)
        /* set the environment path */
        printf("found bundled python: %s\n", py_path_bundle);
 
-#if 0
-       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
 
        {
@@ -309,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);
        }
@@ -327,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;
@@ -422,11 +380,11 @@ int BPY_run_python_script( bContext *C, const char *fn, struct Text *text, struc
 
                        fclose(fp);
 
-                       pystring= malloc(strlen(fn) + 32);
+                       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 );
-                       free(pystring);
+                       MEM_freeN(pystring);
 #else
                        py_result = PyRun_File(fp, fn, Py_file_input, py_dict, py_dict);
                        fclose(fp);
@@ -535,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
@@ -593,201 +553,6 @@ int BPY_run_python_script_space(const char *modulename, const char *func)
 #include "PIL_time.h"
 #endif
 
-/* ****************************************** */
-/* Drivers - PyExpression Evaluation */
-
-/* for pydrivers (drivers using one-line Python expressions to express relationships between targets) */
-PyObject *bpy_pydriver_Dict = NULL;
-
-/* 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;
-       
-       /* 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());
-
-       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);
-               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 {
-               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)
 {
@@ -795,24 +560,26 @@ int BPY_button_eval(bContext *C, char *expr, double *value)
        PyObject *dict, *mod, *retval;
        int error_ret = 0;
        
-       if (!value || !expr || expr[0]=='\0') return -1;
-       
+       if (!value || !expr) return -1;
+
+       if(expr[0]=='\0') {
+               *value= 0.0;
+               return error_ret;
+       }
+
        bpy_context_set(C, &gilstate);
        
        dict= CreateGlobalDictionary(C, NULL);
-       
-       /* import some modules: builtins,math*/
-       PyDict_SetItemString(dict, "__builtins__", PyEval_GetBuiltins());
 
        mod = PyImport_ImportModule("math");
        if (mod) {
                PyDict_Merge(dict, 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(dict, "math", mod);
-               PyDict_SetItemString(dict, "m", mod);
                Py_DECREF(mod);
-       } 
+       }
+       else { /* highly unlikely but possibly */
+               PyErr_Print();
+               PyErr_Clear();
+       }
        
        retval = PyRun_String(expr, Py_eval_input, dict, dict);
        
@@ -858,20 +625,30 @@ int BPY_button_eval(bContext *C, char *expr, double *value)
 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")) {
-                       PyObject *module= bpy_text_import(text);
-
-                       if (module==NULL) {
-                               PyErr_Print();
-                               PyErr_Clear();
+                       if(!(G.f & G_SCRIPT_AUTOEXEC)) {
+                               printf("scripts disabled for \"%s\", skipping '%s'\n", bmain->name, text->id.name+2);
                        }
                        else {
-                               Py_DECREF(module);
+                               PyObject *module= bpy_text_import(text);
+
+                               if (module==NULL) {
+                                       PyErr_Print();
+                                       PyErr_Clear();
+                               }
+                               else {
+                                       Py_DECREF(module);
+                               }
                        }
                }
        }
@@ -934,7 +711,7 @@ int BPY_context_get(bContext *C, const char *member, bContextDataResult *result)
                if (item)       printf("Context '%s' not a valid type\n", member);
                else            printf("Context '%s' not found\n", member);
        }
-       else if (G.f & G_DEBUG) {
+       else {
                printf("Context '%s' found\n", member);
        }