We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Errors in `teardown_class` are not properly recorded
If Mobly encounters an error in the cleanup stage of `teardown_class`, the error would not be recorded anywhere except the cli output, which makes debugging difficult.

This points to a bigger problem: the errors occurred in base test and runner themselves are not clearly handled.

--- 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/controller_manager.py`
Content:
```
1 # Copyright 2018 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 """ Module for Mobly controller management."""
15 import collections
16 import copy
17 import logging
18 import yaml
19 
20 from mobly import records
21 from mobly import signals
22 
23 
24 def verify_controller_module(module):
25     """Verifies a module object follows the required interface for
26     controllers.
27 
28     The interface is explained in the docstring of
29     `base_test.BaseTestClass.register_controller`.
30 
31     Args:
32         module: An object that is a controller module. This is usually
33             imported with import statements or loaded by importlib.
34 
35     Raises:
36         ControllerError: if the module does not match the Mobly controller
37             interface, or one of the required members is null.
38     """
39     required_attributes = ('create', 'destroy', 'MOBLY_CONTROLLER_CONFIG_NAME')
40     for attr in required_attributes:
41         if not hasattr(module, attr):
42             raise signals.ControllerError(
43                 'Module %s missing required controller module attribute'
44                 ' %s.' % (module.__name__, attr))
45         if not getattr(module, attr):
46             raise signals.ControllerError(
47                 'Controller interface %s in %s cannot be null.' %
48                 (attr, module.__name__))
49 
50 
51 class ControllerManager(object):
52     """Manages the controller objects for Mobly.
53 
54     This manages the life cycles and info retrieval of all controller objects
55     used in a test.
56 
57     Attributes:
58         controller_configs: dict, controller configs provided by the user via
59             test bed config.
60     """
61 
62     def __init__(self, class_name, controller_configs):
63         # Controller object management.
64         self._controller_objects = collections.OrderedDict(
65         )  # controller_name: objects
66         self._controller_modules = {}  # controller_name: module
67         self._class_name = class_name
68         self.controller_configs = controller_configs
69 
70     def register_controller(self, module, required=True, min_number=1):
71         """Loads a controller module and returns its loaded devices.
72 
73         This is to be used in a mobly test class.
74 
75         Args:
76             module: A module that follows the controller module interface.
77             required: A bool. If True, failing to register the specified
78                 controller module raises exceptions. If False, the objects
79                 failed to instantiate will be skipped.
80             min_number: An integer that is the minimum number of controller
81                 objects to be created. Default is one, since you should not
82                 register a controller module without expecting at least one
83                 object.
84 
85         Returns:
86             A list of controller objects instantiated from controller_module, or
87             None if no config existed for this controller and it was not a
88             required controller.
89 
90         Raises:
91             ControllerError:
92                 * The controller module has already been registered.
93                 * The actual number of objects instantiated is less than the
94                 * `min_number`.
95                 * `required` is True and no corresponding config can be found.
96                 * Any other error occurred in the registration process.
97         """
98         verify_controller_module(module)
99         # Use the module's name as the ref name
100         module_ref_name = module.__name__.split('.')[-1]
101         if module_ref_name in self._controller_objects:
102             raise signals.ControllerError(
103                 'Controller module %s has already been registered. It cannot '
104                 'be registered again.' % module_ref_name)
105         # Create controller objects.
106         module_config_name = module.MOBLY_CONTROLLER_CONFIG_NAME
107         if module_config_name not in self.controller_configs:
108             if required:
109                 raise signals.ControllerError(
110                     'No corresponding config found for %s' %
111                     module_config_name)
112             logging.warning(
113                 'No corresponding config found for optional controller %s',
114                 module_config_name)
115             return None
116         try:
117             # Make a deep copy of the config to pass to the controller module,
118             # in case the controller module modifies the config internally.
119             original_config = self.controller_configs[module_config_name]
120             controller_config = copy.deepcopy(original_config)
121             objects = module.create(controller_config)
122         except:
123             logging.exception(
124                 'Failed to initialize objects for controller %s, abort!',
125                 module_config_name)
126             raise
127         if not isinstance(objects, list):
128             raise signals.ControllerError(
129                 'Controller module %s did not return a list of objects, abort.'
130                 % module_ref_name)
131         # Check we got enough controller objects to continue.
132         actual_number = len(objects)
133         if actual_number < min_number:
134             module.destroy(objects)
135             raise signals.ControllerError(
136                 'Expected to get at least %d controller objects, got %d.' %
137                 (min_number, actual_number))
138         # Save a shallow copy of the list for internal usage, so tests can't
139         # affect internal registry by manipulating the object list.
140         self._controller_objects[module_ref_name] = copy.copy(objects)
141         logging.debug('Found %d objects for controller %s', len(objects),
142                       module_config_name)
143         self._controller_modules[module_ref_name] = module
144         return objects
145 
146     def unregister_controllers(self):
147         """Destroy controller objects and clear internal registry.
148 
149         This will be called after each test class.
150         """
151         # TODO(xpconanfan): actually record these errors instead of just
152         # logging them.
153         for name, module in self._controller_modules.items():
154             logging.debug('Destroying %s.', name)
155             try:
156                 module.destroy(self._controller_objects[name])
157             except:
158                 logging.exception('Exception occurred destroying %s.', name)
159         self._controller_objects = collections.OrderedDict()
160         self._controller_modules = {}
161 
162     def _create_controller_info_record(self, controller_module_name):
163         """Creates controller info record for a particular controller type.
164 
165         Info is retrieved from all the controller objects spawned from the
166         specified module, using the controller module's `get_info` function.
167 
168         Args:
169             controller_module_name: string, the name of the controller module
170                 to retrieve info from.
171 
172         Returns:
173             A records.ControllerInfoRecord object.
174         """
175         module = self._controller_modules[controller_module_name]
176         controller_info = None
177         try:
178             controller_info = module.get_info(
179                 copy.copy(self._controller_objects[controller_module_name]))
180         except AttributeError:
181             logging.warning('No optional debug info found for controller '
182                             '%s. To provide it, implement `get_info`.',
183                             controller_module_name)
184         try:
185             yaml.dump(controller_info)
186         except TypeError:
187             logging.warning('The info of controller %s in class "%s" is not '
188                             'YAML serializable! Coercing it to string.',
189                             controller_module_name, self._class_name)
190             controller_info = str(controller_info)
191         return records.ControllerInfoRecord(
192             self._class_name, module.MOBLY_CONTROLLER_CONFIG_NAME,
193             controller_info)
194 
195     def get_controller_info_records(self):
196         """Get the info records for all the controller objects in the manager.
197 
198         New info records for each controller object are created for every call
199         so the latest info is included.
200 
201         Returns:
202             List of records.ControllerInfoRecord objects. Each opject conatins
203             the info of a type of controller
204         """
205         info_records = []
206         for controller_module_name in self._controller_objects.keys():
207             record = self._create_controller_info_record(
208                 controller_module_name)
209             if record:
210                 info_records.append(record)
211         return info_records
212
```
--- 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()

```

diff --git a/mobly/controller_manager.py b/mobly/controller_manager.py
--- a/mobly/controller_manager.py
+++ b/mobly/controller_manager.py
@@ -17,6 +17,7 @@
 import logging
 import yaml
 
+from mobly import expects
 from mobly import records
 from mobly import signals
 
@@ -152,10 +153,9 @@
         # logging them.
         for name, module in self._controller_modules.items():
             logging.debug('Destroying %s.', name)
-            try:
+            with expects.expect_no_raises(
+                    'Exception occurred destroying %s.' % name):
                 module.destroy(self._controller_objects[name])
-            except:
-                logging.exception('Exception occurred destroying %s.', name)
         self._controller_objects = collections.OrderedDict()
         self._controller_modules = {}
 
@@ -204,8 +204,11 @@
         """
         info_records = []
         for controller_module_name in self._controller_objects.keys():
-            record = self._create_controller_info_record(
-                controller_module_name)
-            if record:
-                info_records.append(record)
+            with expects.expect_no_raises(
+                    'Failed to collect controller info from %s' %
+                    controller_module_name):
+                record = self._create_controller_info_record(
+                    controller_module_name)
+                if record:
+                    info_records.append(record)
         return info_records

{"golden_diff": "diff --git a/mobly/controller_manager.py b/mobly/controller_manager.py\n--- a/mobly/controller_manager.py\n+++ b/mobly/controller_manager.py\n@@ -17,6 +17,7 @@\n import logging\n import yaml\n \n+from mobly import expects\n from mobly import records\n from mobly import signals\n \n@@ -152,10 +153,9 @@\n         # logging them.\n         for name, module in self._controller_modules.items():\n             logging.debug('Destroying %s.', name)\n-            try:\n+            with expects.expect_no_raises(\n+                    'Exception occurred destroying %s.' % name):\n                 module.destroy(self._controller_objects[name])\n-            except:\n-                logging.exception('Exception occurred destroying %s.', name)\n         self._controller_objects = collections.OrderedDict()\n         self._controller_modules = {}\n \n@@ -204,8 +204,11 @@\n         \"\"\"\n         info_records = []\n         for controller_module_name in self._controller_objects.keys():\n-            record = self._create_controller_info_record(\n-                controller_module_name)\n-            if record:\n-                info_records.append(record)\n+            with expects.expect_no_raises(\n+                    'Failed to collect controller info from %s' %\n+                    controller_module_name):\n+                record = self._create_controller_info_record(\n+                    controller_module_name)\n+                if record:\n+                    info_records.append(record)\n         return info_records\n", "issue": "Errors in `teardown_class` are not properly recorded\nIf Mobly encounters an error in the cleanup stage of `teardown_class`, the error would not be recorded anywhere except the cli output, which makes debugging difficult.\r\n\r\nThis points to a bigger problem: the errors occurred in base test and runner themselves are not clearly handled.\n", "before_files": [{"content": "# Copyright 2018 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\"\"\" Module for Mobly controller management.\"\"\"\nimport collections\nimport copy\nimport logging\nimport yaml\n\nfrom mobly import records\nfrom mobly import signals\n\n\ndef verify_controller_module(module):\n    \"\"\"Verifies a module object follows the required interface for\n    controllers.\n\n    The interface is explained in the docstring of\n    `base_test.BaseTestClass.register_controller`.\n\n    Args:\n        module: An object that is a controller module. This is usually\n            imported with import statements or loaded by importlib.\n\n    Raises:\n        ControllerError: if the module does not match the Mobly controller\n            interface, or one of the required members is null.\n    \"\"\"\n    required_attributes = ('create', 'destroy', 'MOBLY_CONTROLLER_CONFIG_NAME')\n    for attr in required_attributes:\n        if not hasattr(module, attr):\n            raise signals.ControllerError(\n                'Module %s missing required controller module attribute'\n                ' %s.' % (module.__name__, attr))\n        if not getattr(module, attr):\n            raise signals.ControllerError(\n                'Controller interface %s in %s cannot be null.' %\n                (attr, module.__name__))\n\n\nclass ControllerManager(object):\n    \"\"\"Manages the controller objects for Mobly.\n\n    This manages the life cycles and info retrieval of all controller objects\n    used in a test.\n\n    Attributes:\n        controller_configs: dict, controller configs provided by the user via\n            test bed config.\n    \"\"\"\n\n    def __init__(self, class_name, controller_configs):\n        # Controller object management.\n        self._controller_objects = collections.OrderedDict(\n        )  # controller_name: objects\n        self._controller_modules = {}  # controller_name: module\n        self._class_name = class_name\n        self.controller_configs = controller_configs\n\n    def register_controller(self, module, required=True, min_number=1):\n        \"\"\"Loads a controller module and returns its loaded devices.\n\n        This is to be used in a mobly test class.\n\n        Args:\n            module: A module that follows the controller module interface.\n            required: A bool. If True, failing to register the specified\n                controller module raises exceptions. If False, the objects\n                failed to instantiate will be skipped.\n            min_number: An integer that is the minimum number of controller\n                objects to be created. Default is one, since you should not\n                register a controller module without expecting at least one\n                object.\n\n        Returns:\n            A list of controller objects instantiated from controller_module, or\n            None if no config existed for this controller and it was not a\n            required controller.\n\n        Raises:\n            ControllerError:\n                * The controller module has already been registered.\n                * The actual number of objects instantiated is less than the\n                * `min_number`.\n                * `required` is True and no corresponding config can be found.\n                * Any other error occurred in the registration process.\n        \"\"\"\n        verify_controller_module(module)\n        # Use the module's name as the ref name\n        module_ref_name = module.__name__.split('.')[-1]\n        if module_ref_name in self._controller_objects:\n            raise signals.ControllerError(\n                'Controller module %s has already been registered. It cannot '\n                'be registered again.' % module_ref_name)\n        # Create controller objects.\n        module_config_name = module.MOBLY_CONTROLLER_CONFIG_NAME\n        if module_config_name not in self.controller_configs:\n            if required:\n                raise signals.ControllerError(\n                    'No corresponding config found for %s' %\n                    module_config_name)\n            logging.warning(\n                'No corresponding config found for optional controller %s',\n                module_config_name)\n            return None\n        try:\n            # Make a deep copy of the config to pass to the controller module,\n            # in case the controller module modifies the config internally.\n            original_config = self.controller_configs[module_config_name]\n            controller_config = copy.deepcopy(original_config)\n            objects = module.create(controller_config)\n        except:\n            logging.exception(\n                'Failed to initialize objects for controller %s, abort!',\n                module_config_name)\n            raise\n        if not isinstance(objects, list):\n            raise signals.ControllerError(\n                'Controller module %s did not return a list of objects, abort.'\n                % module_ref_name)\n        # Check we got enough controller objects to continue.\n        actual_number = len(objects)\n        if actual_number < min_number:\n            module.destroy(objects)\n            raise signals.ControllerError(\n                'Expected to get at least %d controller objects, got %d.' %\n                (min_number, actual_number))\n        # Save a shallow copy of the list for internal usage, so tests can't\n        # affect internal registry by manipulating the object list.\n        self._controller_objects[module_ref_name] = copy.copy(objects)\n        logging.debug('Found %d objects for controller %s', len(objects),\n                      module_config_name)\n        self._controller_modules[module_ref_name] = module\n        return objects\n\n    def unregister_controllers(self):\n        \"\"\"Destroy controller objects and clear internal registry.\n\n        This will be called after each test class.\n        \"\"\"\n        # TODO(xpconanfan): actually record these errors instead of just\n        # logging them.\n        for name, module in self._controller_modules.items():\n            logging.debug('Destroying %s.', name)\n            try:\n                module.destroy(self._controller_objects[name])\n            except:\n                logging.exception('Exception occurred destroying %s.', name)\n        self._controller_objects = collections.OrderedDict()\n        self._controller_modules = {}\n\n    def _create_controller_info_record(self, controller_module_name):\n        \"\"\"Creates controller info record for a particular controller type.\n\n        Info is retrieved from all the controller objects spawned from the\n        specified module, using the controller module's `get_info` function.\n\n        Args:\n            controller_module_name: string, the name of the controller module\n                to retrieve info from.\n\n        Returns:\n            A records.ControllerInfoRecord object.\n        \"\"\"\n        module = self._controller_modules[controller_module_name]\n        controller_info = None\n        try:\n            controller_info = module.get_info(\n                copy.copy(self._controller_objects[controller_module_name]))\n        except AttributeError:\n            logging.warning('No optional debug info found for controller '\n                            '%s. To provide it, implement `get_info`.',\n                            controller_module_name)\n        try:\n            yaml.dump(controller_info)\n        except TypeError:\n            logging.warning('The info of controller %s in class \"%s\" is not '\n                            'YAML serializable! Coercing it to string.',\n                            controller_module_name, self._class_name)\n            controller_info = str(controller_info)\n        return records.ControllerInfoRecord(\n            self._class_name, module.MOBLY_CONTROLLER_CONFIG_NAME,\n            controller_info)\n\n    def get_controller_info_records(self):\n        \"\"\"Get the info records for all the controller objects in the manager.\n\n        New info records for each controller object are created for every call\n        so the latest info is included.\n\n        Returns:\n            List of records.ControllerInfoRecord objects. Each opject conatins\n            the info of a type of controller\n        \"\"\"\n        info_records = []\n        for controller_module_name in self._controller_objects.keys():\n            record = self._create_controller_info_record(\n                controller_module_name)\n            if record:\n                info_records.append(record)\n        return info_records\n", "path": "mobly/controller_manager.py"}], "after_files": [{"content": "# Copyright 2018 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\"\"\" Module for Mobly controller management.\"\"\"\nimport collections\nimport copy\nimport logging\nimport yaml\n\nfrom mobly import expects\nfrom mobly import records\nfrom mobly import signals\n\n\ndef verify_controller_module(module):\n    \"\"\"Verifies a module object follows the required interface for\n    controllers.\n\n    The interface is explained in the docstring of\n    `base_test.BaseTestClass.register_controller`.\n\n    Args:\n        module: An object that is a controller module. This is usually\n            imported with import statements or loaded by importlib.\n\n    Raises:\n        ControllerError: if the module does not match the Mobly controller\n            interface, or one of the required members is null.\n    \"\"\"\n    required_attributes = ('create', 'destroy', 'MOBLY_CONTROLLER_CONFIG_NAME')\n    for attr in required_attributes:\n        if not hasattr(module, attr):\n            raise signals.ControllerError(\n                'Module %s missing required controller module attribute'\n                ' %s.' % (module.__name__, attr))\n        if not getattr(module, attr):\n            raise signals.ControllerError(\n                'Controller interface %s in %s cannot be null.' %\n                (attr, module.__name__))\n\n\nclass ControllerManager(object):\n    \"\"\"Manages the controller objects for Mobly.\n\n    This manages the life cycles and info retrieval of all controller objects\n    used in a test.\n\n    Attributes:\n        controller_configs: dict, controller configs provided by the user via\n            test bed config.\n    \"\"\"\n\n    def __init__(self, class_name, controller_configs):\n        # Controller object management.\n        self._controller_objects = collections.OrderedDict(\n        )  # controller_name: objects\n        self._controller_modules = {}  # controller_name: module\n        self._class_name = class_name\n        self.controller_configs = controller_configs\n\n    def register_controller(self, module, required=True, min_number=1):\n        \"\"\"Loads a controller module and returns its loaded devices.\n\n        This is to be used in a mobly test class.\n\n        Args:\n            module: A module that follows the controller module interface.\n            required: A bool. If True, failing to register the specified\n                controller module raises exceptions. If False, the objects\n                failed to instantiate will be skipped.\n            min_number: An integer that is the minimum number of controller\n                objects to be created. Default is one, since you should not\n                register a controller module without expecting at least one\n                object.\n\n        Returns:\n            A list of controller objects instantiated from controller_module, or\n            None if no config existed for this controller and it was not a\n            required controller.\n\n        Raises:\n            ControllerError:\n                * The controller module has already been registered.\n                * The actual number of objects instantiated is less than the\n                * `min_number`.\n                * `required` is True and no corresponding config can be found.\n                * Any other error occurred in the registration process.\n        \"\"\"\n        verify_controller_module(module)\n        # Use the module's name as the ref name\n        module_ref_name = module.__name__.split('.')[-1]\n        if module_ref_name in self._controller_objects:\n            raise signals.ControllerError(\n                'Controller module %s has already been registered. It cannot '\n                'be registered again.' % module_ref_name)\n        # Create controller objects.\n        module_config_name = module.MOBLY_CONTROLLER_CONFIG_NAME\n        if module_config_name not in self.controller_configs:\n            if required:\n                raise signals.ControllerError(\n                    'No corresponding config found for %s' %\n                    module_config_name)\n            logging.warning(\n                'No corresponding config found for optional controller %s',\n                module_config_name)\n            return None\n        try:\n            # Make a deep copy of the config to pass to the controller module,\n            # in case the controller module modifies the config internally.\n            original_config = self.controller_configs[module_config_name]\n            controller_config = copy.deepcopy(original_config)\n            objects = module.create(controller_config)\n        except:\n            logging.exception(\n                'Failed to initialize objects for controller %s, abort!',\n                module_config_name)\n            raise\n        if not isinstance(objects, list):\n            raise signals.ControllerError(\n                'Controller module %s did not return a list of objects, abort.'\n                % module_ref_name)\n        # Check we got enough controller objects to continue.\n        actual_number = len(objects)\n        if actual_number < min_number:\n            module.destroy(objects)\n            raise signals.ControllerError(\n                'Expected to get at least %d controller objects, got %d.' %\n                (min_number, actual_number))\n        # Save a shallow copy of the list for internal usage, so tests can't\n        # affect internal registry by manipulating the object list.\n        self._controller_objects[module_ref_name] = copy.copy(objects)\n        logging.debug('Found %d objects for controller %s', len(objects),\n                      module_config_name)\n        self._controller_modules[module_ref_name] = module\n        return objects\n\n    def unregister_controllers(self):\n        \"\"\"Destroy controller objects and clear internal registry.\n\n        This will be called after each test class.\n        \"\"\"\n        # TODO(xpconanfan): actually record these errors instead of just\n        # logging them.\n        for name, module in self._controller_modules.items():\n            logging.debug('Destroying %s.', name)\n            with expects.expect_no_raises(\n                    'Exception occurred destroying %s.' % name):\n                module.destroy(self._controller_objects[name])\n        self._controller_objects = collections.OrderedDict()\n        self._controller_modules = {}\n\n    def _create_controller_info_record(self, controller_module_name):\n        \"\"\"Creates controller info record for a particular controller type.\n\n        Info is retrieved from all the controller objects spawned from the\n        specified module, using the controller module's `get_info` function.\n\n        Args:\n            controller_module_name: string, the name of the controller module\n                to retrieve info from.\n\n        Returns:\n            A records.ControllerInfoRecord object.\n        \"\"\"\n        module = self._controller_modules[controller_module_name]\n        controller_info = None\n        try:\n            controller_info = module.get_info(\n                copy.copy(self._controller_objects[controller_module_name]))\n        except AttributeError:\n            logging.warning('No optional debug info found for controller '\n                            '%s. To provide it, implement `get_info`.',\n                            controller_module_name)\n        try:\n            yaml.dump(controller_info)\n        except TypeError:\n            logging.warning('The info of controller %s in class \"%s\" is not '\n                            'YAML serializable! Coercing it to string.',\n                            controller_module_name, self._class_name)\n            controller_info = str(controller_info)\n        return records.ControllerInfoRecord(\n            self._class_name, module.MOBLY_CONTROLLER_CONFIG_NAME,\n            controller_info)\n\n    def get_controller_info_records(self):\n        \"\"\"Get the info records for all the controller objects in the manager.\n\n        New info records for each controller object are created for every call\n        so the latest info is included.\n\n        Returns:\n            List of records.ControllerInfoRecord objects. Each opject conatins\n            the info of a type of controller\n        \"\"\"\n        info_records = []\n        for controller_module_name in self._controller_objects.keys():\n            with expects.expect_no_raises(\n                    'Failed to collect controller info from %s' %\n                    controller_module_name):\n                record = self._create_controller_info_record(\n                    controller_module_name)\n                if record:\n                    info_records.append(record)\n        return info_records\n", "path": "mobly/controller_manager.py"}]}