We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Log the contents of config file at the debug level early
This helps in debugging remote user's malformed json/yaml or configs that don't adhere to schema.

--- 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/config_parser.py`
Content:
```
1 # Copyright 2016 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 from builtins import str
16 
17 import copy
18 import io
19 import os
20 import yaml
21 
22 from mobly import keys
23 from mobly import utils
24 
25 # An environment variable defining the base location for Mobly logs.
26 ENV_MOBLY_LOGPATH = 'MOBLY_LOGPATH'
27 _DEFAULT_LOG_PATH = '/tmp/logs/mobly/'
28 
29 
30 class MoblyConfigError(Exception):
31     """Raised when there is a problem in test configuration file."""
32 
33 
34 def _validate_test_config(test_config):
35     """Validates the raw configuration loaded from the config file.
36 
37     Making sure the required key 'TestBeds' is present.
38     """
39     required_key = keys.Config.key_testbed.value
40     if required_key not in test_config:
41         raise MoblyConfigError(
42             'Required key %s missing in test config.' % required_key)
43 
44 
45 def _validate_testbed_name(name):
46     """Validates the name of a test bed.
47 
48     Since test bed names are used as part of the test run id, it needs to meet
49     certain requirements.
50 
51     Args:
52         name: The test bed's name specified in config file.
53 
54     Raises:
55         MoblyConfigError: The name does not meet any criteria.
56     """
57     if not name:
58         raise MoblyConfigError("Test bed names can't be empty.")
59     name = str(name)
60     for char in name:
61         if char not in utils.valid_filename_chars:
62             raise MoblyConfigError(
63                 'Char "%s" is not allowed in test bed names.' % char)
64 
65 
66 def _validate_testbed_configs(testbed_configs):
67     """Validates the testbed configurations.
68 
69     Args:
70         testbed_configs: A list of testbed configuration dicts.
71 
72     Raises:
73         MoblyConfigError: Some parts of the configuration is invalid.
74     """
75     seen_names = set()
76     # Cross checks testbed configs for resource conflicts.
77     for config in testbed_configs:
78         # Check for conflicts between multiple concurrent testbed configs.
79         # No need to call it if there's only one testbed config.
80         name = config[keys.Config.key_testbed_name.value]
81         _validate_testbed_name(name)
82         # Test bed names should be unique.
83         if name in seen_names:
84             raise MoblyConfigError('Duplicate testbed name %s found.' % name)
85         seen_names.add(name)
86 
87 
88 def load_test_config_file(test_config_path, tb_filters=None):
89     """Processes the test configuration file provied by user.
90 
91     Loads the configuration file into a dict, unpacks each testbed
92     config into its own dict, and validate the configuration in the
93     process.
94 
95     Args:
96         test_config_path: Path to the test configuration file.
97         tb_filters: A subset of test bed names to be pulled from the config
98             file. If None, then all test beds will be selected.
99 
100     Returns:
101         A list of test configuration dicts to be passed to
102         test_runner.TestRunner.
103     """
104     configs = _load_config_file(test_config_path)
105     if tb_filters:
106         tbs = []
107         for tb in configs[keys.Config.key_testbed.value]:
108             if tb[keys.Config.key_testbed_name.value] in tb_filters:
109                 tbs.append(tb)
110         if len(tbs) != len(tb_filters):
111             raise MoblyConfigError(
112                 'Expect to find %d test bed configs, found %d. Check if'
113                 ' you have the correct test bed names.' % (len(tb_filters),
114                                                            len(tbs)))
115         configs[keys.Config.key_testbed.value] = tbs
116     mobly_params = configs.get(keys.Config.key_mobly_params.value, {})
117     # Decide log path.
118     log_path = mobly_params.get(keys.Config.key_log_path.value,
119                                 _DEFAULT_LOG_PATH)
120     if ENV_MOBLY_LOGPATH in os.environ:
121         log_path = os.environ[ENV_MOBLY_LOGPATH]
122     log_path = utils.abs_path(log_path)
123     # Validate configs
124     _validate_test_config(configs)
125     _validate_testbed_configs(configs[keys.Config.key_testbed.value])
126     # Transform config dict from user-facing key mapping to internal config object.
127     test_configs = []
128     for original_bed_config in configs[keys.Config.key_testbed.value]:
129         test_run_config = TestRunConfig()
130         test_run_config.test_bed_name = original_bed_config[
131             keys.Config.key_testbed_name.value]
132         test_run_config.log_path = log_path
133         test_run_config.controller_configs = original_bed_config.get(
134             keys.Config.key_testbed_controllers.value, {})
135         test_run_config.user_params = original_bed_config.get(
136             keys.Config.key_testbed_test_params.value, {})
137         test_configs.append(test_run_config)
138     return test_configs
139 
140 
141 def _load_config_file(path):
142     """Loads a test config file.
143 
144     The test config file has to be in YAML format.
145 
146     Args:
147         path: A string that is the full path to the config file, including the
148             file name.
149 
150     Returns:
151         A dict that represents info in the config file.
152     """
153     with io.open(utils.abs_path(path), 'r', encoding='utf-8') as f:
154         conf = yaml.load(f)
155         return conf
156 
157 
158 class TestRunConfig(object):
159     """The data class that holds all the information needed for a test run.
160 
161     Attributes:
162         log_path: string, specifies the root directory for all logs written by
163             a test run.
164         test_bed_name: string, the name of the test bed used by a test run.
165         controller_configs: dict, configs used for instantiating controller
166             objects.
167         user_params: dict, all the parameters to be consumed by the test logic.
168         register_controller: func, used by test classes to register controller
169             modules.
170         summary_writer: records.TestSummaryWriter, used to write elements to
171             the test result summary file.
172         test_class_name_suffix: string, suffix to append to the class name for
173                 reporting. This is used for differentiating the same class
174                 executed with different parameters in a suite.
175     """
176 
177     def __init__(self):
178         self.log_path = None
179         self.test_bed_name = None
180         self.controller_configs = None
181         self.user_params = None
182         self.register_controller = None
183         self.summary_writer = None
184         self.test_class_name_suffix = None
185 
186     def copy(self):
187         """Returns a deep copy of the current config.
188         """
189         return copy.deepcopy(self)
190 
191     def __str__(self):
192         return str(self.__dict__)
193
```
--- 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/config_parser.py b/mobly/config_parser.py
--- a/mobly/config_parser.py
+++ b/mobly/config_parser.py
@@ -16,6 +16,7 @@
 
 import copy
 import io
+import pprint
 import os
 import yaml
 
@@ -189,4 +190,7 @@
         return copy.deepcopy(self)
 
     def __str__(self):
-        return str(self.__dict__)
+        content = dict(self.__dict__)
+        content.pop('summary_writer')
+        content.pop('register_controller')
+        return pprint.pformat(content)

{"golden_diff": "diff --git a/mobly/config_parser.py b/mobly/config_parser.py\n--- a/mobly/config_parser.py\n+++ b/mobly/config_parser.py\n@@ -16,6 +16,7 @@\n \n import copy\n import io\n+import pprint\n import os\n import yaml\n \n@@ -189,4 +190,7 @@\n         return copy.deepcopy(self)\n \n     def __str__(self):\n-        return str(self.__dict__)\n+        content = dict(self.__dict__)\n+        content.pop('summary_writer')\n+        content.pop('register_controller')\n+        return pprint.pformat(content)\n", "issue": "Log the contents of config file at the debug level early\nThis helps in debugging remote user's malformed json/yaml or configs that don't adhere to schema.\n", "before_files": [{"content": "# Copyright 2016 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\nfrom builtins import str\n\nimport copy\nimport io\nimport os\nimport yaml\n\nfrom mobly import keys\nfrom mobly import utils\n\n# An environment variable defining the base location for Mobly logs.\nENV_MOBLY_LOGPATH = 'MOBLY_LOGPATH'\n_DEFAULT_LOG_PATH = '/tmp/logs/mobly/'\n\n\nclass MoblyConfigError(Exception):\n    \"\"\"Raised when there is a problem in test configuration file.\"\"\"\n\n\ndef _validate_test_config(test_config):\n    \"\"\"Validates the raw configuration loaded from the config file.\n\n    Making sure the required key 'TestBeds' is present.\n    \"\"\"\n    required_key = keys.Config.key_testbed.value\n    if required_key not in test_config:\n        raise MoblyConfigError(\n            'Required key %s missing in test config.' % required_key)\n\n\ndef _validate_testbed_name(name):\n    \"\"\"Validates the name of a test bed.\n\n    Since test bed names are used as part of the test run id, it needs to meet\n    certain requirements.\n\n    Args:\n        name: The test bed's name specified in config file.\n\n    Raises:\n        MoblyConfigError: The name does not meet any criteria.\n    \"\"\"\n    if not name:\n        raise MoblyConfigError(\"Test bed names can't be empty.\")\n    name = str(name)\n    for char in name:\n        if char not in utils.valid_filename_chars:\n            raise MoblyConfigError(\n                'Char \"%s\" is not allowed in test bed names.' % char)\n\n\ndef _validate_testbed_configs(testbed_configs):\n    \"\"\"Validates the testbed configurations.\n\n    Args:\n        testbed_configs: A list of testbed configuration dicts.\n\n    Raises:\n        MoblyConfigError: Some parts of the configuration is invalid.\n    \"\"\"\n    seen_names = set()\n    # Cross checks testbed configs for resource conflicts.\n    for config in testbed_configs:\n        # Check for conflicts between multiple concurrent testbed configs.\n        # No need to call it if there's only one testbed config.\n        name = config[keys.Config.key_testbed_name.value]\n        _validate_testbed_name(name)\n        # Test bed names should be unique.\n        if name in seen_names:\n            raise MoblyConfigError('Duplicate testbed name %s found.' % name)\n        seen_names.add(name)\n\n\ndef load_test_config_file(test_config_path, tb_filters=None):\n    \"\"\"Processes the test configuration file provied by user.\n\n    Loads the configuration file into a dict, unpacks each testbed\n    config into its own dict, and validate the configuration in the\n    process.\n\n    Args:\n        test_config_path: Path to the test configuration file.\n        tb_filters: A subset of test bed names to be pulled from the config\n            file. If None, then all test beds will be selected.\n\n    Returns:\n        A list of test configuration dicts to be passed to\n        test_runner.TestRunner.\n    \"\"\"\n    configs = _load_config_file(test_config_path)\n    if tb_filters:\n        tbs = []\n        for tb in configs[keys.Config.key_testbed.value]:\n            if tb[keys.Config.key_testbed_name.value] in tb_filters:\n                tbs.append(tb)\n        if len(tbs) != len(tb_filters):\n            raise MoblyConfigError(\n                'Expect to find %d test bed configs, found %d. Check if'\n                ' you have the correct test bed names.' % (len(tb_filters),\n                                                           len(tbs)))\n        configs[keys.Config.key_testbed.value] = tbs\n    mobly_params = configs.get(keys.Config.key_mobly_params.value, {})\n    # Decide log path.\n    log_path = mobly_params.get(keys.Config.key_log_path.value,\n                                _DEFAULT_LOG_PATH)\n    if ENV_MOBLY_LOGPATH in os.environ:\n        log_path = os.environ[ENV_MOBLY_LOGPATH]\n    log_path = utils.abs_path(log_path)\n    # Validate configs\n    _validate_test_config(configs)\n    _validate_testbed_configs(configs[keys.Config.key_testbed.value])\n    # Transform config dict from user-facing key mapping to internal config object.\n    test_configs = []\n    for original_bed_config in configs[keys.Config.key_testbed.value]:\n        test_run_config = TestRunConfig()\n        test_run_config.test_bed_name = original_bed_config[\n            keys.Config.key_testbed_name.value]\n        test_run_config.log_path = log_path\n        test_run_config.controller_configs = original_bed_config.get(\n            keys.Config.key_testbed_controllers.value, {})\n        test_run_config.user_params = original_bed_config.get(\n            keys.Config.key_testbed_test_params.value, {})\n        test_configs.append(test_run_config)\n    return test_configs\n\n\ndef _load_config_file(path):\n    \"\"\"Loads a test config file.\n\n    The test config file has to be in YAML format.\n\n    Args:\n        path: A string that is the full path to the config file, including the\n            file name.\n\n    Returns:\n        A dict that represents info in the config file.\n    \"\"\"\n    with io.open(utils.abs_path(path), 'r', encoding='utf-8') as f:\n        conf = yaml.load(f)\n        return conf\n\n\nclass TestRunConfig(object):\n    \"\"\"The data class that holds all the information needed for a test run.\n\n    Attributes:\n        log_path: string, specifies the root directory for all logs written by\n            a test run.\n        test_bed_name: string, the name of the test bed used by a test run.\n        controller_configs: dict, configs used for instantiating controller\n            objects.\n        user_params: dict, all the parameters to be consumed by the test logic.\n        register_controller: func, used by test classes to register controller\n            modules.\n        summary_writer: records.TestSummaryWriter, used to write elements to\n            the test result summary file.\n        test_class_name_suffix: string, suffix to append to the class name for\n                reporting. This is used for differentiating the same class\n                executed with different parameters in a suite.\n    \"\"\"\n\n    def __init__(self):\n        self.log_path = None\n        self.test_bed_name = None\n        self.controller_configs = None\n        self.user_params = None\n        self.register_controller = None\n        self.summary_writer = None\n        self.test_class_name_suffix = None\n\n    def copy(self):\n        \"\"\"Returns a deep copy of the current config.\n        \"\"\"\n        return copy.deepcopy(self)\n\n    def __str__(self):\n        return str(self.__dict__)\n", "path": "mobly/config_parser.py"}], "after_files": [{"content": "# Copyright 2016 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\nfrom builtins import str\n\nimport copy\nimport io\nimport pprint\nimport os\nimport yaml\n\nfrom mobly import keys\nfrom mobly import utils\n\n# An environment variable defining the base location for Mobly logs.\nENV_MOBLY_LOGPATH = 'MOBLY_LOGPATH'\n_DEFAULT_LOG_PATH = '/tmp/logs/mobly/'\n\n\nclass MoblyConfigError(Exception):\n    \"\"\"Raised when there is a problem in test configuration file.\"\"\"\n\n\ndef _validate_test_config(test_config):\n    \"\"\"Validates the raw configuration loaded from the config file.\n\n    Making sure the required key 'TestBeds' is present.\n    \"\"\"\n    required_key = keys.Config.key_testbed.value\n    if required_key not in test_config:\n        raise MoblyConfigError(\n            'Required key %s missing in test config.' % required_key)\n\n\ndef _validate_testbed_name(name):\n    \"\"\"Validates the name of a test bed.\n\n    Since test bed names are used as part of the test run id, it needs to meet\n    certain requirements.\n\n    Args:\n        name: The test bed's name specified in config file.\n\n    Raises:\n        MoblyConfigError: The name does not meet any criteria.\n    \"\"\"\n    if not name:\n        raise MoblyConfigError(\"Test bed names can't be empty.\")\n    name = str(name)\n    for char in name:\n        if char not in utils.valid_filename_chars:\n            raise MoblyConfigError(\n                'Char \"%s\" is not allowed in test bed names.' % char)\n\n\ndef _validate_testbed_configs(testbed_configs):\n    \"\"\"Validates the testbed configurations.\n\n    Args:\n        testbed_configs: A list of testbed configuration dicts.\n\n    Raises:\n        MoblyConfigError: Some parts of the configuration is invalid.\n    \"\"\"\n    seen_names = set()\n    # Cross checks testbed configs for resource conflicts.\n    for config in testbed_configs:\n        # Check for conflicts between multiple concurrent testbed configs.\n        # No need to call it if there's only one testbed config.\n        name = config[keys.Config.key_testbed_name.value]\n        _validate_testbed_name(name)\n        # Test bed names should be unique.\n        if name in seen_names:\n            raise MoblyConfigError('Duplicate testbed name %s found.' % name)\n        seen_names.add(name)\n\n\ndef load_test_config_file(test_config_path, tb_filters=None):\n    \"\"\"Processes the test configuration file provied by user.\n\n    Loads the configuration file into a dict, unpacks each testbed\n    config into its own dict, and validate the configuration in the\n    process.\n\n    Args:\n        test_config_path: Path to the test configuration file.\n        tb_filters: A subset of test bed names to be pulled from the config\n            file. If None, then all test beds will be selected.\n\n    Returns:\n        A list of test configuration dicts to be passed to\n        test_runner.TestRunner.\n    \"\"\"\n    configs = _load_config_file(test_config_path)\n    if tb_filters:\n        tbs = []\n        for tb in configs[keys.Config.key_testbed.value]:\n            if tb[keys.Config.key_testbed_name.value] in tb_filters:\n                tbs.append(tb)\n        if len(tbs) != len(tb_filters):\n            raise MoblyConfigError(\n                'Expect to find %d test bed configs, found %d. Check if'\n                ' you have the correct test bed names.' % (len(tb_filters),\n                                                           len(tbs)))\n        configs[keys.Config.key_testbed.value] = tbs\n    mobly_params = configs.get(keys.Config.key_mobly_params.value, {})\n    # Decide log path.\n    log_path = mobly_params.get(keys.Config.key_log_path.value,\n                                _DEFAULT_LOG_PATH)\n    if ENV_MOBLY_LOGPATH in os.environ:\n        log_path = os.environ[ENV_MOBLY_LOGPATH]\n    log_path = utils.abs_path(log_path)\n    # Validate configs\n    _validate_test_config(configs)\n    _validate_testbed_configs(configs[keys.Config.key_testbed.value])\n    # Transform config dict from user-facing key mapping to internal config object.\n    test_configs = []\n    for original_bed_config in configs[keys.Config.key_testbed.value]:\n        test_run_config = TestRunConfig()\n        test_run_config.test_bed_name = original_bed_config[\n            keys.Config.key_testbed_name.value]\n        test_run_config.log_path = log_path\n        test_run_config.controller_configs = original_bed_config.get(\n            keys.Config.key_testbed_controllers.value, {})\n        test_run_config.user_params = original_bed_config.get(\n            keys.Config.key_testbed_test_params.value, {})\n        test_configs.append(test_run_config)\n    return test_configs\n\n\ndef _load_config_file(path):\n    \"\"\"Loads a test config file.\n\n    The test config file has to be in YAML format.\n\n    Args:\n        path: A string that is the full path to the config file, including the\n            file name.\n\n    Returns:\n        A dict that represents info in the config file.\n    \"\"\"\n    with io.open(utils.abs_path(path), 'r', encoding='utf-8') as f:\n        conf = yaml.load(f)\n        return conf\n\n\nclass TestRunConfig(object):\n    \"\"\"The data class that holds all the information needed for a test run.\n\n    Attributes:\n        log_path: string, specifies the root directory for all logs written by\n            a test run.\n        test_bed_name: string, the name of the test bed used by a test run.\n        controller_configs: dict, configs used for instantiating controller\n            objects.\n        user_params: dict, all the parameters to be consumed by the test logic.\n        register_controller: func, used by test classes to register controller\n            modules.\n        summary_writer: records.TestSummaryWriter, used to write elements to\n            the test result summary file.\n        test_class_name_suffix: string, suffix to append to the class name for\n                reporting. This is used for differentiating the same class\n                executed with different parameters in a suite.\n    \"\"\"\n\n    def __init__(self):\n        self.log_path = None\n        self.test_bed_name = None\n        self.controller_configs = None\n        self.user_params = None\n        self.register_controller = None\n        self.summary_writer = None\n        self.test_class_name_suffix = None\n\n    def copy(self):\n        \"\"\"Returns a deep copy of the current config.\n        \"\"\"\n        return copy.deepcopy(self)\n\n    def __str__(self):\n        content = dict(self.__dict__)\n        content.pop('summary_writer')\n        content.pop('register_controller')\n        return pprint.pformat(content)\n", "path": "mobly/config_parser.py"}]}