Merged changes in the trunk up to revision 42116.
[blender.git] / source / blender / python / intern / bpy_interface.c
index 51bf02ad37f8ac58b6b348932e3df96c3a181413..b7ead49633c71490c64d2cfe5af1dff6b0a4c96d 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
 
 /** \file blender/python/intern/bpy_interface.c
  *  \ingroup pythonintern
+ *
+ * This file deals with embedding the python interpreter within blender,
+ * starting and stopping python and exposing blender/python modules so they can
+ * be accesses from scripts.
  */
 
  
 /* grr, python redefines */
 #ifdef _POSIX_C_SOURCE
-#undef _POSIX_C_SOURCE
+#  undef _POSIX_C_SOURCE
 #endif
 
 #include <Python.h>
@@ -40,6 +42,7 @@
 #include "RNA_types.h"
 
 #include "bpy.h"
+#include "gpu.h"
 #include "bpy_rna.h"
 #include "bpy_util.h"
 #include "bpy_traceback.h"
 #include "BLI_path_util.h"
 #include "BLI_math_base.h"
 #include "BLI_string.h"
+#include "BLI_string_utf8.h"
 #include "BLI_utildefines.h"
 
 
 #include "BKE_context.h"
 #include "BKE_text.h"
-#include "BKE_font.h" /* only for utf8towchar */
 #include "BKE_main.h"
 #include "BKE_global.h" /* only for script checking */
 
 #include "../generic/py_capi_utils.h"
 
 /* inittab initialization functions */
-#include "../generic/noise_py_api.h"
-#include "../generic/mathutils.h"
 #include "../generic/bgl.h"
 #include "../generic/blf_py_api.h"
+#include "../generic/noise_py_api.h"
+#include "../mathutils/mathutils.h"
 
 /* for internal use, when starting and ending python scripts */
 
@@ -87,27 +90,26 @@ static double       bpy_timer_run; /* time for each python script run */
 static double  bpy_timer_run_tot; /* accumulate python runs */
 #endif
 
+/* use for updating while a python script runs - in case of file load */
+void bpy_context_update(bContext *C)
+{
+       BPy_SetContext(C);
+       bpy_import_main_set(CTX_data_main(C));
+       BPY_modules_update(C); /* can give really bad results if this isnt here */
+}
+
 void bpy_context_set(bContext *C, PyGILState_STATE *gilstate)
 {
        py_call_level++;
 
-       if(gilstate)
+       if (gilstate)
                *gilstate= PyGILState_Ensure();
 
-       if(py_call_level==1) {
-
-               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");
-               }
-
-               BPY_modules_update(C); /* can give really bad results if this isnt here */
+       if (py_call_level==1) {
+               bpy_context_update(C);
 
 #ifdef TIME_PY_RUN
-               if(bpy_timer_count==0) {
+               if (bpy_timer_count==0) {
                        /* record time from the beginning */
                        bpy_timer= PIL_check_seconds_timer();
                        bpy_timer_run= bpy_timer_run_tot= 0.0;
@@ -125,13 +127,13 @@ void bpy_context_clear(bContext *UNUSED(C), PyGILState_STATE *gilstate)
 {
        py_call_level--;
 
-       if(gilstate)
+       if (gilstate)
                PyGILState_Release(*gilstate);
 
-       if(py_call_level < 0) {
+       if (py_call_level < 0) {
                fprintf(stderr, "ERROR: Python context internal state bug. this should not happen!\n");
        }
-       else if(py_call_level==0) {
+       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);
@@ -146,7 +148,7 @@ void bpy_context_clear(bContext *UNUSED(C), PyGILState_STATE *gilstate)
 
 void BPY_text_free_code(Text *text)
 {
-       if(text->compiled) {
+       if (text->compiled) {
                Py_DECREF((PyObject *)text->compiled);
                text->compiled= NULL;
        }
@@ -172,16 +174,22 @@ void BPY_context_set(bContext *C)
 
 /* defined in AUD_C-API.cpp */
 extern PyObject *AUD_initPython(void);
+/* defined in cycles/blender */
+extern PyObject *CYCLES_initPython(void);
 
 static struct _inittab bpy_internal_modules[]= {
        {(char *)"noise", BPyInit_noise},
-       {(char *)"mathutils", BPyInit_mathutils},
-//     {(char *)"mathutils.geometry", BPyInit_mathutils_geometry},
+       {(char *)"mathutils", PyInit_mathutils},
+//     {(char *)"mathutils.geometry", PyInit_mathutils_geometry},
        {(char *)"bgl", BPyInit_bgl},
        {(char *)"blf", BPyInit_blf},
 #ifdef WITH_AUDASPACE
        {(char *)"aud", AUD_initPython},
 #endif
+#ifdef WITH_CYCLES
+       {(char *)"bcycles", CYCLES_initPython},
+#endif
+       {(char *)"gpu", GPU_initPython},
        {NULL, NULL}
 };
 
@@ -192,9 +200,9 @@ void BPY_python_start(int argc, const char **argv)
        PyThreadState *py_tstate= NULL;
 
        /* not essential but nice to set our name */
-       static wchar_t bprogname_wchar[FILE_MAXDIR+FILE_MAXFILE]; /* python holds a reference */
-       utf8towchar(bprogname_wchar, bprogname);
-       Py_SetProgramName(bprogname_wchar);
+       static wchar_t program_path_wchar[FILE_MAX]; /* python holds a reference */
+       BLI_strncpy_wchar_from_utf8(program_path_wchar, BLI_program_path(), sizeof(program_path_wchar) / sizeof(wchar_t));
+       Py_SetProgramName(program_path_wchar);
 
        /* must run before python initializes */
        PyImport_ExtendInittab(bpy_internal_modules);
@@ -202,22 +210,30 @@ void BPY_python_start(int argc, const char **argv)
        /* allow to use our own included python */
        PyC_SetHomePath(BLI_get_folder(BLENDER_SYSTEM_PYTHON, NULL));
 
-       /* Python 3.2 now looks for '2.58/python/include/python3.2d/pyconfig.h' to parse
-        * from the 'sysconfig' module which is used by 'site', so for now disable site.
-        * alternatively we could copy the file. */
+       /* without this the sys.stdout may be set to 'ascii'
+        * (it is on my system at least), where printing unicode values will raise
+        * an error, this is highly annoying, another stumbling block for devs,
+        * so use a more relaxed error handler and enforce utf-8 since the rest of
+        * blender is utf-8 too - campbell */
+       BLI_setenv("PYTHONIOENCODING", "utf-8:surrogateescape");
+
+       /* Python 3.2 now looks for '2.xx/python/include/python3.2d/pyconfig.h' to
+        * parse from the 'sysconfig' module which is used by 'site',
+        * so for now disable site. alternatively we could copy the file. */
        Py_NoSiteFlag= 1;
 
        Py_Initialize();
 
-       bpy_intern_string_init();
-
        // PySys_SetArgv(argc, argv); // broken in py3, not a huge deal
        /* sigh, why do python guys not have a char** version anymore? :( */
        {
                int i;
                PyObject *py_argv= PyList_New(argc);
-               for (i=0; i<argc; i++)
-                       PyList_SET_ITEM(py_argv, i, PyC_UnicodeFromByte(argv[i])); /* should fix bug #20021 - utf path name problems, by replacing PyUnicode_FromString */
+               for (i=0; i<argc; i++) {
+                       /* should fix bug #20021 - utf path name problems, by replacing
+                        * PyUnicode_FromString, with this one */
+                       PyList_SET_ITEM(py_argv, i, PyC_UnicodeFromByte(argv[i]));
+               }
 
                PySys_SetObject("argv", py_argv);
                Py_DECREF(py_argv);
@@ -233,6 +249,8 @@ void BPY_python_start(int argc, const char **argv)
        PyImport_ExtendInittab(bpy_internal_modules);
 #endif
 
+       bpy_intern_string_init();
+
        /* bpy.* and lets us import it */
        BPy_init_modules();
 
@@ -240,6 +258,8 @@ void BPY_python_start(int argc, const char **argv)
        
        pyrna_alloc_types();
 
+       BPY_atexit_register(); /* this can init any time */
+
 #ifndef WITH_PYTHON_MODULE
        py_tstate= PyGILState_GetThisThreadState();
        PyEval_ReleaseThread(py_tstate);
@@ -259,6 +279,8 @@ void BPY_python_end(void)
 
        bpy_intern_string_exit();
 
+       BPY_atexit_unregister(); /* without this we get recursive calls to WM_exit */
+
        Py_Finalize();
        
 #ifdef TIME_PY_RUN
@@ -268,10 +290,10 @@ void BPY_python_end(void)
        printf("*bpy stats* - ");
        printf("tot exec: %d,  ", bpy_timer_count);
        printf("tot run: %.4fsec,  ", bpy_timer_run_tot);
-       if(bpy_timer_count>0)
+       if (bpy_timer_count>0)
                printf("average run: %.6fsec,  ", (bpy_timer_run_tot/bpy_timer_count));
 
-       if(bpy_timer>0.0)
+       if (bpy_timer>0.0)
                printf("tot usage %.4f%%", (bpy_timer_run_tot/bpy_timer)*100.0);
 
        printf("\n");
@@ -287,7 +309,7 @@ static void python_script_error_jump_text(struct Text *text)
        int lineno;
        int offset;
        python_script_error_jump(text->id.name+2, &lineno, &offset);
-       if(lineno != -1) {
+       if (lineno != -1) {
                /* select the line with the error */
                txt_move_to(text, lineno - 1, INT_MAX, FALSE);
                txt_move_to(text, lineno - 1, offset, TRUE);
@@ -327,22 +349,22 @@ static int python_script_exec(bContext *C, const char *fn, struct Text *text, st
                char fn_dummy[FILE_MAXDIR];
                bpy_text_filename_get(fn_dummy, sizeof(fn_dummy), text);
 
-               if(text->compiled == NULL) {    /* if it wasn't already compiled, do it now */
+               if (text->compiled == NULL) {   /* if it wasn't already compiled, do it now */
                        char *buf= txt_to_buf(text);
 
                        text->compiled= Py_CompileString(buf, fn_dummy, Py_file_input);
 
                        MEM_freeN(buf);
 
-                       if(PyErr_Occurred()) {
-                               if(do_jump) {
+                       if (PyErr_Occurred()) {
+                               if (do_jump) {
                                        python_script_error_jump_text(text);
                                }
                                BPY_text_free_code(text);
                        }
                }
 
-               if(text->compiled) {
+               if (text->compiled) {
                        py_dict= PyC_DefaultNameSpace(fn_dummy);
                        py_result=  PyEval_EvalCode(text->compiled, py_dict, py_dict);
                }
@@ -351,7 +373,7 @@ static int python_script_exec(bContext *C, const char *fn, struct Text *text, st
        else {
                FILE *fp= fopen(fn, "r");
 
-               if(fp) {
+               if (fp) {
                        py_dict= PyC_DefaultNameSpace(fn);
 
 #ifdef _WIN32
@@ -385,8 +407,8 @@ static int python_script_exec(bContext *C, const char *fn, struct Text *text, st
        }
 
        if (!py_result) {
-               if(text) {
-                       if(do_jump) {
+               if (text) {
+                       if (do_jump) {
                                python_script_error_jump_text(text);
                        }
                }
@@ -396,7 +418,7 @@ static int python_script_exec(bContext *C, const char *fn, struct Text *text, st
                Py_DECREF(py_result);
        }
 
-       if(py_dict) {
+       if (py_dict) {
 #ifdef PYMODULE_CLEAR_WORKAROUND
                PyModuleObject *mmod= (PyModuleObject *)PyDict_GetItemString(PyThreadState_GET()->interp->modules, "__main__");
                PyObject *dict_back= mmod->md_dict;
@@ -445,7 +467,7 @@ int BPY_button_exec(bContext *C, const char *expr, double *value, const short ve
        
        if (!value || !expr) return -1;
 
-       if(expr[0]=='\0') {
+       if (expr[0]=='\0') {
                *value= 0.0;
                return error_ret;
        }
@@ -474,13 +496,13 @@ int BPY_button_exec(bContext *C, const char *expr, double *value, const short ve
        else {
                double val;
 
-               if(PyTuple_Check(retval)) {
+               if (PyTuple_Check(retval)) {
                        /* Users my have typed in 10km, 2m
                         * add up all values */
                        int i;
                        val= 0.0;
 
-                       for(i=0; i<PyTuple_GET_SIZE(retval); i++) {
+                       for (i=0; i<PyTuple_GET_SIZE(retval); i++) {
                                val+= PyFloat_AsDouble(PyTuple_GET_ITEM(retval, i));
                        }
                }
@@ -489,7 +511,7 @@ int BPY_button_exec(bContext *C, const char *expr, double *value, const short ve
                }
                Py_DECREF(retval);
                
-               if(val==-1 && PyErr_Occurred()) {
+               if (val==-1 && PyErr_Occurred()) {
                        error_ret= -1;
                }
                else if (!finite(val)) {
@@ -500,8 +522,8 @@ int BPY_button_exec(bContext *C, const char *expr, double *value, const short ve
                }
        }
        
-       if(error_ret) {
-               if(verbose) {
+       if (error_ret) {
+               if (verbose) {
                        BPy_errors_to_report(CTX_wm_reports(C));
                }
                else {
@@ -526,7 +548,7 @@ int BPY_string_exec(bContext *C, const char *expr)
 
        if (!expr) return -1;
 
-       if(expr[0]=='\0') {
+       if (expr[0]=='\0') {
                return error_ret;
        }
 
@@ -567,14 +589,20 @@ void BPY_modules_load_user(bContext *C)
        Text *text;
 
        /* can happen on file load */
-       if(bmain==NULL)
+       if (bmain==NULL)
                return;
 
+       /* update pointers since this can run from a nested script
+        * on file load */
+       if (py_call_level) {
+               bpy_context_update(C);
+       }
+
        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)) {
+       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 {
@@ -600,13 +628,13 @@ int BPY_context_member_get(bContext *C, const char *member, bContextDataResult *
        PointerRNA *ptr= NULL;
        int done= 0;
 
-       if(item==NULL) {
+       if (item==NULL) {
                /* pass */
        }
-       else if(item==Py_None) {
+       else if (item==Py_None) {
                /* pass */
        }
-       else if(BPy_StructRNA_Check(item)) {
+       else if (BPy_StructRNA_Check(item)) {
                ptr= &(((BPy_StructRNA *)item)->ptr);
 
                //result->ptr= ((BPy_StructRNA *)item)->ptr;
@@ -622,10 +650,10 @@ int BPY_context_member_get(bContext *C, const char *member, bContextDataResult *
                else {
                        int len= PySequence_Fast_GET_SIZE(seq_fast);
                        int i;
-                       for(i= 0; i < len; i++) {
+                       for (i= 0; i < len; i++) {
                                PyObject *list_item= PySequence_Fast_GET_ITEM(seq_fast, i);
 
-                               if(BPy_StructRNA_Check(list_item)) {
+                               if (BPy_StructRNA_Check(list_item)) {
                                        /*
                                        CollectionPointerLink *link= MEM_callocN(sizeof(CollectionPointerLink), "bpy_context_get");
                                        link->ptr= ((BPy_StructRNA *)item)->ptr;
@@ -645,12 +673,12 @@ int BPY_context_member_get(bContext *C, const char *member, bContextDataResult *
                }
        }
 
-       if(done==0) {
+       if (done==0) {
                if (item)       printf("PyContext '%s' not a valid type\n", member);
                else            printf("PyContext '%s' not found\n", member);
        }
        else {
-               if(G.f & G_DEBUG) {
+               if (G.f & G_DEBUG) {
                        printf("PyContext '%s' found\n", member);
                }
        }
@@ -660,10 +688,12 @@ int BPY_context_member_get(bContext *C, const char *member, bContextDataResult *
 
 
 #ifdef WITH_PYTHON_MODULE
-#include "BLI_storage.h"
+#include "BLI_fileops.h"
 /* TODO, reloading the module isnt functional at the moment. */
 
-extern int main_python(int argc, const char **argv);
+static void bpy_module_free(void *mod);
+extern int main_python_enter(int argc, const char **argv);
+extern void main_python_exit(void);
 static struct PyModuleDef bpy_proxy_def= {
        PyModuleDef_HEAD_INIT,
        "bpy",  /* m_name */
@@ -673,8 +703,8 @@ static struct PyModuleDef bpy_proxy_def= {
        NULL,  /* m_reload */
        NULL,  /* m_traverse */
        NULL,  /* m_clear */
-       NULL,  /* m_free */
-};     
+       bpy_module_free,  /* m_free */
+};
 
 typedef struct {
        PyObject_HEAD
@@ -699,7 +729,7 @@ void bpy_module_delay_init(PyObject *bpy_proxy)
        
        // printf("module found %s\n", argv[0]);
 
-       main_python(argc, argv);
+       main_python_enter(argc, argv);
 
        /* initialized in BPy_init_modules() */
        PyDict_Update(PyModule_GetDict(bpy_proxy), PyModule_GetDict(bpy_package_py));
@@ -746,7 +776,7 @@ PyInit_bpy(void)
        dealloc_obj_Type.tp_dealloc= dealloc_obj_dealloc;
        dealloc_obj_Type.tp_flags= Py_TPFLAGS_DEFAULT;
        
-       if(PyType_Ready(&dealloc_obj_Type) < 0)
+       if (PyType_Ready(&dealloc_obj_Type) < 0)
                return NULL;
 
        dob= (dealloc_obj *) dealloc_obj_Type.tp_alloc(&dealloc_obj_Type, 0);
@@ -756,4 +786,9 @@ PyInit_bpy(void)
        return bpy_proxy;
 }
 
+static void bpy_module_free(void *UNUSED(mod))
+{
+       main_python_exit();
+}
+
 #endif