diff options
author | Campbell Barton <ideasman42@gmail.com> | 2010-09-01 18:13:48 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2010-09-01 18:13:48 +0400 |
commit | 39cb1432d8ab7c2263b3e4c5eeada5e25928938d (patch) | |
tree | d733b5292fdb36c32f35c771a18f3788a3cdfddb /source/blender/python | |
parent | 81d9a3de4302e0d4722d75d727fbc9e9c626bd9e (diff) |
bugfix [#23285] Exporters not available whel using special characters in path name
- ID properties now suopport non utf-8 strings for their values but not their keys.
- moved utility functions into py_capi_utils.c from bpy_utils and bpy_rna.
- import/export paths have to be printed with repr() or %r, so non utf-8 chars are escaped.
Diffstat (limited to 'source/blender/python')
-rw-r--r-- | source/blender/python/generic/IDProp.c | 41 | ||||
-rw-r--r-- | source/blender/python/generic/py_capi_utils.c | 271 | ||||
-rw-r--r-- | source/blender/python/generic/py_capi_utils.h | 41 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_props.c | 10 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_rna.c | 79 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_util.c | 201 | ||||
-rw-r--r-- | source/blender/python/intern/bpy_util.h | 13 |
7 files changed, 375 insertions, 281 deletions
diff --git a/source/blender/python/generic/IDProp.c b/source/blender/python/generic/IDProp.c index ba563f9fcbf..2a07ab3bc90 100644 --- a/source/blender/python/generic/IDProp.c +++ b/source/blender/python/generic/IDProp.c @@ -27,6 +27,15 @@ #include "IDProp.h" #include "MEM_guardedalloc.h" +#define USE_STRING_COERCE + +#ifdef USE_STRING_COERCE +#include "py_capi_utils.h" +#endif + +PyObject * PyC_UnicodeFromByte(const char *str); +const char * PuC_UnicodeAsByte(PyObject *py_str, PyObject **coerce); /* coerce must be NULL */ + /*** Function to wrap ID properties ***/ PyObject *BPy_Wrap_IDProperty(ID *id, IDProperty *prop, IDProperty *parent); @@ -46,7 +55,11 @@ PyObject *BPy_IDGroup_WrapData( ID *id, IDProperty *prop ) { switch ( prop->type ) { case IDP_STRING: - return PyUnicode_FromString( prop->data.pointer ); +#ifdef USE_STRING_COERCE + return PyC_UnicodeFromByte(prop->data.pointer); +#else + return PyUnicode_FromString(prop->data.pointer); +#endif case IDP_INT: return PyLong_FromLong( (long)prop->data.val ); case IDP_FLOAT: @@ -105,10 +118,25 @@ int BPy_IDGroup_SetData(BPy_IDProperty *self, IDProperty *prop, PyObject *value) PyErr_SetString(PyExc_TypeError, "expected a string!"); return -1; } +#ifdef USE_STRING_COERCE + { + int alloc_len; + PyObject *value_coerce= NULL; + st= (char *)PuC_UnicodeAsByte(value, &value_coerce); + alloc_len= strlen(st) + 1; + + st = _PyUnicode_AsString(value); + IDP_ResizeArray(prop, alloc_len); + memcpy(prop->data.pointer, st, alloc_len); + Py_XDECREF(value_coerce); + } +#else st = _PyUnicode_AsString(value); IDP_ResizeArray(prop, strlen(st)+1); strcpy(prop->data.pointer, st); +#endif + return 0; } @@ -281,8 +309,15 @@ char *BPy_IDProperty_Map_ValidateAndCreate(char *name, IDProperty *group, PyObje val.i = (int) PyLong_AsSsize_t(ob); prop = IDP_New(IDP_INT, val, name); } else if (PyUnicode_Check(ob)) { +#ifdef USE_STRING_COERCE + PyObject *value_coerce= NULL; + val.str = (char *)PuC_UnicodeAsByte(ob, &value_coerce); + prop = IDP_New(IDP_STRING, val, name); + Py_XDECREF(value_coerce); +#else val.str = _PyUnicode_AsString(ob); prop = IDP_New(IDP_STRING, val, name); +#endif } else if (PySequence_Check(ob)) { PyObject *item; int i; @@ -432,7 +467,11 @@ static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop) { switch (prop->type) { case IDP_STRING: +#ifdef USE_STRING_COERCE + return PyC_UnicodeFromByte(prop->data.pointer); +#else return PyUnicode_FromString(prop->data.pointer); +#endif break; case IDP_FLOAT: return PyFloat_FromDouble(*((float*)&prop->data.val)); diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c new file mode 100644 index 00000000000..8f4f68bce19 --- /dev/null +++ b/source/blender/python/generic/py_capi_utils.c @@ -0,0 +1,271 @@ +/* + * $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 ***** +*/ + +#include <Python.h> +#include "py_capi_utils.h" + +/* for debugging */ +void PyC_ObSpit(char *name, PyObject *var) { + fprintf(stderr, "<%s> : ", name); + if (var==NULL) { + fprintf(stderr, "<NIL>"); + } + 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, "<NIL>"); + } + fprintf(stderr, "\n"); +} + +void PyC_LineSpit(void) { + const char *filename; + int lineno; + + PyErr_Clear(); + PyC_FileAndNum(&filename, &lineno); + + fprintf(stderr, "%s:%d\n", filename, lineno); +} + +void PyC_FileAndNum(const char **filename, int *lineno) +{ + PyObject *getframe, *frame; + PyObject *f_lineno= NULL, *co_filename= NULL; + + if (filename) *filename= NULL; + if (lineno) *lineno = -1; + + getframe = PySys_GetObject("_getframe"); // borrowed + if (getframe==NULL) { + PyErr_Clear(); + return; + } + + frame = PyObject_CallObject(getframe, NULL); + if (frame==NULL) { + PyErr_Clear(); + return; + } + + /* when executing a script */ + if (filename) { + co_filename= PyC_Object_GetAttrStringArgs(frame, 1, "f_code", "co_filename"); + if (co_filename==NULL) { + PyErr_SetString(PyExc_SystemError, "Could not access sys._getframe().f_code.co_filename"); + Py_DECREF(frame); + return; + } + + *filename = _PyUnicode_AsString(co_filename); + Py_DECREF(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) { + f_lineno= PyObject_GetAttrString(frame, "f_lineno"); + if (f_lineno==NULL) { + PyErr_SetString(PyExc_SystemError, "Could not access sys._getframe().f_lineno"); + Py_DECREF(frame); + return; + } + + *lineno = (int)PyLong_AsSsize_t(f_lineno); + Py_DECREF(f_lineno); + } + + Py_DECREF(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<n; i++) { + attr = va_arg(vargs, char *); + item = PyObject_GetAttrString(item, attr); + + if (item) + Py_DECREF(item); + else /* python will set the error value here */ + break; + + } + va_end(vargs); + + Py_XINCREF(item); /* final value has is increfed, to match PyObject_GetAttrString */ + return item; +} + +/* returns the exception string as a new PyUnicode object, depends on external StringIO module */ +PyObject *PyC_ExceptionBuffer(void) +{ + PyObject *stdout_backup = PySys_GetObject("stdout"); /* borrowed */ + PyObject *stderr_backup = PySys_GetObject("stderr"); /* borrowed */ + PyObject *string_io = NULL; + PyObject *string_io_buf = NULL; + PyObject *string_io_mod= NULL; + PyObject *string_io_getvalue= NULL; + + PyObject *error_type, *error_value, *error_traceback; + + if (!PyErr_Occurred()) + return NULL; + + PyErr_Fetch(&error_type, &error_value, &error_traceback); + + PyErr_Clear(); + + /* import io + * string_io = io.StringIO() + */ + + if(! (string_io_mod= PyImport_ImportModule("io")) ) { + goto error_cleanup; + } else if (! (string_io = PyObject_CallMethod(string_io_mod, "StringIO", NULL))) { + goto error_cleanup; + } else if (! (string_io_getvalue= PyObject_GetAttrString(string_io, "getvalue"))) { + goto error_cleanup; + } + + Py_INCREF(stdout_backup); // since these were borrowed we dont want them freed when replaced. + Py_INCREF(stderr_backup); + + PySys_SetObject("stdout", string_io); // both of these are free'd when restoring + PySys_SetObject("stderr", string_io); + + PyErr_Restore(error_type, error_value, error_traceback); + PyErr_Print(); /* print the error */ + PyErr_Clear(); + + string_io_buf = PyObject_CallObject(string_io_getvalue, NULL); + + PySys_SetObject("stdout", stdout_backup); + PySys_SetObject("stderr", stderr_backup); + + Py_DECREF(stdout_backup); /* now sys owns the ref again */ + Py_DECREF(stderr_backup); + + Py_DECREF(string_io_mod); + Py_DECREF(string_io_getvalue); + Py_DECREF(string_io); /* free the original reference */ + + PyErr_Clear(); + return string_io_buf; + + +error_cleanup: + /* could not import the module so print the error and close */ + Py_XDECREF(string_io_mod); + Py_XDECREF(string_io); + + PyErr_Restore(error_type, error_value, error_traceback); + PyErr_Print(); /* print the error */ + PyErr_Clear(); + + return NULL; +} + + +/* string conversion, escape non-unicode chars, coerce must be set to NULL */ +const char *PuC_UnicodeAsByte(PyObject *py_str, PyObject **coerce) +{ + char *result; + + result= _PyUnicode_AsString(py_str); + + if(result) { + /* 99% of the time this is enough but we better support non unicode + * chars since blender doesnt limit this */ + return result; + } + else { + /* mostly copied from fileio.c's, fileio_init */ + PyObject *stringobj; + PyObject *u; + + PyErr_Clear(); + + u= PyUnicode_FromObject(py_str); /* coerce into unicode */ + + if (u == NULL) + return NULL; + + stringobj= PyUnicode_EncodeUTF8(PyUnicode_AS_UNICODE(u), PyUnicode_GET_SIZE(u), "surrogateescape"); + Py_DECREF(u); + if (stringobj == NULL) + return NULL; + if (!PyBytes_Check(stringobj)) { /* this seems wrong but it works fine */ + // printf("encoder failed to return bytes\n"); + Py_DECREF(stringobj); + return NULL; + } + *coerce= stringobj; + + return PyBytes_AS_STRING(stringobj); + } +} + +PyObject *PyC_UnicodeFromByte(const char *str) +{ + PyObject *result= PyUnicode_FromString(str); + if(result) { + /* 99% of the time this is enough but we better support non unicode + * chars since blender doesnt limit this */ + return result; + } + else { + PyErr_Clear(); + result= PyUnicode_DecodeUTF8(str, strlen(str), "surrogateescape"); + return result; + } +} diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h new file mode 100644 index 00000000000..bab89dbb01a --- /dev/null +++ b/source/blender/python/generic/py_capi_utils.h @@ -0,0 +1,41 @@ +/** + * $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. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef PY_CAPI_UTILS_H +#define PY_CAPI_UTILS_H + +struct PyObject; + +void PyC_ObSpit(char *name, PyObject *var); +void PyC_LineSpit(void); +PyObject * PyC_ExceptionBuffer(void); +PyObject * PyC_Object_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...); +void PyC_FileAndNum(const char **filename, int *lineno); +int PyC_AsArray(void *array, PyObject *value, int length, PyTypeObject *type, char *error_prefix); + +/* follow http://www.python.org/dev/peps/pep-0383/ */ +PyObject * PyC_UnicodeFromByte(const char *str); +const char * PuC_UnicodeAsByte(PyObject *py_str, PyObject **coerce); /* coerce must be NULL */ + +#endif // PY_CAPI_UTILS_H diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index 9afe638908c..9535741f2b5 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -31,6 +31,8 @@ #include "MEM_guardedalloc.h" +#include "../generic/py_capi_utils.h" + EnumPropertyItem property_flag_items[] = { {PROP_HIDDEN, "HIDDEN", 0, "Hidden", ""}, {PROP_ANIMATABLE, "ANIMATABLE", 0, "Animateable", ""}, @@ -219,7 +221,7 @@ PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject *kw) return NULL; } - if(pydef && BPyAsPrimitiveArray(def, pydef, size, &PyBool_Type, "BoolVectorProperty(default=sequence)") < 0) + if(pydef && PyC_AsArray(def, pydef, size, &PyBool_Type, "BoolVectorProperty(default=sequence)") < 0) return NULL; // prop= RNA_def_boolean_array(srna, id, size, pydef ? def:NULL, name, description); @@ -361,7 +363,7 @@ PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject *kw) return NULL; } - if(pydef && BPyAsPrimitiveArray(def, pydef, size, &PyLong_Type, "IntVectorProperty(default=sequence)") < 0) + if(pydef && PyC_AsArray(def, pydef, size, &PyLong_Type, "IntVectorProperty(default=sequence)") < 0) return NULL; prop= RNA_def_property(srna, id, PROP_INT, subtype); @@ -515,7 +517,7 @@ PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObject *kw) return NULL; } - if(pydef && BPyAsPrimitiveArray(def, pydef, size, &PyFloat_Type, "FloatVectorProperty(default=sequence)") < 0) + if(pydef && PyC_AsArray(def, pydef, size, &PyFloat_Type, "FloatVectorProperty(default=sequence)") < 0) return NULL; prop= RNA_def_property(srna, id, PROP_FLOAT, subtype); @@ -717,7 +719,7 @@ static StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix srna= srna_from_self(value, "BoolProperty(...):"); if(!srna) { - PyObject *msg= BPY_exception_buffer(); + PyObject *msg= PyC_ExceptionBuffer(); char *msg_char= _PyUnicode_AsString(msg); PyErr_Format(PyExc_TypeError, "%.200s expected an RNA type derived from IDPropertyGroup, failed with: %s", error_prefix, msg_char); Py_DECREF(msg); diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 6133a1da616..3a7ee4806e9 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -54,6 +54,7 @@ #ifdef USE_MATHUTILS #include "../generic/mathutils.h" /* so we can have mathutils callbacks */ #include "../generic/IDProp.h" /* for IDprop lookups */ +#include "../generic/py_capi_utils.h" static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, ParameterList *parms, void *data, PyObject *value, const char *error_prefix); static PyObject *pyrna_prop_array_subscript_slice(BPy_PropertyRNA *self, PointerRNA *ptr, PropertyRNA *prop, int start, int stop, int length); @@ -209,62 +210,6 @@ Mathutils_Callback mathutils_rna_matrix_cb = { NULL }; -#ifdef USE_STRING_COERCE -/* string conversion, escape non-unicode chars, coerce must be set to NULL */ -static const char *py_safe_unicode_to_byte(PyObject *py_str, PyObject **coerce) -{ - char *result; - - result= _PyUnicode_AsString(py_str); - - if(result) { - /* 99% of the time this is enough but we better support non unicode - * chars since blender doesnt limit this */ - return result; - } - else { - /* mostly copied from fileio.c's, fileio_init */ - PyObject *stringobj; - PyObject *u; - - PyErr_Clear(); - - u= PyUnicode_FromObject(py_str); /* coerce into unicode */ - - if (u == NULL) - return NULL; - - stringobj= PyUnicode_EncodeUTF8(PyUnicode_AS_UNICODE(u), PyUnicode_GET_SIZE(u), "surrogateescape"); - Py_DECREF(u); - if (stringobj == NULL) - return NULL; - if (!PyBytes_Check(stringobj)) { /* this seems wrong but it works fine */ - // printf("encoder failed to return bytes\n"); - Py_DECREF(stringobj); - return NULL; - } - *coerce= stringobj; - - return PyBytes_AS_STRING(stringobj); - } -} - -static PyObject *py_safe_byte_to_unicode(const char *str) -{ - PyObject *result= PyUnicode_FromString(str); - if(result) { - /* 99% of the time this is enough but we better support non unicode - * chars since blender doesnt limit this */ - return result; - } - else { - PyErr_Clear(); - result= PyUnicode_DecodeUTF8(str, strlen(str), "surrogateescape"); - return result; - } -} -#endif - /* same as RNA_enum_value_from_id but raises an exception */ int pyrna_enum_value_from_id(EnumPropertyItem *item, const char *identifier, int *value, const char *error_prefix) { @@ -847,7 +792,7 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop) #ifdef USE_STRING_COERCE /* only file paths get special treatment, they may contain non utf-8 chars */ if(ELEM3(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) { - ret= py_safe_byte_to_unicode(buf); + ret= PyC_UnicodeFromByte(buf); } else { ret= PyUnicode_FromString(buf); @@ -1060,7 +1005,7 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, ParameterList *p PyObject *value_coerce= NULL; int subtype= RNA_property_subtype(prop); if(ELEM3(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) { - param= py_safe_unicode_to_byte(value, &value_coerce); + param= PuC_UnicodeAsByte(value, &value_coerce); } else { param= _PyUnicode_AsString(value); @@ -1239,7 +1184,7 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, ParameterList *p RNA_property_collection_add(ptr, prop, &itemptr); if(pyrna_pydict_to_props(&itemptr, item, 1, "Converting a python list to an RNA collection")==-1) { - PyObject *msg= BPY_exception_buffer(); + PyObject *msg= PyC_ExceptionBuffer(); char *msg_char= _PyUnicode_AsString(msg); PyErr_Format(PyExc_TypeError, "%.200s %.200s.%.200s error converting a member of a collection from a dicts into an RNA collection, failed with: %s", error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), msg_char); @@ -3487,7 +3432,7 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, ParameterList *parms, PropertyRNA * #ifdef USE_STRING_COERCE if(ELEM3(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) { - ret= py_safe_byte_to_unicode(data_ch); + ret= PyC_UnicodeFromByte(data_ch); } else { ret= PyUnicode_FromString(data_ch); @@ -4127,7 +4072,7 @@ static void pyrna_subtype_set_rna(PyObject *newclass, StructRNA *srna) Py_INCREF(newclass); if (RNA_struct_py_type_get(srna)) - PyObSpit("RNA WAS SET - ", RNA_struct_py_type_get(srna)); + PyC_ObSpit("RNA WAS SET - ", RNA_struct_py_type_get(srna)); Py_XDECREF(((PyObject *)RNA_struct_py_type_get(srna))); @@ -4213,7 +4158,7 @@ static PyObject* pyrna_srna_ExternalType(StructRNA *srna) if(base_compare != base) { fprintf(stderr, "pyrna_srna_ExternalType: incorrect subclassing of SRNA '%s'\nSee bpy_types.py\n", idname); - PyObSpit("Expected! ", base_compare); + PyC_ObSpit("Expected! ", base_compare); newclass= NULL; } else { @@ -4263,7 +4208,7 @@ static PyObject* pyrna_srna_Subtype(StructRNA *srna) newclass = PyObject_CallFunction((PyObject*)&PyType_Type, "s(O){sss()}", idname, py_base, "__module__","bpy.types", "__slots__"); /* newclass will now have 2 ref's, ???, probably 1 is internal since decrefing here segfaults */ - /* PyObSpit("new class ref", newclass); */ + /* PyC_ObSpit("new class ref", newclass); */ if (newclass) { /* srna owns one, and the other is owned by the caller */ @@ -4329,7 +4274,7 @@ PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr ) pyrna->ptr= *ptr; pyrna->freeptr= FALSE; - // PyObSpit("NewStructRNA: ", (PyObject *)pyrna); + // PyC_ObSpit("NewStructRNA: ", (PyObject *)pyrna); return ( PyObject * ) pyrna; } @@ -4594,7 +4539,7 @@ static int deferred_register_prop(StructRNA *srna, PyObject *item, PyObject *key PyErr_Print(); PyErr_Clear(); - // PyLineSpit(); + // PyC_LineSpit(); PyErr_Format(PyExc_ValueError, "bpy_struct \"%.200s\" registration error: %.200s could not register\n", RNA_struct_identifier(srna), _PyUnicode_AsString(key)); return -1; } @@ -4603,7 +4548,7 @@ static int deferred_register_prop(StructRNA *srna, PyObject *item, PyObject *key /* Since this is a class dict, ignore args that can't be passed */ /* for testing only */ - /* PyObSpit("Why doesn't this work??", item); + /* PyC_ObSpit("Why doesn't this work??", item); PyErr_Print(); */ PyErr_Clear(); } @@ -5048,7 +4993,7 @@ static void bpy_class_free(void *pyob_ptr) if(G.f&G_DEBUG) { if(self->ob_refcnt > 1) { - PyObSpit("zombie class - ref should be 1", self); + PyC_ObSpit("zombie class - ref should be 1", self); } } diff --git a/source/blender/python/intern/bpy_util.c b/source/blender/python/intern/bpy_util.c index 1d14ab67510..1a2d7b297b6 100644 --- a/source/blender/python/intern/bpy_util.c +++ b/source/blender/python/intern/bpy_util.c @@ -26,136 +26,14 @@ #include "BLI_dynstr.h" #include "MEM_guardedalloc.h" #include "BKE_report.h" +#include "BKE_context.h" +#include "../generic/py_capi_utils.h" -#include "BKE_context.h" bContext* __py_context = NULL; bContext* BPy_GetContext(void) { return __py_context; }; void BPy_SetContext(bContext *C) { __py_context= C; }; -/* for debugging */ -void PyObSpit(char *name, PyObject *var) { - fprintf(stderr, "<%s> : ", name); - if (var==NULL) { - fprintf(stderr, "<NIL>"); - } - 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, "<NIL>"); - } - fprintf(stderr, "\n"); -} - -void PyLineSpit(void) { - const char *filename; - int lineno; - - PyErr_Clear(); - BPY_getFileAndNum(&filename, &lineno); - - fprintf(stderr, "%s:%d\n", filename, lineno); -} - -void BPY_getFileAndNum(const char **filename, int *lineno) -{ - PyObject *getframe, *frame; - PyObject *f_lineno= NULL, *co_filename= NULL; - - if (filename) *filename= NULL; - if (lineno) *lineno = -1; - - getframe = PySys_GetObject("_getframe"); // borrowed - if (getframe==NULL) { - PyErr_Clear(); - return; - } - - frame = PyObject_CallObject(getframe, NULL); - if (frame==NULL) { - PyErr_Clear(); - return; - } - - /* when executing a script */ - if (filename) { - co_filename= PyObject_GetAttrStringArgs(frame, 1, "f_code", "co_filename"); - if (co_filename==NULL) { - PyErr_SetString(PyExc_SystemError, "Could not access sys._getframe().f_code.co_filename"); - Py_DECREF(frame); - return; - } - - *filename = _PyUnicode_AsString(co_filename); - Py_DECREF(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) { - f_lineno= PyObject_GetAttrString(frame, "f_lineno"); - if (f_lineno==NULL) { - PyErr_SetString(PyExc_SystemError, "Could not access sys._getframe().f_lineno"); - Py_DECREF(frame); - return; - } - - *lineno = (int)PyLong_AsSsize_t(f_lineno); - Py_DECREF(f_lineno); - } - - Py_DECREF(frame); -} - -/* Would be nice if python had this built in */ -PyObject *PyObject_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<n; i++) { - attr = va_arg(vargs, char *); - item = PyObject_GetAttrString(item, attr); - - if (item) - Py_DECREF(item); - else /* python will set the error value here */ - break; - - } - va_end(vargs); - - Py_XINCREF(item); /* final value has is increfed, to match PyObject_GetAttrString */ - return item; -} - int BPY_class_validate(const char *class_type, PyObject *class, PyObject *base_class, BPY_class_attr_check* class_attrs, PyObject **py_class_attrs) { PyObject *item, *fitem; @@ -244,75 +122,6 @@ int BPY_class_validate(const char *class_type, PyObject *class, PyObject *base_c -/* returns the exception string as a new PyUnicode object, depends on external StringIO module */ -PyObject *BPY_exception_buffer(void) -{ - PyObject *stdout_backup = PySys_GetObject("stdout"); /* borrowed */ - PyObject *stderr_backup = PySys_GetObject("stderr"); /* borrowed */ - PyObject *string_io = NULL; - PyObject *string_io_buf = NULL; - PyObject *string_io_mod= NULL; - PyObject *string_io_getvalue= NULL; - - PyObject *error_type, *error_value, *error_traceback; - - if (!PyErr_Occurred()) - return NULL; - - PyErr_Fetch(&error_type, &error_value, &error_traceback); - - PyErr_Clear(); - - /* import io - * string_io = io.StringIO() - */ - - if(! (string_io_mod= PyImport_ImportModule("io")) ) { - goto error_cleanup; - } else if (! (string_io = PyObject_CallMethod(string_io_mod, "StringIO", NULL))) { - goto error_cleanup; - } else if (! (string_io_getvalue= PyObject_GetAttrString(string_io, "getvalue"))) { - goto error_cleanup; - } - - Py_INCREF(stdout_backup); // since these were borrowed we dont want them freed when replaced. - Py_INCREF(stderr_backup); - - PySys_SetObject("stdout", string_io); // both of these are free'd when restoring - PySys_SetObject("stderr", string_io); - - PyErr_Restore(error_type, error_value, error_traceback); - PyErr_Print(); /* print the error */ - PyErr_Clear(); - - string_io_buf = PyObject_CallObject(string_io_getvalue, NULL); - - PySys_SetObject("stdout", stdout_backup); - PySys_SetObject("stderr", stderr_backup); - - Py_DECREF(stdout_backup); /* now sys owns the ref again */ - Py_DECREF(stderr_backup); - - Py_DECREF(string_io_mod); - Py_DECREF(string_io_getvalue); - Py_DECREF(string_io); /* free the original reference */ - - PyErr_Clear(); - return string_io_buf; - - -error_cleanup: - /* could not import the module so print the error and close */ - Py_XDECREF(string_io_mod); - Py_XDECREF(string_io); - - PyErr_Restore(error_type, error_value, error_traceback); - PyErr_Print(); /* print the error */ - PyErr_Clear(); - - return NULL; -} - char *BPy_enum_as_string(EnumPropertyItem *item) { DynStr *dynstr= BLI_dynstr_new(); @@ -363,14 +172,14 @@ int BPy_errors_to_report(ReportList *reports) return 1; } - pystring= BPY_exception_buffer(); + pystring= PyC_ExceptionBuffer(); if(pystring==NULL) { BKE_report(reports, RPT_ERROR, "unknown py-exception, could not convert"); return 0; } - BPY_getFileAndNum(&filename, &lineno); + PyC_FileAndNum(&filename, &lineno); if(filename==NULL) filename= "<unknown location>"; @@ -392,7 +201,7 @@ int BPy_errors_to_report(ReportList *reports) } /* array utility function */ -int BPyAsPrimitiveArray(void *array, PyObject *value, int length, PyTypeObject *type, char *error_prefix) +int PyC_AsArray(void *array, PyObject *value, int length, PyTypeObject *type, char *error_prefix) { PyObject *value_fast; int value_len; diff --git a/source/blender/python/intern/bpy_util.h b/source/blender/python/intern/bpy_util.h index cfe820b53b0..ae215725087 100644 --- a/source/blender/python/intern/bpy_util.h +++ b/source/blender/python/intern/bpy_util.h @@ -36,17 +36,6 @@ struct EnumPropertyItem; struct ReportList; -void PyObSpit(char *name, PyObject *var); -void PyLineSpit(void); -void BPY_getFileAndNum(const char **filename, int *lineno); - -PyObject *BPY_exception_buffer(void); - -/* own python like utility function */ -PyObject *PyObject_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...); - - - /* Class type checking, use for checking classes can be added as operators, panels etc */ typedef struct BPY_class_attr_check { const char *name; /* name of the class attribute */ @@ -77,6 +66,4 @@ void BPy_SetContext(struct bContext *C); extern void bpy_context_set(struct bContext *C, PyGILState_STATE *gilstate); extern void bpy_context_clear(struct bContext *C, PyGILState_STATE *gilstate); - -int BPyAsPrimitiveArray(void *array, PyObject *value, int length, PyTypeObject *type, char *error_prefix); #endif |