diff options
Diffstat (limited to 'source/blender/python/generic/py_capi_utils.c')
-rw-r--r-- | source/blender/python/generic/py_capi_utils.c | 234 |
1 files changed, 164 insertions, 70 deletions
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c index 37ed96bcaa0..caae5c4e122 100644 --- a/source/blender/python/generic/py_capi_utils.c +++ b/source/blender/python/generic/py_capi_utils.c @@ -51,6 +51,10 @@ # include "BLI_math_base.h" /* isfinite() */ #endif +/* -------------------------------------------------------------------- */ +/** \name Fast Python to C Array Conversion for Primitive Types + * \{ */ + /* array utility function */ int PyC_AsArray_FAST(void *array, PyObject *value_fast, @@ -137,11 +141,12 @@ int PyC_AsArray(void *array, return ret; } +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Typed Tuple Packing * * \note See #PyC_Tuple_Pack_* macros that take multiple arguments. - * * \{ */ /* array utility function */ @@ -192,6 +197,10 @@ PyObject *PyC_Tuple_PackArray_Bool(const bool *array, uint len) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Tuple/List Filling + * \{ */ + /** * Caller needs to ensure tuple is uninitialized. * Handy for filling a tuple with None for eg. @@ -218,6 +227,12 @@ void PyC_List_Fill(PyObject *list, PyObject *value) } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Bool/Enum Argument Parsing + * \{ */ + /** * Use with PyArg_ParseTuple's "O&" formatting. * @@ -274,8 +289,16 @@ int PyC_CheckArgs_DeepCopy(PyObject *args) return PyArg_ParseTuple(args, "|O!:__deepcopy__", &PyDict_Type, &dummy_pydict) != 0; } +/** \} */ + #ifndef MATH_STANDALONE +/* -------------------------------------------------------------------- */ +/** \name Simple Printing (for debugging) + * + * These are useful to run directly from a debugger to be able to inspect the state. + * \{ */ + /* for debugging */ void PyC_ObSpit(const char *name, PyObject *var) { @@ -352,12 +375,11 @@ void PyC_StackSpit(void) fprintf(stderr, "python line lookup failed, interpreter inactive\n"); return; } - else { - /* lame but handy */ - PyGILState_STATE gilstate = PyGILState_Ensure(); - PyRun_SimpleString("__import__('traceback').print_stack()"); - PyGILState_Release(gilstate); - } + + /* lame but handy */ + PyGILState_STATE gilstate = PyGILState_Ensure(); + PyRun_SimpleString("__import__('traceback').print_stack()"); + PyGILState_Release(gilstate); } void PyC_StackPrint(/* FILE */ void *fp) @@ -374,6 +396,12 @@ void PyC_StackPrint(/* FILE */ void *fp) } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Access Current Frame File Name & Line Number + * \{ */ + void PyC_FileAndNum(const char **r_filename, int *r_lineno) { PyFrameObject *frame; @@ -433,6 +461,12 @@ void PyC_FileAndNum_Safe(const char **r_filename, int *r_lineno) PyC_FileAndNum(r_filename, r_lineno); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Object Access Utilities + * \{ */ + /* Would be nice if python had this built in */ PyObject *PyC_Object_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...) { @@ -461,6 +495,12 @@ PyObject *PyC_Object_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...) return item; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Frozen Set Creation + * \{ */ + PyObject *PyC_FrozenSetFromStrings(const char **strings) { const char **str; @@ -477,6 +517,12 @@ PyObject *PyC_FrozenSetFromStrings(const char **strings) return ret; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Exception Utilities + * \{ */ + /** * Similar to #PyErr_Format(), * @@ -542,6 +588,12 @@ void PyC_Err_PrintWithFunc(PyObject *py_func) _PyUnicode_AsString(((PyFunctionObject *)py_func)->func_name)); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Exception Buffer Access + * \{ */ + /* returns the exception string as a new PyUnicode object, depends on external traceback module */ # if 0 @@ -648,7 +700,7 @@ error_cleanup: PyObject *PyC_ExceptionBuffer_Simple(void) { - PyObject *string_io_buf; + PyObject *string_io_buf = NULL; PyObject *error_type, *error_value, *error_traceback; @@ -662,7 +714,19 @@ PyObject *PyC_ExceptionBuffer_Simple(void) return NULL; } - string_io_buf = PyObject_Str(error_value); + if (PyErr_GivenExceptionMatches(error_type, PyExc_SyntaxError)) { + /* Special exception for syntax errors, + * in these cases the full error is verbose and not very useful, + * just use the initial text so we know what the error is. */ + if (PyTuple_CheckExact(error_value) && PyTuple_GET_SIZE(error_value) >= 1) { + string_io_buf = PyObject_Str(PyTuple_GET_ITEM(error_value, 0)); + } + } + + if (string_io_buf == NULL) { + string_io_buf = PyObject_Str(error_value); + } + /* Python does this too */ if (UNLIKELY(string_io_buf == NULL)) { string_io_buf = PyUnicode_FromFormat("<unprintable %s object>", Py_TYPE(error_value)->tp_name); @@ -675,6 +739,14 @@ PyObject *PyC_ExceptionBuffer_Simple(void) return string_io_buf; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Unicode Conversion + * + * In some cases we need to coerce strings, avoid doing this inline. + * \{ */ + /* string conversion, escape non-unicode chars, coerce must be set to NULL */ const char *PyC_UnicodeAsByteAndSize(PyObject *py_str, Py_ssize_t *size, PyObject **coerce) { @@ -687,22 +759,20 @@ const char *PyC_UnicodeAsByteAndSize(PyObject *py_str, Py_ssize_t *size, PyObjec * chars since blender doesn't limit this */ return result; } - else { - PyErr_Clear(); - if (PyBytes_Check(py_str)) { - *size = PyBytes_GET_SIZE(py_str); - return PyBytes_AS_STRING(py_str); - } - else if ((*coerce = PyUnicode_EncodeFSDefault(py_str))) { - *size = PyBytes_GET_SIZE(*coerce); - return PyBytes_AS_STRING(*coerce); - } - else { - /* leave error raised from EncodeFS */ - return NULL; - } + PyErr_Clear(); + + if (PyBytes_Check(py_str)) { + *size = PyBytes_GET_SIZE(py_str); + return PyBytes_AS_STRING(py_str); } + if ((*coerce = PyUnicode_EncodeFSDefault(py_str))) { + *size = PyBytes_GET_SIZE(*coerce); + return PyBytes_AS_STRING(*coerce); + } + + /* leave error raised from EncodeFS */ + return NULL; } const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce) @@ -716,20 +786,18 @@ const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce) * chars since blender doesn't limit this. */ return result; } - else { - PyErr_Clear(); - if (PyBytes_Check(py_str)) { - return PyBytes_AS_STRING(py_str); - } - else if ((*coerce = PyUnicode_EncodeFSDefault(py_str))) { - return PyBytes_AS_STRING(*coerce); - } - else { - /* leave error raised from EncodeFS */ - return NULL; - } + PyErr_Clear(); + + if (PyBytes_Check(py_str)) { + return PyBytes_AS_STRING(py_str); } + if ((*coerce = PyUnicode_EncodeFSDefault(py_str))) { + return PyBytes_AS_STRING(*coerce); + } + + /* leave error raised from EncodeFS */ + return NULL; } PyObject *PyC_UnicodeFromByteAndSize(const char *str, Py_ssize_t size) @@ -740,12 +808,11 @@ PyObject *PyC_UnicodeFromByteAndSize(const char *str, Py_ssize_t size) * chars since blender doesn't limit this */ return result; } - else { - PyErr_Clear(); - /* this means paths will always be accessible once converted, on all OS's */ - result = PyUnicode_DecodeFSDefaultAndSize(str, size); - return result; - } + + PyErr_Clear(); + /* this means paths will always be accessible once converted, on all OS's */ + result = PyUnicode_DecodeFSDefaultAndSize(str, size); + return result; } PyObject *PyC_UnicodeFromByte(const char *str) @@ -753,6 +820,12 @@ PyObject *PyC_UnicodeFromByte(const char *str) return PyC_UnicodeFromByteAndSize(str, strlen(str)); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Name Space Creation/Manipulation + * \{ */ + /***************************************************************************** * Description: This function creates a new Python dictionary object. * note: dict is owned by sys.modules["__main__"] module, reference is borrowed @@ -818,8 +891,18 @@ void PyC_MainModule_Restore(PyObject *main_mod) Py_XDECREF(main_mod); } -/* Must be called before Py_Initialize, - * expects output of BKE_appdir_folder_id(BLENDER_PYTHON, NULL). */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #Py_SetPythonHome Wrapper + * \{ */ + +/** + * - Must be called before #Py_Initialize. + * - Expects output of `BKE_appdir_folder_id(BLENDER_PYTHON, NULL)`. + * - Note that the `PYTHONPATH` environment variable isn't reliable, see T31506. + Use #Py_SetPythonHome instead. + */ void PyC_SetHomePath(const char *py_path_bundle) { if (py_path_bundle == NULL) { @@ -838,24 +921,14 @@ void PyC_SetHomePath(const char *py_path_bundle) /* 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 - -# if 0 /* disable for now [#31506] - campbell */ -# ifdef _WIN32 - /* cmake/MSVC debug build crashes without this, why only - * in this case is unknown.. */ - { - /*BLI_setenv("PYTHONPATH", py_path_bundle)*/; + fprintf(stderr, + "Warning! Blender application is located in a path containing ':' or '/' chars\n" + "This may make python import function fail\n"); } -# endif # endif { - static wchar_t py_path_bundle_wchar[1024]; + wchar_t py_path_bundle_wchar[1024]; /* Can't use this, on linux gives bug: #23018, * TODO: try LANG="en_US.UTF-8" /usr/bin/blender, suggested 2008 */ @@ -875,6 +948,12 @@ bool PyC_IsInterpreterActive(void) return (PyThreadState_GetDict() != NULL); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #Py_SetPythonHome Wrapper + * \{ */ + /* Would be nice if python had this built in * See: https://wiki.blender.org/wiki/Tools/Debugging/PyFromC */ @@ -1051,15 +1130,22 @@ void *PyC_RNA_AsPointer(PyObject *value, const char *type_name) return result; } - else { - PyErr_Format(PyExc_TypeError, - "expected '%.200s' type found '%.200s' instead", - type_name, - Py_TYPE(value)->tp_name); - return NULL; - } + + PyErr_Format(PyExc_TypeError, + "expected '%.200s' type found '%.200s' instead", + type_name, + Py_TYPE(value)->tp_name); + return NULL; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Flag Set Utilities (#PyC_FlagSet) + * + * Convert to/from Python set of strings to an int flag. + * \{ */ + PyObject *PyC_FlagSet_AsString(PyC_FlagSet *item) { PyObject *py_items = PyList_New(0); @@ -1160,6 +1246,12 @@ PyObject *PyC_FlagSet_FromBitfield(PyC_FlagSet *items, int flag) return ret; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Run String (Evaluate to Primitive Types) + * \{ */ + /** * \return success * @@ -1323,6 +1415,8 @@ bool PyC_RunString_AsString(const char *imports[], return PyC_RunString_AsStringAndSize(imports, expr, filename, r_value, &value_size); } +/** \} */ + #endif /* #ifndef MATH_STANDALONE */ /* -------------------------------------------------------------------- */ @@ -1410,6 +1504,12 @@ uint32_t PyC_Long_AsU32(PyObject *value) * PyC_Long_AsU64 */ +#ifdef __GNUC__ +# pragma warning(pop) +#endif + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Py_buffer Utils * @@ -1486,9 +1586,3 @@ bool PyC_StructFmt_type_is_bool(char format) } /** \} */ - -#ifdef __GNUC__ -# pragma warning(pop) -#endif - -/** \} */ |