From 86eaa103828d04fdd5be8cf14fbd62001ef610d0 Mon Sep 17 00:00:00 2001 From: kwy404 Date: Thu, 24 Sep 2026 08:47:18 -0300 Subject: [PATCH] Handle predicates without __name__ in waitForEvent timeouts --- mobly/snippet/callback_handler_base.py | 4 +++- .../snippet/callback_handler_base_test.py | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/mobly/snippet/callback_handler_base.py b/mobly/snippet/callback_handler_base.py index 992d9712..e9cf1172 100644 --- a/mobly/snippet/callback_handler_base.py +++ b/mobly/snippet/callback_handler_base.py @@ -233,10 +233,12 @@ def waitForEvent( return event custom_error = '' if message is None else f' Details: {message}.' + # Callables like functools.partial objects have no __name__. + predicate_name = getattr(predicate, '__name__', type(predicate).__name__) raise errors.CallbackHandlerTimeoutError( self._device, f'Timed out after {timeout}s waiting for an "{event_name}" event that ' - f'satisfies the predicate "{predicate.__name__}".{custom_error}', + f'satisfies the predicate "{predicate_name}".{custom_error}', ) def getAll(self, event_name): diff --git a/tests/mobly/snippet/callback_handler_base_test.py b/tests/mobly/snippet/callback_handler_base_test.py index 273df066..bb1eb541 100644 --- a/tests/mobly/snippet/callback_handler_base_test.py +++ b/tests/mobly/snippet/callback_handler_base_test.py @@ -13,6 +13,7 @@ # limitations under the License. """Unit tests for mobly.snippet.callback_handler_base.CallbackHandlerBase.""" +import functools import unittest from unittest import mock @@ -190,6 +191,24 @@ def some_condition(_): ): handler.waitForEvent('AsyncTaskResult', some_condition, 0.01) + def test_wait_for_event_negative_with_partial_predicate(self): + handler = FakeCallbackHandler() + handler.mock_rpc_func.callEventWaitAndGetRpc = mock.Mock( + return_value=MOCK_RAW_EVENT + ) + + def has_secret_number(event, number): + return event.data['secretNumber'] == number + + with self.assertRaisesRegex( + errors.CallbackHandlerTimeoutError, 'satisfies the predicate "partial"' + ): + handler.waitForEvent( + 'AsyncTaskResult', + functools.partial(has_secret_number, number=42), + 0.01, + ) + def test_wait_for_event_max_timeout(self): """waitForEvent should not raise the timeout exceed threshold error.""" rpc_max_timeout_sec = 5