prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Pubsub.list_topics fails when there are no topics
  [Offending line](https://github.com/GoogleCloudPlatform/gcloud-python/blob/0910f9979a45af8cc2826dd4c6ff38d9efa5ccec/gcloud/pubsub/client.py#L80). Reproduce via:
  
  ``` python
  client = pubsub.Client()
  >>> client.list_topics()
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "gcloud/pubsub/client.py", line 80, in list_topics
      for resource in resp['topics']]
  KeyError: 'topics'
  ```
  
  @tseaver ISTM we should locate all instances where we assume a key is present and just protect against this. The time between releases behooves us to be "protective" of users. (I realize that we've usually done it this way based on documented outputs.)
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `gcloud/pubsub/client.py`
  Content:
  ```
  1 # Copyright 2015 Google Inc. All rights reserved.
  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 """Client for interacting with the Google Cloud Pub/Sub API."""
  16 
  17 
  18 from gcloud.client import JSONClient
  19 from gcloud.pubsub.connection import Connection
  20 from gcloud.pubsub.subscription import Subscription
  21 from gcloud.pubsub.topic import Topic
  22 
  23 
  24 class Client(JSONClient):
  25     """Client to bundle configuration needed for API requests.
  26 
  27     :type project: string
  28     :param project: the project which the client acts on behalf of. Will be
  29                     passed when creating a topic.  If not passed,
  30                     falls back to the default inferred from the environment.
  31 
  32     :type credentials: :class:`oauth2client.client.OAuth2Credentials` or
  33                        :class:`NoneType`
  34     :param credentials: The OAuth2 Credentials to use for the connection
  35                         owned by this client. If not passed (and if no ``http``
  36                         object is passed), falls back to the default inferred
  37                         from the environment.
  38 
  39     :type http: :class:`httplib2.Http` or class that defines ``request()``.
  40     :param http: An optional HTTP object to make requests. If not passed, an
  41                  ``http`` object is created that is bound to the
  42                  ``credentials`` for the current object.
  43     """
  44 
  45     _connection_class = Connection
  46 
  47     def list_topics(self, page_size=None, page_token=None):
  48         """List topics for the project associated with this client.
  49 
  50         See:
  51         https://cloud.google.com/pubsub/reference/rest/v1/projects.topics/list
  52 
  53         :type page_size: int
  54         :param page_size: maximum number of topics to return, If not passed,
  55                           defaults to a value set by the API.
  56 
  57         :type page_token: string
  58         :param page_token: opaque marker for the next "page" of topics. If not
  59                            passed, the API will return the first page of
  60                            topics.
  61 
  62         :rtype: tuple, (list, str)
  63         :returns: list of :class:`gcloud.pubsub.topic.Topic`, plus a
  64                   "next page token" string:  if not None, indicates that
  65                   more topics can be retrieved with another call (pass that
  66                   value as ``page_token``).
  67         """
  68         params = {}
  69 
  70         if page_size is not None:
  71             params['pageSize'] = page_size
  72 
  73         if page_token is not None:
  74             params['pageToken'] = page_token
  75 
  76         path = '/projects/%s/topics' % (self.project,)
  77         resp = self.connection.api_request(method='GET', path=path,
  78                                            query_params=params)
  79         topics = [Topic.from_api_repr(resource, self)
  80                   for resource in resp['topics']]
  81         return topics, resp.get('nextPageToken')
  82 
  83     def list_subscriptions(self, page_size=None, page_token=None,
  84                            topic_name=None):
  85         """List subscriptions for the project associated with this client.
  86 
  87         See:
  88         https://cloud.google.com/pubsub/reference/rest/v1/projects.topics/list
  89 
  90         and (where ``topic_name`` is passed):
  91         https://cloud.google.com/pubsub/reference/rest/v1/projects.topics.subscriptions/list
  92 
  93         :type page_size: int
  94         :param page_size: maximum number of topics to return, If not passed,
  95                           defaults to a value set by the API.
  96 
  97         :type page_token: string
  98         :param page_token: opaque marker for the next "page" of topics. If not
  99                            passed, the API will return the first page of
  100                            topics.
  101 
  102         :type topic_name: string
  103         :param topic_name: limit results to subscriptions bound to the given
  104                            topic.
  105 
  106         :rtype: tuple, (list, str)
  107         :returns: list of :class:`gcloud.pubsub.subscription.Subscription`,
  108                   plus a "next page token" string:  if not None, indicates that
  109                   more topics can be retrieved with another call (pass that
  110                   value as ``page_token``).
  111         """
  112         params = {}
  113 
  114         if page_size is not None:
  115             params['pageSize'] = page_size
  116 
  117         if page_token is not None:
  118             params['pageToken'] = page_token
  119 
  120         if topic_name is None:
  121             path = '/projects/%s/subscriptions' % (self.project,)
  122         else:
  123             path = '/projects/%s/topics/%s/subscriptions' % (self.project,
  124                                                              topic_name)
  125 
  126         resp = self.connection.api_request(method='GET', path=path,
  127                                            query_params=params)
  128         topics = {}
  129         subscriptions = [Subscription.from_api_repr(resource, self,
  130                                                     topics=topics)
  131                          for resource in resp['subscriptions']]
  132         return subscriptions, resp.get('nextPageToken')
  133 
  134     def topic(self, name, timestamp_messages=False):
  135         """Creates a topic bound to the current client.
  136 
  137         :type name: string
  138         :param name: the name of the topic to be constructed.
  139 
  140         :type timestamp_messages: boolean
  141         :param timestamp_messages: To be passed to ``Topic`` constructor.
  142 
  143         :rtype: :class:`gcloud.pubsub.topic.Topic`
  144         :returns: Topic created with the current client.
  145         """
  146         return Topic(name, client=self, timestamp_messages=timestamp_messages)
  147
  ```
  --- 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/gcloud/pubsub/client.py b/gcloud/pubsub/client.py
  --- a/gcloud/pubsub/client.py
  +++ b/gcloud/pubsub/client.py
  @@ -77,7 +77,7 @@
           resp = self.connection.api_request(method='GET', path=path,
                                              query_params=params)
           topics = [Topic.from_api_repr(resource, self)
  -                  for resource in resp['topics']]
  +                  for resource in resp.get('topics', ())]
           return topics, resp.get('nextPageToken')
   
       def list_subscriptions(self, page_size=None, page_token=None,
  @@ -128,7 +128,7 @@
           topics = {}
           subscriptions = [Subscription.from_api_repr(resource, self,
                                                       topics=topics)
  -                         for resource in resp['subscriptions']]
  +                         for resource in resp.get('subscriptions', ())]
           return subscriptions, resp.get('nextPageToken')
   
       def topic(self, name, timestamp_messages=False):
  
verification_info: {"golden_diff": "diff --git a/gcloud/pubsub/client.py b/gcloud/pubsub/client.py\n--- a/gcloud/pubsub/client.py\n+++ b/gcloud/pubsub/client.py\n@@ -77,7 +77,7 @@\n         resp = self.connection.api_request(method='GET', path=path,\n                                            query_params=params)\n         topics = [Topic.from_api_repr(resource, self)\n-                  for resource in resp['topics']]\n+                  for resource in resp.get('topics', ())]\n         return topics, resp.get('nextPageToken')\n \n     def list_subscriptions(self, page_size=None, page_token=None,\n@@ -128,7 +128,7 @@\n         topics = {}\n         subscriptions = [Subscription.from_api_repr(resource, self,\n                                                     topics=topics)\n-                         for resource in resp['subscriptions']]\n+                         for resource in resp.get('subscriptions', ())]\n         return subscriptions, resp.get('nextPageToken')\n \n     def topic(self, name, timestamp_messages=False):\n", "issue": "Pubsub.list_topics fails when there are no topics\n[Offending line](https://github.com/GoogleCloudPlatform/gcloud-python/blob/0910f9979a45af8cc2826dd4c6ff38d9efa5ccec/gcloud/pubsub/client.py#L80). Reproduce via:\n\n``` python\nclient = pubsub.Client()\n>>> client.list_topics()\nTraceback (most recent call last):\n  File \"<stdin>\", line 1, in <module>\n  File \"gcloud/pubsub/client.py\", line 80, in list_topics\n    for resource in resp['topics']]\nKeyError: 'topics'\n```\n\n@tseaver ISTM we should locate all instances where we assume a key is present and just protect against this. The time between releases behooves us to be \"protective\" of users. (I realize that we've usually done it this way based on documented outputs.)\n\n", "before_files": [{"content": "# Copyright 2015 Google Inc. All rights reserved.\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\"\"\"Client for interacting with the Google Cloud Pub/Sub API.\"\"\"\n\n\nfrom gcloud.client import JSONClient\nfrom gcloud.pubsub.connection import Connection\nfrom gcloud.pubsub.subscription import Subscription\nfrom gcloud.pubsub.topic import Topic\n\n\nclass Client(JSONClient):\n    \"\"\"Client to bundle configuration needed for API requests.\n\n    :type project: string\n    :param project: the project which the client acts on behalf of. Will be\n                    passed when creating a topic.  If not passed,\n                    falls back to the default inferred from the environment.\n\n    :type credentials: :class:`oauth2client.client.OAuth2Credentials` or\n                       :class:`NoneType`\n    :param credentials: The OAuth2 Credentials to use for the connection\n                        owned by this client. If not passed (and if no ``http``\n                        object is passed), falls back to the default inferred\n                        from the environment.\n\n    :type http: :class:`httplib2.Http` or class that defines ``request()``.\n    :param http: An optional HTTP object to make requests. If not passed, an\n                 ``http`` object is created that is bound to the\n                 ``credentials`` for the current object.\n    \"\"\"\n\n    _connection_class = Connection\n\n    def list_topics(self, page_size=None, page_token=None):\n        \"\"\"List topics for the project associated with this client.\n\n        See:\n        https://cloud.google.com/pubsub/reference/rest/v1/projects.topics/list\n\n        :type page_size: int\n        :param page_size: maximum number of topics to return, If not passed,\n                          defaults to a value set by the API.\n\n        :type page_token: string\n        :param page_token: opaque marker for the next \"page\" of topics. If not\n                           passed, the API will return the first page of\n                           topics.\n\n        :rtype: tuple, (list, str)\n        :returns: list of :class:`gcloud.pubsub.topic.Topic`, plus a\n                  \"next page token\" string:  if not None, indicates that\n                  more topics can be retrieved with another call (pass that\n                  value as ``page_token``).\n        \"\"\"\n        params = {}\n\n        if page_size is not None:\n            params['pageSize'] = page_size\n\n        if page_token is not None:\n            params['pageToken'] = page_token\n\n        path = '/projects/%s/topics' % (self.project,)\n        resp = self.connection.api_request(method='GET', path=path,\n                                           query_params=params)\n        topics = [Topic.from_api_repr(resource, self)\n                  for resource in resp['topics']]\n        return topics, resp.get('nextPageToken')\n\n    def list_subscriptions(self, page_size=None, page_token=None,\n                           topic_name=None):\n        \"\"\"List subscriptions for the project associated with this client.\n\n        See:\n        https://cloud.google.com/pubsub/reference/rest/v1/projects.topics/list\n\n        and (where ``topic_name`` is passed):\n        https://cloud.google.com/pubsub/reference/rest/v1/projects.topics.subscriptions/list\n\n        :type page_size: int\n        :param page_size: maximum number of topics to return, If not passed,\n                          defaults to a value set by the API.\n\n        :type page_token: string\n        :param page_token: opaque marker for the next \"page\" of topics. If not\n                           passed, the API will return the first page of\n                           topics.\n\n        :type topic_name: string\n        :param topic_name: limit results to subscriptions bound to the given\n                           topic.\n\n        :rtype: tuple, (list, str)\n        :returns: list of :class:`gcloud.pubsub.subscription.Subscription`,\n                  plus a \"next page token\" string:  if not None, indicates that\n                  more topics can be retrieved with another call (pass that\n                  value as ``page_token``).\n        \"\"\"\n        params = {}\n\n        if page_size is not None:\n            params['pageSize'] = page_size\n\n        if page_token is not None:\n            params['pageToken'] = page_token\n\n        if topic_name is None:\n            path = '/projects/%s/subscriptions' % (self.project,)\n        else:\n            path = '/projects/%s/topics/%s/subscriptions' % (self.project,\n                                                             topic_name)\n\n        resp = self.connection.api_request(method='GET', path=path,\n                                           query_params=params)\n        topics = {}\n        subscriptions = [Subscription.from_api_repr(resource, self,\n                                                    topics=topics)\n                         for resource in resp['subscriptions']]\n        return subscriptions, resp.get('nextPageToken')\n\n    def topic(self, name, timestamp_messages=False):\n        \"\"\"Creates a topic bound to the current client.\n\n        :type name: string\n        :param name: the name of the topic to be constructed.\n\n        :type timestamp_messages: boolean\n        :param timestamp_messages: To be passed to ``Topic`` constructor.\n\n        :rtype: :class:`gcloud.pubsub.topic.Topic`\n        :returns: Topic created with the current client.\n        \"\"\"\n        return Topic(name, client=self, timestamp_messages=timestamp_messages)\n", "path": "gcloud/pubsub/client.py"}], "after_files": [{"content": "# Copyright 2015 Google Inc. All rights reserved.\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\"\"\"Client for interacting with the Google Cloud Pub/Sub API.\"\"\"\n\n\nfrom gcloud.client import JSONClient\nfrom gcloud.pubsub.connection import Connection\nfrom gcloud.pubsub.subscription import Subscription\nfrom gcloud.pubsub.topic import Topic\n\n\nclass Client(JSONClient):\n    \"\"\"Client to bundle configuration needed for API requests.\n\n    :type project: string\n    :param project: the project which the client acts on behalf of. Will be\n                    passed when creating a topic.  If not passed,\n                    falls back to the default inferred from the environment.\n\n    :type credentials: :class:`oauth2client.client.OAuth2Credentials` or\n                       :class:`NoneType`\n    :param credentials: The OAuth2 Credentials to use for the connection\n                        owned by this client. If not passed (and if no ``http``\n                        object is passed), falls back to the default inferred\n                        from the environment.\n\n    :type http: :class:`httplib2.Http` or class that defines ``request()``.\n    :param http: An optional HTTP object to make requests. If not passed, an\n                 ``http`` object is created that is bound to the\n                 ``credentials`` for the current object.\n    \"\"\"\n\n    _connection_class = Connection\n\n    def list_topics(self, page_size=None, page_token=None):\n        \"\"\"List topics for the project associated with this client.\n\n        See:\n        https://cloud.google.com/pubsub/reference/rest/v1/projects.topics/list\n\n        :type page_size: int\n        :param page_size: maximum number of topics to return, If not passed,\n                          defaults to a value set by the API.\n\n        :type page_token: string\n        :param page_token: opaque marker for the next \"page\" of topics. If not\n                           passed, the API will return the first page of\n                           topics.\n\n        :rtype: tuple, (list, str)\n        :returns: list of :class:`gcloud.pubsub.topic.Topic`, plus a\n                  \"next page token\" string:  if not None, indicates that\n                  more topics can be retrieved with another call (pass that\n                  value as ``page_token``).\n        \"\"\"\n        params = {}\n\n        if page_size is not None:\n            params['pageSize'] = page_size\n\n        if page_token is not None:\n            params['pageToken'] = page_token\n\n        path = '/projects/%s/topics' % (self.project,)\n        resp = self.connection.api_request(method='GET', path=path,\n                                           query_params=params)\n        topics = [Topic.from_api_repr(resource, self)\n                  for resource in resp.get('topics', ())]\n        return topics, resp.get('nextPageToken')\n\n    def list_subscriptions(self, page_size=None, page_token=None,\n                           topic_name=None):\n        \"\"\"List subscriptions for the project associated with this client.\n\n        See:\n        https://cloud.google.com/pubsub/reference/rest/v1/projects.topics/list\n\n        and (where ``topic_name`` is passed):\n        https://cloud.google.com/pubsub/reference/rest/v1/projects.topics.subscriptions/list\n\n        :type page_size: int\n        :param page_size: maximum number of topics to return, If not passed,\n                          defaults to a value set by the API.\n\n        :type page_token: string\n        :param page_token: opaque marker for the next \"page\" of topics. If not\n                           passed, the API will return the first page of\n                           topics.\n\n        :type topic_name: string\n        :param topic_name: limit results to subscriptions bound to the given\n                           topic.\n\n        :rtype: tuple, (list, str)\n        :returns: list of :class:`gcloud.pubsub.subscription.Subscription`,\n                  plus a \"next page token\" string:  if not None, indicates that\n                  more topics can be retrieved with another call (pass that\n                  value as ``page_token``).\n        \"\"\"\n        params = {}\n\n        if page_size is not None:\n            params['pageSize'] = page_size\n\n        if page_token is not None:\n            params['pageToken'] = page_token\n\n        if topic_name is None:\n            path = '/projects/%s/subscriptions' % (self.project,)\n        else:\n            path = '/projects/%s/topics/%s/subscriptions' % (self.project,\n                                                             topic_name)\n\n        resp = self.connection.api_request(method='GET', path=path,\n                                           query_params=params)\n        topics = {}\n        subscriptions = [Subscription.from_api_repr(resource, self,\n                                                    topics=topics)\n                         for resource in resp.get('subscriptions', ())]\n        return subscriptions, resp.get('nextPageToken')\n\n    def topic(self, name, timestamp_messages=False):\n        \"\"\"Creates a topic bound to the current client.\n\n        :type name: string\n        :param name: the name of the topic to be constructed.\n\n        :type timestamp_messages: boolean\n        :param timestamp_messages: To be passed to ``Topic`` constructor.\n\n        :rtype: :class:`gcloud.pubsub.topic.Topic`\n        :returns: Topic created with the current client.\n        \"\"\"\n        return Topic(name, client=self, timestamp_messages=timestamp_messages)\n", "path": "gcloud/pubsub/client.py"}]}