From 9e9c9dbbcb9eef6b3bc728f57764119059202685 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 --- .../android_device_lib/callback_handler.py | 3 ++- mobly/snippet/callback_handler_base.py | 4 +++- .../snippet/callback_handler_base_test.py | 19 +++++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/mobly/controllers/android_device_lib/callback_handler.py b/mobly/controllers/android_device_lib/callback_handler.py index 711c92af4..a8478177b 100644 --- a/mobly/controllers/android_device_lib/callback_handler.py +++ b/mobly/controllers/android_device_lib/callback_handler.py @@ -189,10 +189,11 @@ def waitForEvent(self, event_name, predicate, timeout=DEFAULT_TIMEOUT): break if predicate(event): return event + predicate_name = getattr(predicate, '__name__', repr(predicate)) raise TimeoutError( self._ad, 'Timed out after %ss waiting for an "%s" event that satisfies the ' - 'predicate "%s".' % (timeout, event_name, predicate.__name__), + 'predicate "%s".' % (timeout, event_name, predicate_name), ) def getAll(self, event_name): diff --git a/mobly/snippet/callback_handler_base.py b/mobly/snippet/callback_handler_base.py index 992d97127..688fa8f08 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__', repr(predicate)) 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 273df0665..9bb21681b 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' + ): + 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