From 7b0d7d0c9a1a17257ef55a5906e7bb8da51735d1 Mon Sep 17 00:00:00 2001 From: Vadim Levin Date: Wed, 16 Dec 2020 13:30:11 +0300 Subject: [PATCH] fix: conversion to string in python bindings If provided `PyObject` can't be converted to string `TypeError` is reported instead of `SytemError` without any message. --- .../include/opencv2/core/bindings_utils.hpp | 6 ++++++ modules/python/src2/cv2.cpp | 18 +++++++++++++++++- modules/python/test/test_misc.py | 16 +++++++++++++++- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/modules/core/include/opencv2/core/bindings_utils.hpp b/modules/core/include/opencv2/core/bindings_utils.hpp index f693dc8c65..92f27f0e87 100644 --- a/modules/core/include/opencv2/core/bindings_utils.hpp +++ b/modules/core/include/opencv2/core/bindings_utils.hpp @@ -58,6 +58,12 @@ String dumpCString(const char* argument) return cv::format("String: %s", argument); } +CV_WRAP static inline +String dumpString(const String& argument) +{ + return cv::format("String: %s", argument.c_str()); +} + CV_WRAP static inline AsyncArray testAsyncArray(InputArray argument) { diff --git a/modules/python/src2/cv2.cpp b/modules/python/src2/cv2.cpp index 39d7c55823..d5ecd0e20a 100644 --- a/modules/python/src2/cv2.cpp +++ b/modules/python/src2/cv2.cpp @@ -963,15 +963,31 @@ PyObject* pyopencv_from(const std::string& value) template<> bool pyopencv_to(PyObject* obj, String &value, const ArgInfo& info) { - CV_UNUSED(info); if(!obj || obj == Py_None) + { return true; + } std::string str; if (getUnicodeString(obj, str)) { value = str; return true; } + else + { + // If error hasn't been already set by Python conversion functions + if (!PyErr_Occurred()) + { + // Direct access to underlying slots of PyObjectType is not allowed + // when limited API is enabled +#ifdef Py_LIMITED_API + failmsg("Can't convert object to 'str' for '%s'", info.name); +#else + failmsg("Can't convert object of type '%s' to 'str' for '%s'", + obj->ob_type->tp_name, info.name); +#endif + } + } return false; } diff --git a/modules/python/test/test_misc.py b/modules/python/test/test_misc.py index f9a350d160..9ab85be46c 100644 --- a/modules/python/test/test_misc.py +++ b/modules/python/test/test_misc.py @@ -314,7 +314,7 @@ class Arguments(NewOpenCVTests): def test_parse_to_cstring_convertible(self): try_to_convert = partial(self._try_to_convert, cv.utils.dumpCString) - for convertible in ('s', 'str', str(123), ('char'), np.str('test1'), np.str_('test2')): + for convertible in ('', 's', 'str', str(123), ('char'), np.str('test1'), np.str_('test2')): expected = 'string: ' + convertible actual = try_to_convert(convertible) self.assertEqual(expected, actual, @@ -326,6 +326,20 @@ class Arguments(NewOpenCVTests): with self.assertRaises((TypeError), msg=get_no_exception_msg(not_convertible)): _ = cv.utils.dumpCString(not_convertible) + def test_parse_to_string_convertible(self): + try_to_convert = partial(self._try_to_convert, cv.utils.dumpString) + for convertible in (None, '', 's', 'str', str(123), np.str('test1'), np.str_('test2')): + expected = 'string: ' + (convertible if convertible else '') + actual = try_to_convert(convertible) + self.assertEqual(expected, actual, + msg=get_conversion_error_msg(convertible, expected, actual)) + + def test_parse_to_string_not_convertible(self): + for not_convertible in ((12,), ('t', 'e', 's', 't'), np.array(['123', ]), + np.array(['t', 'e', 's', 't']), 1, True, False): + with self.assertRaises((TypeError), msg=get_no_exception_msg(not_convertible)): + _ = cv.utils.dumpString(not_convertible) + class SamplesFindFile(NewOpenCVTests):