Fix for the test interpreter_test.py with PY3

The test interpreter_test.py is failing when it is run using PY3.
There are several issues due to difference between PY2 and PY3:

The string in PY2 is stored as bytes by default, but as unicode in PY3 by default.
In PY3 if the string is in bytes, it has the prefix 'b'.
We convert all strings to be the same.

There is an exception chaining in PY3.
As result, the message thrown from the exception is different.

There is a segmentation fault on Python3, when all tests in
the file interpreter_test are run. The bug is that the global variable
stores the pointer to the function, which goes away from the scope.
This commit is contained in:
Anton Kachatkou 2019-08-22 15:55:12 +01:00
parent d5677beba5
commit 093e00fee1
3 changed files with 23 additions and 8 deletions

View File

@ -108,7 +108,11 @@ class Delegate(object):
self.message = ''
def report(self, x):
self.message += x
if (type(x) is not bytes):
self.message += x
else:
# To support both: PY2 and PY3, we don't use the function decode, but do this way
self.message.join(chr(l) for l in x)
capture = ErrorMessageCapture()
error_capturer_cb = ctypes.CFUNCTYPE(None, ctypes.c_char_p)(capture.report)
@ -119,7 +123,7 @@ class Delegate(object):
raise ValueError(capture.message)
def __del__(self):
# __del__ can be called multiple times, so if the delegate is destroyed.
# __del__ can not be called multiple times, so if the delegate is destroyed.
# don't try to destroy it twice.
if self._library is not None:
self._library.tflite_plugin_destroy_delegate.argtypes = [ctypes.c_void_p]

View File

@ -305,7 +305,12 @@ class InterpreterDelegateTest(test_util.TensorFlowTestCase):
if sys.platform == 'darwin': return
destructions = []
def register_destruction(x):
destructions.append(x)
if (type(x) is not bytes):
destructions.append(x)
else:
# To support both: PY2 and PY3, we don't use the function decode, but do this way
y = ''.join(chr(l) for l in x)
destructions.append(y)
return 0
# Make a wrapper for the callback so we can send this to ctypes
delegate = interpreter_wrapper.load_delegate(self._delegate_file)
@ -342,8 +347,8 @@ class InterpreterDelegateTest(test_util.TensorFlowTestCase):
delegate_b = interpreter_wrapper.load_delegate(
self._delegate_file, options={
'unused': False,
'options_counter': 2
'unused': False,
'options_counter': 2
})
lib = delegate_b._library
@ -354,7 +359,6 @@ class InterpreterDelegateTest(test_util.TensorFlowTestCase):
del delegate_a
del delegate_b
self.assertEqual(lib.get_num_delegates_created(), 2)
self.assertEqual(lib.get_num_delegates_destroyed(), 2)
self.assertEqual(lib.get_num_delegates_invoked(), 0)
@ -364,7 +368,9 @@ class InterpreterDelegateTest(test_util.TensorFlowTestCase):
# TODO(b/137299813): Enable when we fix for mac
if sys.platform == 'darwin': return
with self.assertRaisesRegexp(
ValueError, 'Failed to load delegate from .*\nFail argument sent.'):
# Due to exception chaining in PY3, we can't be more specific here and check that
# the phrase 'Fail argument sent' is present.
ValueError, r'Failed to load delegate from'):
interpreter_wrapper.load_delegate(
self._delegate_file, options={'fail': 'fail'})

View File

@ -66,7 +66,12 @@ void set_destroy_callback(int (*callback)(const char* s)) {
void tflite_plugin_destroy_delegate(TfLiteDelegate* delegate) {
num_delegates_destroyed++;
delete delegate;
if (destruction_callback) destruction_callback("test_delegate");
if (destruction_callback) {
destruction_callback("test_delegate");
// destruction_callback is a global variable,
// so it should be set to nullptr here to avoid crashes
destruction_callback = nullptr;
}
}
void initialize_counters() {