From 28b8e667a0c2ef77dd862bc40909d089a96d1324 Mon Sep 17 00:00:00 2001 From: Willian Padovani Germano Date: Fri, 4 Jul 2003 02:56:07 +0000 Subject: [PATCH] Exppython: - Fixed a problem with control of the global Python dictionary persistence: Blender.ReleaseGlobalDict(bool) should now work fine. - Trying to fix the sigsegv crashes on Windows: They happen when we try to "print" our objects, like Lamps or Cameras. Following advice from the Python Embedding doc, removed the tp_print method from Camera and also improved its tp_repr one, that will be used as print, repr() and str() for Cameras. If this test works all other objs will be updated accordingly. --- source/blender/python/BPY_interface.c | 241 ++++++++++--------- source/blender/python/api2_2x/Camera.c | 11 +- source/blender/python/api2_2x/Camera.h | 2 +- source/blender/python/api2_2x/Material.c | 2 + source/blender/python/api2_2x/doc/Blender.py | 1 + 5 files changed, 135 insertions(+), 122 deletions(-) diff --git a/source/blender/python/BPY_interface.c b/source/blender/python/BPY_interface.c index ec03f90487f..510dc52085e 100644 --- a/source/blender/python/BPY_interface.c +++ b/source/blender/python/BPY_interface.c @@ -102,13 +102,13 @@ void BPY_start_python(void) Py_Initialize (); - init_ourImport (); + init_ourImport (); initBlenderApi2_2x (); - init_syspath(); + init_syspath(); - return; /* We could take away all these return; ... */ + return; } /*****************************************************************************/ @@ -142,62 +142,58 @@ void syspath_append(PyObject *dir) void init_syspath(void) { - PyObject *path; - PyObject *mod, *d; - PyObject *p; - char *c, *progname; - char execdir[FILE_MAXDIR + FILE_MAXFILE];/*defines from DNA_space_types.h*/ + PyObject *path; + PyObject *mod, *d; + PyObject *p; + char *c, *progname; + char execdir[FILE_MAXDIR + FILE_MAXFILE];/*defines from DNA_space_types.h*/ - int n; + int n; - path = Py_BuildValue("s", bprogname); + path = Py_BuildValue("s", bprogname); - mod = PyImport_ImportModule("Blender.sys"); + mod = PyImport_ImportModule("Blender.sys"); if (mod) { - d = PyModule_GetDict(mod); - PyDict_SetItemString(d, "progname", path); - Py_DECREF(mod); - } + d = PyModule_GetDict(mod); + PyDict_SetItemString(d, "progname", path); + Py_DECREF(mod); + } else printf("Warning: could not set Blender.sys.progname\n"); - progname = BLI_last_slash(bprogname); /* looks for the last dir separator */ + progname = BLI_last_slash(bprogname); /* looks for the last dir separator */ - c = Py_GetPath(); /* get python system path */ - PySys_SetPath(c); /* initialize */ + c = Py_GetPath(); /* get python system path */ + PySys_SetPath(c); /* initialize */ - n = progname - bprogname; - if (n > 0) { - strncpy(execdir, bprogname, n); - if (execdir[n-1] == '.') n--; /*fix for when run as ./blender */ - execdir[n] = '\0'; + n = progname - bprogname; + if (n > 0) { + strncpy(execdir, bprogname, n); + if (execdir[n-1] == '.') n--; /*fix for when run as ./blender */ + execdir[n] = '\0'; - p = Py_BuildValue("s", execdir); - syspath_append(p); /* append to module search path */ + p = Py_BuildValue("s", execdir); + syspath_append(p); /* append to module search path */ - /* set Blender.sys.progname */ - } + /* set Blender.sys.progname */ + } else printf ("Warning: could not determine argv[0] path\n"); - if (U.pythondir) { /* XXX not working, U.pythondir is NULL here ?!?*/ - /* maybe it wasn't defined yet at this point in start-up ...*/ - /* Update: definitely that is the reason. We need to start python - * after U.pythondir is defined (better after the other U.xxxx are - * too. */ - p = Py_BuildValue("s", U.pythondir); - syspath_append(p); /* append to module search path */ - } + if (U.pythondir) { + p = Py_BuildValue("s", U.pythondir); + syspath_append(p); /* append to module search path */ + } - /* set sys.executable to the Blender exe */ + /* set sys.executable to the Blender exe */ mod = PyImport_ImportModule("sys"); /* new ref */ - if (mod) { - d = PyModule_GetDict(mod); /* borrowed ref */ - PyDict_SetItemString(d, "executable", Py_BuildValue("s", bprogname)); - Py_DECREF(mod); - } + if (mod) { + d = PyModule_GetDict(mod); /* borrowed ref */ + PyDict_SetItemString(d, "executable", Py_BuildValue("s", bprogname)); + Py_DECREF(mod); + } } /*****************************************************************************/ @@ -209,7 +205,7 @@ void init_syspath(void) /*****************************************************************************/ void BPY_syspath_append_pythondir(void) { - syspath_append(Py_BuildValue("s", U.pythondir)); + syspath_append(Py_BuildValue("s", U.pythondir)); } /*****************************************************************************/ @@ -323,6 +319,7 @@ void BPY_Err_Handle(Text *text) struct _object *BPY_txt_do_python(struct SpaceText* st) { PyObject *dict, *ret; + PyObject *main_dict = PyModule_GetDict(PyImport_AddModule("__main__")); //printf ("\nIn BPY_txt_do_python\n"); @@ -332,7 +329,7 @@ struct _object *BPY_txt_do_python(struct SpaceText* st) * the script with a clean global dictionary or should keep the current one, * possibly already "polluted" by other calls to the Python Interpreter. * The default is to use a clean one. To change this the script writer must - * call Blender.releaseGlobalDict(bool), with bool == 0, in the script */ + * call Blender.ReleaseGlobalDict(bool), with bool == 0, in the script. */ if (EXPP_releaseGlobalDict) { printf("Using a clean Global Dictionary.\n"); @@ -340,7 +337,7 @@ struct _object *BPY_txt_do_python(struct SpaceText* st) dict = CreateGlobalDictionary(); } else - dict = PyModule_GetDict(PyImport_AddModule("__main__")); + dict = main_dict; /* must be careful not to free the main_dict */ clearScriptLinks (); @@ -348,7 +345,8 @@ struct _object *BPY_txt_do_python(struct SpaceText* st) if (!ret) { /* Failed execution of the script */ - if (EXPP_releaseGlobalDict) ReleaseGlobalDictionary(dict); + if (EXPP_releaseGlobalDict && (dict != main_dict)) + ReleaseGlobalDictionary(dict); BPY_Err_Handle(st->text); BPY_end_python(); @@ -359,22 +357,33 @@ struct _object *BPY_txt_do_python(struct SpaceText* st) else Py_DECREF (ret); -/* From the old BPY_main.c: - * 'The following lines clear the global name space of the python - * interpreter. This is desired to release objects after execution - * of a script (remember that each wrapper object increments the refcount - * of the Blender Object. - * Exception: scripts that use the GUI rely on the - * persistent global namespace, so they need a workaround: The namespace - * is released when the GUI is exit.' +/* Scripts that use the GUI rely on the persistent global namespace, so + * they need a workaround: The namespace is released when the GUI is exit.' * See api2_2x/Draw.c: Method_Register() */ - if (EXPP_releaseGlobalDict) { - if (st->flags & ST_CLEAR_NAMESPACE) { - ReleaseGlobalDictionary(dict); - /*garbage_collect(&G.main); Unfinished in the previous implementation */ +/* Block below: The global dict should only be released if: + * - a script didn't defined it to be persistent and + * - Draw.Register() is not in use (no GUI) and + * - it is not the real __main__ dict (if it is, restart to clean it) */ + + if (EXPP_releaseGlobalDict) { + if (st->flags & ST_CLEAR_NAMESPACE) { /* False if the GUI is in use */ + + if (dict != main_dict) ReleaseGlobalDictionary(dict); + + else { + BPY_end_python(); /* restart to get a fresh __main__ dict */ + BPY_start_python(); + } + } } + else if (dict != main_dict) PyDict_Update (main_dict, dict); + +/* Line above: if it should be kept and it's not already the __main__ dict, + * merge it into the __main__ one. This happens when to release is the + * current behavior and the script changes that with + * Blender.ReleaseGlobalDict(0). */ /* Edited from old BPY_main.c: * 'The return value is the global namespace dictionary of the script @@ -669,86 +678,86 @@ void DoAllScriptsFromList (ListBase *list, short event) PyObject *importText(char *name) { - Text *text; - char *txtname; - char *buf = NULL; - int namelen = strlen(name); + Text *text; + char *txtname; + char *buf = NULL; + int namelen = strlen(name); - txtname = malloc(namelen+3+1); - if (!txtname) return NULL; + txtname = malloc(namelen+3+1); + if (!txtname) return NULL; - memcpy(txtname, name, namelen); - memcpy(&txtname[namelen], ".py", 4); + memcpy(txtname, name, namelen); + memcpy(&txtname[namelen], ".py", 4); - text = (Text*) &(G.main->text.first); + text = (Text*) &(G.main->text.first); - while(text) { - if (!strcmp (txtname, GetName(text))) - break; - text = text->id.next; - } + while(text) { + if (!strcmp (txtname, GetName(text))) + break; + text = text->id.next; + } - if (!text) { - free(txtname); - return NULL; - } + if (!text) { + free(txtname); + return NULL; + } - if (!text->compiled) { - buf = txt_to_buf(text); - text->compiled = Py_CompileString(buf, GetName(text), Py_file_input); - MEM_freeN(buf); + if (!text->compiled) { + buf = txt_to_buf(text); + text->compiled = Py_CompileString(buf, GetName(text), Py_file_input); + MEM_freeN(buf); - if (PyErr_Occurred()) { - PyErr_Print(); - BPY_free_compiled_text(text); - free(txtname); - return NULL; - } - } + if (PyErr_Occurred()) { + PyErr_Print(); + BPY_free_compiled_text(text); + free(txtname); + return NULL; + } + } - free(txtname); - return PyImport_ExecCodeModule(name, text->compiled); + free(txtname); + return PyImport_ExecCodeModule(name, text->compiled); } static PyMethodDef bimport[] = { - { "blimport", blender_import, METH_VARARGS, "our own import"} + { "blimport", blender_import, METH_VARARGS, "our own import"} }; PyObject *blender_import(PyObject *self, PyObject *args) { - PyObject *exception, *err, *tb; - char *name; - PyObject *globals = NULL, *locals = NULL, *fromlist = NULL; - PyObject *m; + PyObject *exception, *err, *tb; + char *name; + PyObject *globals = NULL, *locals = NULL, *fromlist = NULL; + PyObject *m; - if (!PyArg_ParseTuple(args, "s|OOO:bimport", - &name, &globals, &locals, &fromlist)) - return NULL; + if (!PyArg_ParseTuple(args, "s|OOO:bimport", + &name, &globals, &locals, &fromlist)) + return NULL; - m = PyImport_ImportModuleEx(name, globals, locals, fromlist); + m = PyImport_ImportModuleEx(name, globals, locals, fromlist); - if (m) - return m; - else - PyErr_Fetch(&exception, &err, &tb); /*restore for probable later use*/ - - m = importText(name); - if (m) { /* found module, ignore above exception*/ - PyErr_Clear(); - Py_XDECREF(exception); Py_XDECREF(err); Py_XDECREF(tb); - printf("imported from text buffer...\n"); - } else { - PyErr_Restore(exception, err, tb); - } - return m; + if (m) + return m; + else + PyErr_Fetch(&exception, &err, &tb); /*restore for probable later use*/ + + m = importText(name); + if (m) { /* found module, ignore above exception*/ + PyErr_Clear(); + Py_XDECREF(exception); Py_XDECREF(err); Py_XDECREF(tb); + printf("imported from text buffer...\n"); + } else { + PyErr_Restore(exception, err, tb); + } + return m; } void init_ourImport(void) { - PyObject *m, *d; - PyObject *import = PyCFunction_New(bimport, NULL); + PyObject *m, *d; + PyObject *import = PyCFunction_New(bimport, NULL); - m = PyImport_AddModule("__builtin__"); - d = PyModule_GetDict(m); - PyDict_SetItemString(d, "__import__", import); + m = PyImport_AddModule("__builtin__"); + d = PyModule_GetDict(m); + PyDict_SetItemString(d, "__import__", import); } diff --git a/source/blender/python/api2_2x/Camera.c b/source/blender/python/api2_2x/Camera.c index 24dc7b5df42..913949789d4 100644 --- a/source/blender/python/api2_2x/Camera.c +++ b/source/blender/python/api2_2x/Camera.c @@ -50,8 +50,9 @@ PyTypeObject Camera_Type = 0, /* tp_itemsize */ /* methods */ (destructor)Camera_dealloc, /* tp_dealloc */ - (printfunc)Camera_print, /* tp_print */ - (getattrfunc)Camera_getAttr, /* tp_getattr */ +// (printfunc)Camera_print, /* tp_print */ + 0, /* tp_print */ + (getattrfunc)Camera_getAttr, /* tp_getattr */ (setattrfunc)Camera_setAttr, /* tp_setattr */ (cmpfunc)Camera_compare, /* tp_compare */ (reprfunc)Camera_repr, /* tp_repr */ @@ -582,14 +583,14 @@ static int Camera_compare (BPy_Camera *a, BPy_Camera *b) Camera *pa = a->camera, *pb = b->camera; return (pa == pb) ? 0:-1; } - +/* static int Camera_print(BPy_Camera *self, FILE *fp, int flags) { fprintf(fp, "[Camera \"%s\"]", self->camera->id.name+2); return 0; } - +*/ static PyObject *Camera_repr (BPy_Camera *self) { - return PyString_FromString(self->camera->id.name+2); + return PyString_FromFormat("[Camera \"%s\"]", self->camera->id.name+2); } diff --git a/source/blender/python/api2_2x/Camera.h b/source/blender/python/api2_2x/Camera.h index ead55e01277..b0a2a643c43 100644 --- a/source/blender/python/api2_2x/Camera.h +++ b/source/blender/python/api2_2x/Camera.h @@ -174,7 +174,7 @@ static PyMethodDef BPy_Camera_methods[] = { /* Python Camera_Type callback function prototypes: */ /*****************************************************************************/ static void Camera_dealloc (BPy_Camera *self); -static int Camera_print (BPy_Camera *self, FILE *fp, int flags); +//static int Camera_print (BPy_Camera *self, FILE *fp, int flags); static int Camera_setAttr (BPy_Camera *self, char *name, PyObject *v); static int Camera_compare (BPy_Camera *a, BPy_Camera *b); static PyObject *Camera_getAttr (BPy_Camera *self, char *name); diff --git a/source/blender/python/api2_2x/Material.c b/source/blender/python/api2_2x/Material.c index eb0bad312a2..c4cd3e19091 100644 --- a/source/blender/python/api2_2x/Material.c +++ b/source/blender/python/api2_2x/Material.c @@ -167,6 +167,8 @@ static PyObject *M_Material_New(PyObject *self, PyObject *args, return (EXPP_ReturnPyObjError (PyExc_RuntimeError, "couldn't create Material Data in Blender")); + blmat->id.us = 0; /* was incref'ed by add_material() above */ + if (pymat == NULL) return (EXPP_ReturnPyObjError (PyExc_MemoryError, "couldn't create Material Data object")); diff --git a/source/blender/python/api2_2x/doc/Blender.py b/source/blender/python/api2_2x/doc/Blender.py index 0ece60bdb50..6f701c2defb 100644 --- a/source/blender/python/api2_2x/doc/Blender.py +++ b/source/blender/python/api2_2x/doc/Blender.py @@ -15,6 +15,7 @@ Blender Python Submodules: ----------- + - L{Material} - L{Camera} - L{Lamp} - L{BGL}