From d651ff8d6b9669b8214876568694c1dca7c2ef8a Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 31 Mar 2021 14:17:45 +0000 Subject: [PATCH] python: exception-free pyopencv_to() wrapper --- modules/python/src2/cv2.cpp | 28 ++++++++++++++++++++++++++-- modules/python/src2/gen2.py | 12 ++++++------ 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/modules/python/src2/cv2.cpp b/modules/python/src2/cv2.cpp index 8bb15cd43f..0806e03552 100644 --- a/modules/python/src2/cv2.cpp +++ b/modules/python/src2/cv2.cpp @@ -44,6 +44,7 @@ #define CV_HAS_CONVERSION_ERROR(x) (((x) == -1) && PyErr_Occurred()) +static PyObject* opencv_error = NULL; class ArgInfo { @@ -66,14 +67,32 @@ struct PyOpenCV_Converter //static inline PyObject* from(const T& src); }; +// exception-safe pyopencv_to +template static +bool pyopencv_to_safe(PyObject* obj, _Tp& value, const ArgInfo& info) +{ + try + { + return pyopencv_to(obj, value, info); + } + catch (const std::exception &e) + { + PyErr_SetString(opencv_error, cv::format("Conversion error: %s, what: %s", info.name, e.what()).c_str()); + return false; + } + catch (...) + { + PyErr_SetString(opencv_error, cv::format("Conversion error: %s", info.name).c_str()); + return false; + } +} + template static bool pyopencv_to(PyObject* obj, T& p, const ArgInfo& info) { return PyOpenCV_Converter::to(obj, p, info); } template static PyObject* pyopencv_from(const T& src) { return PyOpenCV_Converter::from(src); } -static PyObject* opencv_error = NULL; - static bool isPythonBindingsDebugEnabled() { static bool param_debug = cv::utils::getConfigurationParameterBool("OPENCV_PYTHON_DEBUG", false); @@ -211,6 +230,11 @@ catch (const std::exception &e) \ { \ PyErr_SetString(opencv_error, e.what()); \ return 0; \ +} \ +catch (...) \ +{ \ + PyErr_SetString(opencv_error, "Unknown C++ exception from OpenCV code"); \ + return 0; \ } using namespace cv; diff --git a/modules/python/src2/gen2.py b/modules/python/src2/gen2.py index 4acca07ada..b25647c4b3 100755 --- a/modules/python/src2/gen2.py +++ b/modules/python/src2/gen2.py @@ -47,7 +47,7 @@ gen_template_func_body = Template("""$code_decl gen_template_mappable = Template(""" { ${mappable} _src; - if (pyopencv_to(src, _src, info)) + if (pyopencv_to_safe(src, _src, info)) { return cv_mappable_to(_src, dst); } @@ -91,7 +91,7 @@ gen_template_set_prop_from_map = Template(""" if( PyMapping_HasKeyString(src, (char*)"$propname") ) { tmp = PyMapping_GetItemString(src, (char*)"$propname"); - ok = tmp && pyopencv_to(tmp, dst.$propname, ArgInfo("$propname", false)); + ok = tmp && pyopencv_to_safe(tmp, dst.$propname, ArgInfo("$propname", false)); Py_DECREF(tmp); if(!ok) return false; }""") @@ -145,7 +145,7 @@ static int pyopencv_${name}_set_${member}(pyopencv_${name}_t* p, PyObject *value PyErr_SetString(PyExc_TypeError, "Cannot delete the ${member} attribute"); return -1; } - return pyopencv_to(value, p->v${access}${member}, ArgInfo("value", false)) ? 0 : -1; + return pyopencv_to_safe(value, p->v${access}${member}, ArgInfo("value", false)) ? 0 : -1; } """) @@ -163,7 +163,7 @@ static int pyopencv_${name}_set_${member}(pyopencv_${name}_t* p, PyObject *value failmsgp("Incorrect type of object (must be '${name}' or its derivative)"); return -1; } - return pyopencv_to(value, _self_${access}${member}, ArgInfo("value", false)) ? 0 : -1; + return pyopencv_to_safe(value, _self_${access}${member}, ArgInfo("value", false)) ? 0 : -1; } """) @@ -281,7 +281,7 @@ class ClassInfo(object): code = "static bool pyopencv_to(PyObject* src, %s& dst, const ArgInfo& info)\n{\n PyObject* tmp;\n bool ok;\n" % (self.cname) code += "".join([gen_template_set_prop_from_map.substitute(propname=p.name,proptype=p.tp) for p in self.props]) if self.base: - code += "\n return pyopencv_to(src, (%s&)dst, info);\n}\n" % all_classes[self.base].cname + code += "\n return pyopencv_to_safe(src, (%s&)dst, info);\n}\n" % all_classes[self.base].cname else: code += "\n return true;\n}\n" return code @@ -665,7 +665,7 @@ class FuncInfo(object): if a.tp == 'char': code_cvt_list.append("convert_to_char(pyobj_%s, &%s, %s)" % (a.name, a.name, a.crepr())) else: - code_cvt_list.append("pyopencv_to(pyobj_%s, %s, %s)" % (a.name, a.name, a.crepr())) + code_cvt_list.append("pyopencv_to_safe(pyobj_%s, %s, %s)" % (a.name, a.name, a.crepr())) all_cargs.append([arg_type_info, parse_name])