123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- #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;
- }
|