mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
178 lines
5.7 KiB
178 lines
5.7 KiB
#include "cv2_util.hpp" |
|
#include "opencv2/core.hpp" |
|
#include "opencv2/core/utils/configuration.private.hpp" |
|
#include "opencv2/core/utils/logger.hpp" |
|
|
|
PyObject* opencv_error = NULL; |
|
cv::TLSData<std::vector<std::string> > conversionErrorsTLS; |
|
|
|
using namespace cv; |
|
|
|
//====================================================================================================================== |
|
|
|
bool isPythonBindingsDebugEnabled() |
|
{ |
|
static bool param_debug = cv::utils::getConfigurationParameterBool("OPENCV_PYTHON_DEBUG", false); |
|
return param_debug; |
|
} |
|
|
|
void emit_failmsg(PyObject * exc, const char *msg) |
|
{ |
|
static bool param_debug = isPythonBindingsDebugEnabled(); |
|
if (param_debug) |
|
{ |
|
CV_LOG_WARNING(NULL, "Bindings conversion failed: " << msg); |
|
} |
|
PyErr_SetString(exc, msg); |
|
} |
|
|
|
int failmsg(const char *fmt, ...) |
|
{ |
|
char str[1000]; |
|
|
|
va_list ap; |
|
va_start(ap, fmt); |
|
vsnprintf(str, sizeof(str), fmt, ap); |
|
va_end(ap); |
|
|
|
emit_failmsg(PyExc_TypeError, str); |
|
return 0; |
|
} |
|
|
|
PyObject* failmsgp(const char *fmt, ...) |
|
{ |
|
char str[1000]; |
|
|
|
va_list ap; |
|
va_start(ap, fmt); |
|
vsnprintf(str, sizeof(str), fmt, ap); |
|
va_end(ap); |
|
|
|
emit_failmsg(PyExc_TypeError, str); |
|
return 0; |
|
} |
|
|
|
void pyRaiseCVException(const cv::Exception &e) |
|
{ |
|
PyObject_SetAttrString(opencv_error, "file", PyString_FromString(e.file.c_str())); |
|
PyObject_SetAttrString(opencv_error, "func", PyString_FromString(e.func.c_str())); |
|
PyObject_SetAttrString(opencv_error, "line", PyInt_FromLong(e.line)); |
|
PyObject_SetAttrString(opencv_error, "code", PyInt_FromLong(e.code)); |
|
PyObject_SetAttrString(opencv_error, "msg", PyString_FromString(e.msg.c_str())); |
|
PyObject_SetAttrString(opencv_error, "err", PyString_FromString(e.err.c_str())); |
|
PyErr_SetString(opencv_error, e.what()); |
|
} |
|
|
|
//====================================================================================================================== |
|
|
|
void pyRaiseCVOverloadException(const std::string& functionName) |
|
{ |
|
const std::vector<std::string>& conversionErrors = conversionErrorsTLS.getRef(); |
|
const std::size_t conversionErrorsCount = conversionErrors.size(); |
|
if (conversionErrorsCount > 0) |
|
{ |
|
// In modern std libraries small string optimization is used = no dynamic memory allocations, |
|
// but it can be applied only for string with length < 18 symbols (in GCC) |
|
const std::string bullet = "\n - "; |
|
|
|
// Estimate required buffer size - save dynamic memory allocations = faster |
|
std::size_t requiredBufferSize = bullet.size() * conversionErrorsCount; |
|
for (std::size_t i = 0; i < conversionErrorsCount; ++i) |
|
{ |
|
requiredBufferSize += conversionErrors[i].size(); |
|
} |
|
|
|
// Only string concatenation is required so std::string is way faster than |
|
// std::ostringstream |
|
std::string errorMessage("Overload resolution failed:"); |
|
errorMessage.reserve(errorMessage.size() + requiredBufferSize); |
|
for (std::size_t i = 0; i < conversionErrorsCount; ++i) |
|
{ |
|
errorMessage += bullet; |
|
errorMessage += conversionErrors[i]; |
|
} |
|
cv::Exception exception(Error::StsBadArg, errorMessage, functionName, "", -1); |
|
pyRaiseCVException(exception); |
|
} |
|
else |
|
{ |
|
cv::Exception exception(Error::StsInternal, "Overload resolution failed, but no errors reported", |
|
functionName, "", -1); |
|
pyRaiseCVException(exception); |
|
} |
|
} |
|
|
|
void pyPopulateArgumentConversionErrors() |
|
{ |
|
if (PyErr_Occurred()) |
|
{ |
|
PySafeObject exception_type; |
|
PySafeObject exception_value; |
|
PySafeObject exception_traceback; |
|
PyErr_Fetch(exception_type, exception_value, exception_traceback); |
|
PyErr_NormalizeException(exception_type, exception_value, |
|
exception_traceback); |
|
|
|
PySafeObject exception_message(PyObject_Str(exception_value)); |
|
std::string message; |
|
getUnicodeString(exception_message, message); |
|
#ifdef CV_CXX11 |
|
conversionErrorsTLS.getRef().push_back(std::move(message)); |
|
#else |
|
conversionErrorsTLS.getRef().push_back(message); |
|
#endif |
|
} |
|
} |
|
|
|
//====================================================================================================================== |
|
|
|
static int OnError(int status, const char *func_name, const char *err_msg, const char *file_name, int line, void *userdata) |
|
{ |
|
PyGILState_STATE gstate; |
|
gstate = PyGILState_Ensure(); |
|
|
|
PyObject *on_error = (PyObject*)userdata; |
|
PyObject *args = Py_BuildValue("isssi", status, func_name, err_msg, file_name, line); |
|
|
|
PyObject *r = PyObject_Call(on_error, args, NULL); |
|
if (r == NULL) { |
|
PyErr_Print(); |
|
} else { |
|
Py_DECREF(r); |
|
} |
|
|
|
Py_DECREF(args); |
|
PyGILState_Release(gstate); |
|
|
|
return 0; // The return value isn't used |
|
} |
|
|
|
PyObject *pycvRedirectError(PyObject*, PyObject *args, PyObject *kw) |
|
{ |
|
const char *keywords[] = { "on_error", NULL }; |
|
PyObject *on_error; |
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kw, "O", (char**)keywords, &on_error)) |
|
return NULL; |
|
|
|
if ((on_error != Py_None) && !PyCallable_Check(on_error)) { |
|
PyErr_SetString(PyExc_TypeError, "on_error must be callable"); |
|
return NULL; |
|
} |
|
|
|
// Keep track of the previous handler parameter, so we can decref it when no longer used |
|
static PyObject* last_on_error = NULL; |
|
if (last_on_error) { |
|
Py_DECREF(last_on_error); |
|
last_on_error = NULL; |
|
} |
|
|
|
if (on_error == Py_None) { |
|
ERRWRAP2(redirectError(NULL)); |
|
} else { |
|
last_on_error = on_error; |
|
Py_INCREF(last_on_error); |
|
ERRWRAP2(redirectError(OnError, last_on_error)); |
|
} |
|
Py_RETURN_NONE; |
|
}
|
|
|