prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Exceptions from `CallbackHandler` should include timeout value
  Right now some timeout exceptions thrown by `CallbackHandler` do not include how long the timeout was, making debugging more difficult.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `mobly/controllers/android_device_lib/callback_handler.py`
  Content:
  ```
  1 # Copyright 2017 Google Inc.
  2 # 
  3 # Licensed under the Apache License, Version 2.0 (the "License");
  4 # you may not use this file except in compliance with the License.
  5 # You may obtain a copy of the License at
  6 # 
  7 #     http://www.apache.org/licenses/LICENSE-2.0
  8 # 
  9 # Unless required by applicable law or agreed to in writing, software
  10 # distributed under the License is distributed on an "AS IS" BASIS,
  11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 # See the License for the specific language governing permissions and
  13 # limitations under the License.
  14 
  15 import time
  16 
  17 from mobly.controllers.android_device_lib import snippet_event
  18 
  19 # The max timeout cannot be larger than the max time the socket waits for a
  20 # response message. Otherwise, the socket would timeout before the Rpc call
  21 # does, leaving both server and client in unknown states.
  22 MAX_TIMEOUT = 60 * 10
  23 DEFAULT_TIMEOUT = 120  # two minutes
  24 
  25 
  26 class Error(Exception):
  27     pass
  28 
  29 
  30 class TimeoutError(Error):
  31     pass
  32 
  33 
  34 class CallbackHandler(object):
  35     """The class used to handle a specific group of callback events.
  36 
  37     All the events handled by a CallbackHandler are originally triggered by one
  38     async Rpc call. All the events are tagged with a callback_id specific to a
  39     call to an AsyncRpc method defined on the server side.
  40 
  41     The raw message representing an event looks like:
  42     {
  43         'callbackId': <string, callbackId>,
  44         'name': <string, name of the event>,
  45         'time': <long, epoch time of when the event was created on the server
  46                  side>,
  47         'data': <dict, extra data from the callback on the server side>
  48     }
  49 
  50     Each message is then used to create a SnippetEvent object on the client
  51     side.
  52 
  53     Attributes:
  54         ret_value: The direct return value of the async Rpc call.
  55     """
  56 
  57     def __init__(self, callback_id, event_client, ret_value, method_name):
  58         self._id = callback_id
  59         self._event_client = event_client
  60         self.ret_value = ret_value
  61         self._method_name = method_name
  62 
  63     def waitAndGet(self, event_name, timeout=DEFAULT_TIMEOUT):
  64         """Blocks until an event of the specified name has been received and
  65         return the event, or timeout.
  66 
  67         Args:
  68             event_name: string, name of the event to get.
  69             timeout: float, the number of seconds to wait before giving up.
  70 
  71         Returns:
  72             SnippetEvent, the oldest entry of the specified event.
  73 
  74         Raises:
  75             Error: If the specified timeout is longer than the max timeout
  76                    supported.
  77             TimeoutError: The expected event does not occur within time limit.
  78         """
  79         if timeout:
  80             if timeout > MAX_TIMEOUT:
  81                 raise Error(
  82                     'Specified timeout %s is longer than max timeout %s.' %
  83                     (timeout, MAX_TIMEOUT))
  84             timeout *= 1000  # convert to milliseconds for java side
  85         try:
  86             raw_event = self._event_client.eventWaitAndGet(self._id,
  87                                                            event_name, timeout)
  88         except Exception as e:
  89             if 'EventSnippetException: timeout.' in str(e):
  90                 raise TimeoutError(
  91                     'Timeout waiting for event "%s" triggered by %s (%s).' %
  92                     (event_name, self._method_name, self._id))
  93             raise
  94         return snippet_event.from_dict(raw_event)
  95 
  96     def waitForEvent(self, event_name, predicate, timeout=DEFAULT_TIMEOUT):
  97         """Wait for an event of a specific name that satisfies the predicate.
  98 
  99         This call will block until the expected event has been received or time
  100         out.
  101 
  102         The predicate function defines the condition the event is expected to
  103         satisfy. It takes an event and returns True if the condition is
  104         satisfied, False otherwise.
  105 
  106         Note all events of the same name that are received but don't satisfy
  107         the predicate will be discarded and not be available for further
  108         consumption.
  109 
  110         Args:
  111           event_name: string, the name of the event to wait for.
  112           predicate: function, a function that takes an event (dictionary) and
  113                      returns a bool.
  114           timeout: float, default is 120s.
  115 
  116         Returns:
  117           dictionary, the event that satisfies the predicate if received.
  118 
  119         Raises:
  120           TimeoutError: raised if no event that satisfies the predicate is
  121                         received after timeout seconds.
  122         """
  123         deadline = time.time() + timeout
  124         while time.time() <= deadline:
  125             # Calculate the max timeout for the next event rpc call.
  126             rpc_timeout = deadline - time.time()
  127             if rpc_timeout < 0:
  128                 break
  129             try:
  130                 event = self.waitAndGet(event_name, rpc_timeout)
  131             except TimeoutError:
  132                 # Ignoring TimeoutError since we need to throw one with a more
  133                 # specific message.
  134                 break
  135             if predicate(event):
  136                 return event
  137         raise TimeoutError(
  138             'Timed out after %ss waiting for an "%s" event that satisfies the '
  139             'predicate "%s".' % (timeout, event_name, predicate.__name__))
  140 
  141     def getAll(self, event_name):
  142         """Gets all the events of a certain name that have been received so
  143         far. This is a non-blocking call.
  144 
  145         Args:
  146             callback_id: The id of the callback.
  147             event_name: string, the name of the event to get.
  148 
  149         Returns:
  150             A list of SnippetEvent, each representing an event from the Java
  151             side.
  152         """
  153         raw_events = self._event_client.eventGetAll(self._id, event_name)
  154         return [snippet_event.from_dict(msg) for msg in raw_events]
  155
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/mobly/controllers/android_device_lib/callback_handler.py b/mobly/controllers/android_device_lib/callback_handler.py
  --- a/mobly/controllers/android_device_lib/callback_handler.py
  +++ b/mobly/controllers/android_device_lib/callback_handler.py
  @@ -83,13 +83,14 @@
                       (timeout, MAX_TIMEOUT))
               timeout *= 1000  # convert to milliseconds for java side
           try:
  -            raw_event = self._event_client.eventWaitAndGet(self._id,
  -                                                           event_name, timeout)
  +            raw_event = self._event_client.eventWaitAndGet(
  +                self._id, event_name, timeout)
           except Exception as e:
               if 'EventSnippetException: timeout.' in str(e):
                   raise TimeoutError(
  -                    'Timeout waiting for event "%s" triggered by %s (%s).' %
  -                    (event_name, self._method_name, self._id))
  +                    'Timed out after waiting %ss for event "%s" triggered by'
  +                    ' %s (%s).' % (timeout, event_name, self._method_name,
  +                                   self._id))
               raise
           return snippet_event.from_dict(raw_event)
  
verification_info: {"golden_diff": "diff --git a/mobly/controllers/android_device_lib/callback_handler.py b/mobly/controllers/android_device_lib/callback_handler.py\n--- a/mobly/controllers/android_device_lib/callback_handler.py\n+++ b/mobly/controllers/android_device_lib/callback_handler.py\n@@ -83,13 +83,14 @@\n                     (timeout, MAX_TIMEOUT))\n             timeout *= 1000  # convert to milliseconds for java side\n         try:\n-            raw_event = self._event_client.eventWaitAndGet(self._id,\n-                                                           event_name, timeout)\n+            raw_event = self._event_client.eventWaitAndGet(\n+                self._id, event_name, timeout)\n         except Exception as e:\n             if 'EventSnippetException: timeout.' in str(e):\n                 raise TimeoutError(\n-                    'Timeout waiting for event \"%s\" triggered by %s (%s).' %\n-                    (event_name, self._method_name, self._id))\n+                    'Timed out after waiting %ss for event \"%s\" triggered by'\n+                    ' %s (%s).' % (timeout, event_name, self._method_name,\n+                                   self._id))\n             raise\n         return snippet_event.from_dict(raw_event)\n", "issue": "Exceptions from `CallbackHandler` should include timeout value\nRight now some timeout exceptions thrown by `CallbackHandler` do not include how long the timeout was, making debugging more difficult.\n", "before_files": [{"content": "# Copyright 2017 Google Inc.\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#     http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport time\n\nfrom mobly.controllers.android_device_lib import snippet_event\n\n# The max timeout cannot be larger than the max time the socket waits for a\n# response message. Otherwise, the socket would timeout before the Rpc call\n# does, leaving both server and client in unknown states.\nMAX_TIMEOUT = 60 * 10\nDEFAULT_TIMEOUT = 120  # two minutes\n\n\nclass Error(Exception):\n    pass\n\n\nclass TimeoutError(Error):\n    pass\n\n\nclass CallbackHandler(object):\n    \"\"\"The class used to handle a specific group of callback events.\n\n    All the events handled by a CallbackHandler are originally triggered by one\n    async Rpc call. All the events are tagged with a callback_id specific to a\n    call to an AsyncRpc method defined on the server side.\n\n    The raw message representing an event looks like:\n    {\n        'callbackId': <string, callbackId>,\n        'name': <string, name of the event>,\n        'time': <long, epoch time of when the event was created on the server\n                 side>,\n        'data': <dict, extra data from the callback on the server side>\n    }\n\n    Each message is then used to create a SnippetEvent object on the client\n    side.\n\n    Attributes:\n        ret_value: The direct return value of the async Rpc call.\n    \"\"\"\n\n    def __init__(self, callback_id, event_client, ret_value, method_name):\n        self._id = callback_id\n        self._event_client = event_client\n        self.ret_value = ret_value\n        self._method_name = method_name\n\n    def waitAndGet(self, event_name, timeout=DEFAULT_TIMEOUT):\n        \"\"\"Blocks until an event of the specified name has been received and\n        return the event, or timeout.\n\n        Args:\n            event_name: string, name of the event to get.\n            timeout: float, the number of seconds to wait before giving up.\n\n        Returns:\n            SnippetEvent, the oldest entry of the specified event.\n\n        Raises:\n            Error: If the specified timeout is longer than the max timeout\n                   supported.\n            TimeoutError: The expected event does not occur within time limit.\n        \"\"\"\n        if timeout:\n            if timeout > MAX_TIMEOUT:\n                raise Error(\n                    'Specified timeout %s is longer than max timeout %s.' %\n                    (timeout, MAX_TIMEOUT))\n            timeout *= 1000  # convert to milliseconds for java side\n        try:\n            raw_event = self._event_client.eventWaitAndGet(self._id,\n                                                           event_name, timeout)\n        except Exception as e:\n            if 'EventSnippetException: timeout.' in str(e):\n                raise TimeoutError(\n                    'Timeout waiting for event \"%s\" triggered by %s (%s).' %\n                    (event_name, self._method_name, self._id))\n            raise\n        return snippet_event.from_dict(raw_event)\n\n    def waitForEvent(self, event_name, predicate, timeout=DEFAULT_TIMEOUT):\n        \"\"\"Wait for an event of a specific name that satisfies the predicate.\n\n        This call will block until the expected event has been received or time\n        out.\n\n        The predicate function defines the condition the event is expected to\n        satisfy. It takes an event and returns True if the condition is\n        satisfied, False otherwise.\n\n        Note all events of the same name that are received but don't satisfy\n        the predicate will be discarded and not be available for further\n        consumption.\n\n        Args:\n          event_name: string, the name of the event to wait for.\n          predicate: function, a function that takes an event (dictionary) and\n                     returns a bool.\n          timeout: float, default is 120s.\n\n        Returns:\n          dictionary, the event that satisfies the predicate if received.\n\n        Raises:\n          TimeoutError: raised if no event that satisfies the predicate is\n                        received after timeout seconds.\n        \"\"\"\n        deadline = time.time() + timeout\n        while time.time() <= deadline:\n            # Calculate the max timeout for the next event rpc call.\n            rpc_timeout = deadline - time.time()\n            if rpc_timeout < 0:\n                break\n            try:\n                event = self.waitAndGet(event_name, rpc_timeout)\n            except TimeoutError:\n                # Ignoring TimeoutError since we need to throw one with a more\n                # specific message.\n                break\n            if predicate(event):\n                return event\n        raise TimeoutError(\n            'Timed out after %ss waiting for an \"%s\" event that satisfies the '\n            'predicate \"%s\".' % (timeout, event_name, predicate.__name__))\n\n    def getAll(self, event_name):\n        \"\"\"Gets all the events of a certain name that have been received so\n        far. This is a non-blocking call.\n\n        Args:\n            callback_id: The id of the callback.\n            event_name: string, the name of the event to get.\n\n        Returns:\n            A list of SnippetEvent, each representing an event from the Java\n            side.\n        \"\"\"\n        raw_events = self._event_client.eventGetAll(self._id, event_name)\n        return [snippet_event.from_dict(msg) for msg in raw_events]\n", "path": "mobly/controllers/android_device_lib/callback_handler.py"}], "after_files": [{"content": "# Copyright 2017 Google Inc.\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n# \n#     http://www.apache.org/licenses/LICENSE-2.0\n# \n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport time\n\nfrom mobly.controllers.android_device_lib import snippet_event\n\n# The max timeout cannot be larger than the max time the socket waits for a\n# response message. Otherwise, the socket would timeout before the Rpc call\n# does, leaving both server and client in unknown states.\nMAX_TIMEOUT = 60 * 10\nDEFAULT_TIMEOUT = 120  # two minutes\n\n\nclass Error(Exception):\n    pass\n\n\nclass TimeoutError(Error):\n    pass\n\n\nclass CallbackHandler(object):\n    \"\"\"The class used to handle a specific group of callback events.\n\n    All the events handled by a CallbackHandler are originally triggered by one\n    async Rpc call. All the events are tagged with a callback_id specific to a\n    call to an AsyncRpc method defined on the server side.\n\n    The raw message representing an event looks like:\n    {\n        'callbackId': <string, callbackId>,\n        'name': <string, name of the event>,\n        'time': <long, epoch time of when the event was created on the server\n                 side>,\n        'data': <dict, extra data from the callback on the server side>\n    }\n\n    Each message is then used to create a SnippetEvent object on the client\n    side.\n\n    Attributes:\n        ret_value: The direct return value of the async Rpc call.\n    \"\"\"\n\n    def __init__(self, callback_id, event_client, ret_value, method_name):\n        self._id = callback_id\n        self._event_client = event_client\n        self.ret_value = ret_value\n        self._method_name = method_name\n\n    def waitAndGet(self, event_name, timeout=DEFAULT_TIMEOUT):\n        \"\"\"Blocks until an event of the specified name has been received and\n        return the event, or timeout.\n\n        Args:\n            event_name: string, name of the event to get.\n            timeout: float, the number of seconds to wait before giving up.\n\n        Returns:\n            SnippetEvent, the oldest entry of the specified event.\n\n        Raises:\n            Error: If the specified timeout is longer than the max timeout\n                   supported.\n            TimeoutError: The expected event does not occur within time limit.\n        \"\"\"\n        if timeout:\n            if timeout > MAX_TIMEOUT:\n                raise Error(\n                    'Specified timeout %s is longer than max timeout %s.' %\n                    (timeout, MAX_TIMEOUT))\n            timeout *= 1000  # convert to milliseconds for java side\n        try:\n            raw_event = self._event_client.eventWaitAndGet(\n                self._id, event_name, timeout)\n        except Exception as e:\n            if 'EventSnippetException: timeout.' in str(e):\n                raise TimeoutError(\n                    'Timed out after waiting %ss for event \"%s\" triggered by'\n                    ' %s (%s).' % (timeout, event_name, self._method_name,\n                                   self._id))\n            raise\n        return snippet_event.from_dict(raw_event)\n\n    def waitForEvent(self, event_name, predicate, timeout=DEFAULT_TIMEOUT):\n        \"\"\"Wait for an event of a specific name that satisfies the predicate.\n\n        This call will block until the expected event has been received or time\n        out.\n\n        The predicate function defines the condition the event is expected to\n        satisfy. It takes an event and returns True if the condition is\n        satisfied, False otherwise.\n\n        Note all events of the same name that are received but don't satisfy\n        the predicate will be discarded and not be available for further\n        consumption.\n\n        Args:\n          event_name: string, the name of the event to wait for.\n          predicate: function, a function that takes an event (dictionary) and\n                     returns a bool.\n          timeout: float, default is 120s.\n\n        Returns:\n          dictionary, the event that satisfies the predicate if received.\n\n        Raises:\n          TimeoutError: raised if no event that satisfies the predicate is\n                        received after timeout seconds.\n        \"\"\"\n        deadline = time.time() + timeout\n        while time.time() <= deadline:\n            # Calculate the max timeout for the next event rpc call.\n            rpc_timeout = deadline - time.time()\n            if rpc_timeout < 0:\n                break\n            try:\n                event = self.waitAndGet(event_name, rpc_timeout)\n            except TimeoutError:\n                # Ignoring TimeoutError since we need to throw one with a more\n                # specific message.\n                break\n            if predicate(event):\n                return event\n        raise TimeoutError(\n            'Timed out after %ss waiting for an \"%s\" event that satisfies the '\n            'predicate \"%s\".' % (timeout, event_name, predicate.__name__))\n\n    def getAll(self, event_name):\n        \"\"\"Gets all the events of a certain name that have been received so\n        far. This is a non-blocking call.\n\n        Args:\n            callback_id: The id of the callback.\n            event_name: string, the name of the event to get.\n\n        Returns:\n            A list of SnippetEvent, each representing an event from the Java\n            side.\n        \"\"\"\n        raw_events = self._event_client.eventGetAll(self._id, event_name)\n        return [snippet_event.from_dict(msg) for msg in raw_events]\n", "path": "mobly/controllers/android_device_lib/callback_handler.py"}]}