prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  BigQuery: expose public helper method to convert a list of schema fields to/from a list of schema dictionaries (JSON)
  I've received some feedback asking how to take a schema from the client library and save it to a JSON file. One reason to do this is the [`bq` command-line tool](https://cloud.google.com/bigquery/bq-command-line-tool#creatingtablefromfile) accepts a schema file, formatted like
  
  ```
  [
    {"name": "name", "type": "string", "mode": "required"},
    {"name": "gender", "type": "string", "mode": "nullable"},
    {"name": "count", "type": "integer", "mode": "required"}
  ]
  ```
  
  Note: this format is the same as the API representation.
  
  It would be great if our client libraries could read/write in this format.
  
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `bigquery/google/cloud/bigquery/schema.py`
  Content:
  ```
  1 # Copyright 2015 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 """Schemas for BigQuery tables / queries."""
  16 
  17 
  18 class SchemaField(object):
  19     """Describe a single field within a table schema.
  20 
  21     :type name: str
  22     :param name: the name of the field.
  23 
  24     :type field_type: str
  25     :param field_type: the type of the field (one of 'STRING', 'INTEGER',
  26                        'FLOAT', 'BOOLEAN', 'TIMESTAMP' or 'RECORD').
  27 
  28     :type mode: str
  29     :param mode: the mode of the field (one of 'NULLABLE', 'REQUIRED',
  30                  or 'REPEATED').
  31 
  32     :type description: str
  33     :param description: optional description for the field.
  34 
  35     :type fields: tuple of :class:`SchemaField`
  36     :param fields: subfields (requires ``field_type`` of 'RECORD').
  37     """
  38     def __init__(self, name, field_type, mode='NULLABLE',
  39                  description=None, fields=()):
  40         self._name = name
  41         self._field_type = field_type
  42         self._mode = mode
  43         self._description = description
  44         self._fields = tuple(fields)
  45 
  46     @property
  47     def name(self):
  48         """str: The name of the field."""
  49         return self._name
  50 
  51     @property
  52     def field_type(self):
  53         """str: The type of the field.
  54 
  55         Will be one of 'STRING', 'INTEGER', 'FLOAT', 'BOOLEAN',
  56         'TIMESTAMP' or 'RECORD'.
  57         """
  58         return self._field_type
  59 
  60     @property
  61     def mode(self):
  62         """str: The mode of the field.
  63 
  64         Will be one of 'NULLABLE', 'REQUIRED', or 'REPEATED'.
  65         """
  66         return self._mode
  67 
  68     @property
  69     def is_nullable(self):
  70         """Check whether 'mode' is 'nullable'."""
  71         return self._mode == 'NULLABLE'
  72 
  73     @property
  74     def description(self):
  75         """Optional[str]: Description for the field."""
  76         return self._description
  77 
  78     @property
  79     def fields(self):
  80         """tuple: Subfields contained in this field.
  81 
  82         If ``field_type`` is not 'RECORD', this property must be
  83         empty / unset.
  84         """
  85         return self._fields
  86 
  87     def _key(self):
  88         """A tuple key that unique-ly describes this field.
  89 
  90         Used to compute this instance's hashcode and evaluate equality.
  91 
  92         Returns:
  93             tuple: The contents of this :class:`SchemaField`.
  94         """
  95         return (
  96             self._name,
  97             self._field_type.lower(),
  98             self._mode,
  99             self._description,
  100             self._fields,
  101         )
  102 
  103     def __eq__(self, other):
  104         if not isinstance(other, SchemaField):
  105             return NotImplemented
  106         return self._key() == other._key()
  107 
  108     def __ne__(self, other):
  109         return not self == other
  110 
  111     def __hash__(self):
  112         return hash(self._key())
  113 
  114     def __repr__(self):
  115         return 'SchemaField{}'.format(self._key())
  116
  ```
  --- 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/bigquery/google/cloud/bigquery/schema.py b/bigquery/google/cloud/bigquery/schema.py
  --- a/bigquery/google/cloud/bigquery/schema.py
  +++ b/bigquery/google/cloud/bigquery/schema.py
  @@ -43,6 +43,25 @@
           self._description = description
           self._fields = tuple(fields)
   
  +    @classmethod
  +    def from_api_repr(cls, api_repr):
  +        """Return a ``SchemaField`` object deserialized from a dictionary.
  +
  +        Args:
  +            api_repr (Mapping[str, str]): The serialized representation
  +                of the SchemaField, such as what is output by
  +                :meth:`to_api_repr`.
  +
  +        Returns:
  +            SchemaField: The ``SchemaField`` object.
  +        """
  +        return cls(
  +            field_type=api_repr['type'].upper(),
  +            fields=[cls.from_api_repr(f) for f in api_repr.get('fields', ())],
  +            mode=api_repr['mode'].upper(),
  +            name=api_repr['name'],
  +        )
  +
       @property
       def name(self):
           """str: The name of the field."""
  @@ -84,6 +103,28 @@
           """
           return self._fields
   
  +    def to_api_repr(self):
  +        """Return a dictionary representing this schema field.
  +
  +        Returns:
  +            dict: A dictionary representing the SchemaField in a serialized
  +                form.
  +        """
  +        # Put together the basic representation. See http://bit.ly/2hOAT5u.
  +        answer = {
  +            'mode': self.mode.lower(),
  +            'name': self.name,
  +            'type': self.field_type.lower(),
  +        }
  +
  +        # If this is a RECORD type, then sub-fields are also included,
  +        # add this to the serialized representation.
  +        if self.field_type.upper() == 'RECORD':
  +            answer['fields'] = [f.to_api_repr() for f in self.fields]
  +
  +        # Done; return the serialized dictionary.
  +        return answer
  +
       def _key(self):
           """A tuple key that unique-ly describes this field.
  
verification_info: {"golden_diff": "diff --git a/bigquery/google/cloud/bigquery/schema.py b/bigquery/google/cloud/bigquery/schema.py\n--- a/bigquery/google/cloud/bigquery/schema.py\n+++ b/bigquery/google/cloud/bigquery/schema.py\n@@ -43,6 +43,25 @@\n         self._description = description\n         self._fields = tuple(fields)\n \n+    @classmethod\n+    def from_api_repr(cls, api_repr):\n+        \"\"\"Return a ``SchemaField`` object deserialized from a dictionary.\n+\n+        Args:\n+            api_repr (Mapping[str, str]): The serialized representation\n+                of the SchemaField, such as what is output by\n+                :meth:`to_api_repr`.\n+\n+        Returns:\n+            SchemaField: The ``SchemaField`` object.\n+        \"\"\"\n+        return cls(\n+            field_type=api_repr['type'].upper(),\n+            fields=[cls.from_api_repr(f) for f in api_repr.get('fields', ())],\n+            mode=api_repr['mode'].upper(),\n+            name=api_repr['name'],\n+        )\n+\n     @property\n     def name(self):\n         \"\"\"str: The name of the field.\"\"\"\n@@ -84,6 +103,28 @@\n         \"\"\"\n         return self._fields\n \n+    def to_api_repr(self):\n+        \"\"\"Return a dictionary representing this schema field.\n+\n+        Returns:\n+            dict: A dictionary representing the SchemaField in a serialized\n+                form.\n+        \"\"\"\n+        # Put together the basic representation. See http://bit.ly/2hOAT5u.\n+        answer = {\n+            'mode': self.mode.lower(),\n+            'name': self.name,\n+            'type': self.field_type.lower(),\n+        }\n+\n+        # If this is a RECORD type, then sub-fields are also included,\n+        # add this to the serialized representation.\n+        if self.field_type.upper() == 'RECORD':\n+            answer['fields'] = [f.to_api_repr() for f in self.fields]\n+\n+        # Done; return the serialized dictionary.\n+        return answer\n+\n     def _key(self):\n         \"\"\"A tuple key that unique-ly describes this field.\n", "issue": "BigQuery: expose public helper method to convert a list of schema fields to/from a list of schema dictionaries (JSON)\nI've received some feedback asking how to take a schema from the client library and save it to a JSON file. One reason to do this is the [`bq` command-line tool](https://cloud.google.com/bigquery/bq-command-line-tool#creatingtablefromfile) accepts a schema file, formatted like\r\n\r\n```\r\n[\r\n  {\"name\": \"name\", \"type\": \"string\", \"mode\": \"required\"},\r\n  {\"name\": \"gender\", \"type\": \"string\", \"mode\": \"nullable\"},\r\n  {\"name\": \"count\", \"type\": \"integer\", \"mode\": \"required\"}\r\n]\r\n```\r\n\r\nNote: this format is the same as the API representation.\r\n\r\nIt would be great if our client libraries could read/write in this format.\r\n\r\n\n", "before_files": [{"content": "# Copyright 2015 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\n\"\"\"Schemas for BigQuery tables / queries.\"\"\"\n\n\nclass SchemaField(object):\n    \"\"\"Describe a single field within a table schema.\n\n    :type name: str\n    :param name: the name of the field.\n\n    :type field_type: str\n    :param field_type: the type of the field (one of 'STRING', 'INTEGER',\n                       'FLOAT', 'BOOLEAN', 'TIMESTAMP' or 'RECORD').\n\n    :type mode: str\n    :param mode: the mode of the field (one of 'NULLABLE', 'REQUIRED',\n                 or 'REPEATED').\n\n    :type description: str\n    :param description: optional description for the field.\n\n    :type fields: tuple of :class:`SchemaField`\n    :param fields: subfields (requires ``field_type`` of 'RECORD').\n    \"\"\"\n    def __init__(self, name, field_type, mode='NULLABLE',\n                 description=None, fields=()):\n        self._name = name\n        self._field_type = field_type\n        self._mode = mode\n        self._description = description\n        self._fields = tuple(fields)\n\n    @property\n    def name(self):\n        \"\"\"str: The name of the field.\"\"\"\n        return self._name\n\n    @property\n    def field_type(self):\n        \"\"\"str: The type of the field.\n\n        Will be one of 'STRING', 'INTEGER', 'FLOAT', 'BOOLEAN',\n        'TIMESTAMP' or 'RECORD'.\n        \"\"\"\n        return self._field_type\n\n    @property\n    def mode(self):\n        \"\"\"str: The mode of the field.\n\n        Will be one of 'NULLABLE', 'REQUIRED', or 'REPEATED'.\n        \"\"\"\n        return self._mode\n\n    @property\n    def is_nullable(self):\n        \"\"\"Check whether 'mode' is 'nullable'.\"\"\"\n        return self._mode == 'NULLABLE'\n\n    @property\n    def description(self):\n        \"\"\"Optional[str]: Description for the field.\"\"\"\n        return self._description\n\n    @property\n    def fields(self):\n        \"\"\"tuple: Subfields contained in this field.\n\n        If ``field_type`` is not 'RECORD', this property must be\n        empty / unset.\n        \"\"\"\n        return self._fields\n\n    def _key(self):\n        \"\"\"A tuple key that unique-ly describes this field.\n\n        Used to compute this instance's hashcode and evaluate equality.\n\n        Returns:\n            tuple: The contents of this :class:`SchemaField`.\n        \"\"\"\n        return (\n            self._name,\n            self._field_type.lower(),\n            self._mode,\n            self._description,\n            self._fields,\n        )\n\n    def __eq__(self, other):\n        if not isinstance(other, SchemaField):\n            return NotImplemented\n        return self._key() == other._key()\n\n    def __ne__(self, other):\n        return not self == other\n\n    def __hash__(self):\n        return hash(self._key())\n\n    def __repr__(self):\n        return 'SchemaField{}'.format(self._key())\n", "path": "bigquery/google/cloud/bigquery/schema.py"}], "after_files": [{"content": "# Copyright 2015 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\n\"\"\"Schemas for BigQuery tables / queries.\"\"\"\n\n\nclass SchemaField(object):\n    \"\"\"Describe a single field within a table schema.\n\n    :type name: str\n    :param name: the name of the field.\n\n    :type field_type: str\n    :param field_type: the type of the field (one of 'STRING', 'INTEGER',\n                       'FLOAT', 'BOOLEAN', 'TIMESTAMP' or 'RECORD').\n\n    :type mode: str\n    :param mode: the mode of the field (one of 'NULLABLE', 'REQUIRED',\n                 or 'REPEATED').\n\n    :type description: str\n    :param description: optional description for the field.\n\n    :type fields: tuple of :class:`SchemaField`\n    :param fields: subfields (requires ``field_type`` of 'RECORD').\n    \"\"\"\n    def __init__(self, name, field_type, mode='NULLABLE',\n                 description=None, fields=()):\n        self._name = name\n        self._field_type = field_type\n        self._mode = mode\n        self._description = description\n        self._fields = tuple(fields)\n\n    @classmethod\n    def from_api_repr(cls, api_repr):\n        \"\"\"Return a ``SchemaField`` object deserialized from a dictionary.\n\n        Args:\n            api_repr (Mapping[str, str]): The serialized representation\n                of the SchemaField, such as what is output by\n                :meth:`to_api_repr`.\n\n        Returns:\n            SchemaField: The ``SchemaField`` object.\n        \"\"\"\n        return cls(\n            field_type=api_repr['type'].upper(),\n            fields=[cls.from_api_repr(f) for f in api_repr.get('fields', ())],\n            mode=api_repr['mode'].upper(),\n            name=api_repr['name'],\n        )\n\n    @property\n    def name(self):\n        \"\"\"str: The name of the field.\"\"\"\n        return self._name\n\n    @property\n    def field_type(self):\n        \"\"\"str: The type of the field.\n\n        Will be one of 'STRING', 'INTEGER', 'FLOAT', 'BOOLEAN',\n        'TIMESTAMP' or 'RECORD'.\n        \"\"\"\n        return self._field_type\n\n    @property\n    def mode(self):\n        \"\"\"str: The mode of the field.\n\n        Will be one of 'NULLABLE', 'REQUIRED', or 'REPEATED'.\n        \"\"\"\n        return self._mode\n\n    @property\n    def is_nullable(self):\n        \"\"\"Check whether 'mode' is 'nullable'.\"\"\"\n        return self._mode == 'NULLABLE'\n\n    @property\n    def description(self):\n        \"\"\"Optional[str]: Description for the field.\"\"\"\n        return self._description\n\n    @property\n    def fields(self):\n        \"\"\"tuple: Subfields contained in this field.\n\n        If ``field_type`` is not 'RECORD', this property must be\n        empty / unset.\n        \"\"\"\n        return self._fields\n\n    def to_api_repr(self):\n        \"\"\"Return a dictionary representing this schema field.\n\n        Returns:\n            dict: A dictionary representing the SchemaField in a serialized\n                form.\n        \"\"\"\n        # Put together the basic representation. See http://bit.ly/2hOAT5u.\n        answer = {\n            'mode': self.mode.lower(),\n            'name': self.name,\n            'type': self.field_type.lower(),\n        }\n\n        # If this is a RECORD type, then sub-fields are also included,\n        # add this to the serialized representation.\n        if self.field_type.upper() == 'RECORD':\n            answer['fields'] = [f.to_api_repr() for f in self.fields]\n\n        # Done; return the serialized dictionary.\n        return answer\n\n    def _key(self):\n        \"\"\"A tuple key that unique-ly describes this field.\n\n        Used to compute this instance's hashcode and evaluate equality.\n\n        Returns:\n            tuple: The contents of this :class:`SchemaField`.\n        \"\"\"\n        return (\n            self._name,\n            self._field_type.lower(),\n            self._mode,\n            self._description,\n            self._fields,\n        )\n\n    def __eq__(self, other):\n        if not isinstance(other, SchemaField):\n            return NotImplemented\n        return self._key() == other._key()\n\n    def __ne__(self, other):\n        return not self == other\n\n    def __hash__(self):\n        return hash(self._key())\n\n    def __repr__(self):\n        return 'SchemaField{}'.format(self._key())\n", "path": "bigquery/google/cloud/bigquery/schema.py"}]}