/* * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * ***** END GPL LICENSE BLOCK ***** */ /** \file blender/python/generic/py_capi_utils.c * \ingroup pygen */ #include #include #include "py_capi_utils.h" #include "BKE_font.h" /* only for utf8towchar, should replace with py funcs but too late in release now */ #ifdef _WIN32 /* BLI_setenv */ #include "BLI_path_util.h" #endif #define PYC_INTERPRETER_ACTIVE (((PyThreadState*)_Py_atomic_load_relaxed(&_PyThreadState_Current)) != NULL) /* for debugging */ void PyC_ObSpit(const char *name, PyObject *var) { fprintf(stderr, "<%s> : ", name); if (var==NULL) { fprintf(stderr, ""); } else { PyObject_Print(var, stderr, 0); fprintf(stderr, " ref:%d ", (int)var->ob_refcnt); fprintf(stderr, " ptr:%p", (void *)var); fprintf(stderr, " type:"); if(Py_TYPE(var)) fprintf(stderr, "%s", Py_TYPE(var)->tp_name); else fprintf(stderr, ""); } fprintf(stderr, "\n"); } void PyC_LineSpit(void) { const char *filename; int lineno; /* Note, allow calling from outside python (RNA) */ if(!PYC_INTERPRETER_ACTIVE) { fprintf(stderr, "python line lookup failed, interpreter inactive\n"); return; } PyErr_Clear(); PyC_FileAndNum(&filename, &lineno); fprintf(stderr, "%s:%d\n", filename, lineno); } void PyC_FileAndNum(const char **filename, int *lineno) { PyFrameObject *frame; if (filename) *filename= NULL; if (lineno) *lineno = -1; if (!(frame= PyThreadState_GET()->frame)) { return; } /* when executing a script */ if (filename) { *filename = _PyUnicode_AsString(frame->f_code->co_filename); } /* when executing a module */ if(filename && *filename == NULL) { /* try an alternative method to get the filename - module based * references below are all borrowed (double checked) */ PyObject *mod_name= PyDict_GetItemString(PyEval_GetGlobals(), "__name__"); if(mod_name) { PyObject *mod= PyDict_GetItem(PyImport_GetModuleDict(), mod_name); if(mod) { *filename= PyModule_GetFilename(mod); } /* unlikely, fallback */ if(*filename == NULL) { *filename= _PyUnicode_AsString(mod_name); } } } if (lineno) { *lineno = PyFrame_GetLineNumber(frame); } } /* Would be nice if python had this built in */ PyObject *PyC_Object_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...) { Py_ssize_t i; PyObject *item= o; char *attr; va_list vargs; va_start(vargs, n); for (i=0; i> foo = 10 >> print(__import__("__main__").foo) * * note: this overwrites __main__ which gives problems with nested calles. * be sure to run PyC_MainModule_Backup & PyC_MainModule_Restore if there is * any chance that python is in the call stack. *****************************************************************************/ PyObject *PyC_DefaultNameSpace(const char *filename) { PyInterpreterState *interp= PyThreadState_GET()->interp; PyObject *mod_main= PyModule_New("__main__"); PyDict_SetItemString(interp->modules, "__main__", mod_main); Py_DECREF(mod_main); /* sys.modules owns now */ PyModule_AddStringConstant(mod_main, "__name__", "__main__"); if(filename) PyModule_AddStringConstant(mod_main, "__file__", filename); /* __file__ only for nice UI'ness */ PyModule_AddObject(mod_main, "__builtins__", interp->builtins); Py_INCREF(interp->builtins); /* AddObject steals a reference */ return PyModule_GetDict(mod_main); } /* restore MUST be called after this */ void PyC_MainModule_Backup(PyObject **main_mod) { PyInterpreterState *interp= PyThreadState_GET()->interp; *main_mod= PyDict_GetItemString(interp->modules, "__main__"); Py_XINCREF(*main_mod); /* dont free */ } void PyC_MainModule_Restore(PyObject *main_mod) { PyInterpreterState *interp= PyThreadState_GET()->interp; PyDict_SetItemString(interp->modules, "__main__", main_mod); Py_XDECREF(main_mod); } /* must be called before Py_Initialize, expects output of BLI_get_folder(BLENDER_PYTHON, NULL) */ void PyC_SetHomePath(const char *py_path_bundle) { if(py_path_bundle==NULL) { /* Common enough to have bundled *nix python but complain on OSX/Win */ #if defined(__APPLE__) || defined(_WIN32) fprintf(stderr, "Warning! bundled python not found and is expected on this platform. (if you built with CMake: 'install' target may have not been built)\n"); #endif return; } /* set the environment path */ printf("found bundled python: %s\n", 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.. */ { BLI_setenv("PYTHONPATH", py_path_bundle); } #endif { static wchar_t py_path_bundle_wchar[1024]; /* cant use this, on linux gives bug: #23018, TODO: try LANG="en_US.UTF-8" /usr/bin/blender, suggested 22008 */ /* mbstowcs(py_path_bundle_wchar, py_path_bundle, FILE_MAXDIR); */ utf8towchar(py_path_bundle_wchar, py_path_bundle); Py_SetPythonHome(py_path_bundle_wchar); // printf("found python (wchar_t) '%ls'\n", py_path_bundle_wchar); } } /* Would be nice if python had this built in */ void PyC_RunQuicky(const char *filepath, int n, ...) { FILE *fp= fopen(filepath, "r"); if(fp) { PyGILState_STATE gilstate= PyGILState_Ensure(); va_list vargs; int *sizes= PyMem_MALLOC(sizeof(int) * (n / 2)); int i; PyObject *py_dict = PyC_DefaultNameSpace(filepath); PyObject *values= PyList_New(n / 2); /* namespace owns this, dont free */ PyObject *py_result, *ret; PyObject *struct_mod= PyImport_ImportModule("struct"); PyObject *calcsize= PyObject_GetAttrString(struct_mod, "calcsize"); /* struct.calcsize */ PyObject *pack= PyObject_GetAttrString(struct_mod, "pack"); /* struct.pack */ PyObject *unpack= PyObject_GetAttrString(struct_mod, "unpack"); /* struct.unpack */ Py_DECREF(struct_mod); va_start(vargs, n); for (i=0; i * 2