prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  pubsub fails if data key is not present
  If a message is published with a string of 0 length (`topic.publish( '', url=url, title=title)`) when the message is received there is no data field in the message and a key error is thrown when trying to transform the message from the PubSub API representation.
  
  https://github.com/GoogleCloudPlatform/gcloud-python/blob/master/gcloud/pubsub/message.py#L74
  
  ```
  Traceback (most recent call last):
  File "/en_notifications/en_notifications.py", line 51, in <module>
  received = PS_SUBSCRIPTION.pull(max_messages=PULL_COUNT)
  File "/usr/local/lib/python2.7/dist-packages/gcloud/pubsub/subscription.py", line 212, in pull
  File "/usr/local/lib/python2.7/dist-packages/gcloud/pubsub/message.py", line 74, in from_api_repr
  for info in response.get('receivedMessages', ())]
  data = base64.b64decode(api_repr['data'])
  KeyError: 'data'
  ```
  
  
  --- 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/message.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 """Define API Topics."""
  16 
  17 import base64
  18 
  19 from gcloud._helpers import _rfc3339_to_datetime
  20 
  21 
  22 class Message(object):
  23     """Messages can be published to a topic and received by subscribers.
  24 
  25     See:
  26     https://cloud.google.com/pubsub/reference/rest/v1/PubsubMessage
  27 
  28     :type data: bytes
  29     :param data: the payload of the message
  30 
  31     :type message_id: string
  32     :param message_id: An ID assigned to the message by the API.
  33 
  34     :type attributes: dict or None
  35     :param attributes: Extra metadata associated by the publisher with the
  36                        message.
  37     """
  38     def __init__(self, data, message_id, attributes=None):
  39         self.data = data
  40         self.message_id = message_id
  41         self._attributes = attributes
  42 
  43     @property
  44     def attributes(self):
  45         """Lazily-constructed attribute dictionary"""
  46         if self._attributes is None:
  47             self._attributes = {}
  48         return self._attributes
  49 
  50     @property
  51     def timestamp(self):
  52         """Return sortable timestamp from attributes, if passed.
  53 
  54         Allows sorting messages in publication order (assuming consistent
  55         clocks across all publishers).
  56 
  57         :rtype: :class:`datetime.datetime`
  58         :returns: timestamp (in UTC timezone) parsed from RFC 3339 timestamp
  59         :raises: ValueError if timestamp not in ``attributes``, or if it does
  60                  not match the RFC 3339 format.
  61         """
  62         stamp = self.attributes.get('timestamp')
  63         if stamp is None:
  64             raise ValueError('No timestamp')
  65         return _rfc3339_to_datetime(stamp)
  66 
  67     @classmethod
  68     def from_api_repr(cls, api_repr):
  69         """Factory:  construct message from API representation.
  70 
  71         :type api_repr: dict or None
  72         :param api_repr: The API representation of the message
  73         """
  74         data = base64.b64decode(api_repr['data'])
  75         return cls(data=data, message_id=api_repr['messageId'],
  76                    attributes=api_repr.get('attributes'))
  77
  ```
  --- 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/message.py b/gcloud/pubsub/message.py
  --- a/gcloud/pubsub/message.py
  +++ b/gcloud/pubsub/message.py
  @@ -71,6 +71,6 @@
           :type api_repr: dict or None
           :param api_repr: The API representation of the message
           """
  -        data = base64.b64decode(api_repr['data'])
  +        data = base64.b64decode(api_repr.get('data', b''))
           return cls(data=data, message_id=api_repr['messageId'],
                      attributes=api_repr.get('attributes'))
  
verification_info: {"golden_diff": "diff --git a/gcloud/pubsub/message.py b/gcloud/pubsub/message.py\n--- a/gcloud/pubsub/message.py\n+++ b/gcloud/pubsub/message.py\n@@ -71,6 +71,6 @@\n         :type api_repr: dict or None\n         :param api_repr: The API representation of the message\n         \"\"\"\n-        data = base64.b64decode(api_repr['data'])\n+        data = base64.b64decode(api_repr.get('data', b''))\n         return cls(data=data, message_id=api_repr['messageId'],\n                    attributes=api_repr.get('attributes'))\n", "issue": "pubsub fails if data key is not present\nIf a message is published with a string of 0 length (`topic.publish( '', url=url, title=title)`) when the message is received there is no data field in the message and a key error is thrown when trying to transform the message from the PubSub API representation.\n\nhttps://github.com/GoogleCloudPlatform/gcloud-python/blob/master/gcloud/pubsub/message.py#L74\n\n```\nTraceback (most recent call last):\nFile \"/en_notifications/en_notifications.py\", line 51, in <module>\nreceived = PS_SUBSCRIPTION.pull(max_messages=PULL_COUNT)\nFile \"/usr/local/lib/python2.7/dist-packages/gcloud/pubsub/subscription.py\", line 212, in pull\nFile \"/usr/local/lib/python2.7/dist-packages/gcloud/pubsub/message.py\", line 74, in from_api_repr\nfor info in response.get('receivedMessages', ())]\ndata = base64.b64decode(api_repr['data'])\nKeyError: 'data'\n```\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\"\"\"Define API Topics.\"\"\"\n\nimport base64\n\nfrom gcloud._helpers import _rfc3339_to_datetime\n\n\nclass Message(object):\n    \"\"\"Messages can be published to a topic and received by subscribers.\n\n    See:\n    https://cloud.google.com/pubsub/reference/rest/v1/PubsubMessage\n\n    :type data: bytes\n    :param data: the payload of the message\n\n    :type message_id: string\n    :param message_id: An ID assigned to the message by the API.\n\n    :type attributes: dict or None\n    :param attributes: Extra metadata associated by the publisher with the\n                       message.\n    \"\"\"\n    def __init__(self, data, message_id, attributes=None):\n        self.data = data\n        self.message_id = message_id\n        self._attributes = attributes\n\n    @property\n    def attributes(self):\n        \"\"\"Lazily-constructed attribute dictionary\"\"\"\n        if self._attributes is None:\n            self._attributes = {}\n        return self._attributes\n\n    @property\n    def timestamp(self):\n        \"\"\"Return sortable timestamp from attributes, if passed.\n\n        Allows sorting messages in publication order (assuming consistent\n        clocks across all publishers).\n\n        :rtype: :class:`datetime.datetime`\n        :returns: timestamp (in UTC timezone) parsed from RFC 3339 timestamp\n        :raises: ValueError if timestamp not in ``attributes``, or if it does\n                 not match the RFC 3339 format.\n        \"\"\"\n        stamp = self.attributes.get('timestamp')\n        if stamp is None:\n            raise ValueError('No timestamp')\n        return _rfc3339_to_datetime(stamp)\n\n    @classmethod\n    def from_api_repr(cls, api_repr):\n        \"\"\"Factory:  construct message from API representation.\n\n        :type api_repr: dict or None\n        :param api_repr: The API representation of the message\n        \"\"\"\n        data = base64.b64decode(api_repr['data'])\n        return cls(data=data, message_id=api_repr['messageId'],\n                   attributes=api_repr.get('attributes'))\n", "path": "gcloud/pubsub/message.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\"\"\"Define API Topics.\"\"\"\n\nimport base64\n\nfrom gcloud._helpers import _rfc3339_to_datetime\n\n\nclass Message(object):\n    \"\"\"Messages can be published to a topic and received by subscribers.\n\n    See:\n    https://cloud.google.com/pubsub/reference/rest/v1/PubsubMessage\n\n    :type data: bytes\n    :param data: the payload of the message\n\n    :type message_id: string\n    :param message_id: An ID assigned to the message by the API.\n\n    :type attributes: dict or None\n    :param attributes: Extra metadata associated by the publisher with the\n                       message.\n    \"\"\"\n    def __init__(self, data, message_id, attributes=None):\n        self.data = data\n        self.message_id = message_id\n        self._attributes = attributes\n\n    @property\n    def attributes(self):\n        \"\"\"Lazily-constructed attribute dictionary\"\"\"\n        if self._attributes is None:\n            self._attributes = {}\n        return self._attributes\n\n    @property\n    def timestamp(self):\n        \"\"\"Return sortable timestamp from attributes, if passed.\n\n        Allows sorting messages in publication order (assuming consistent\n        clocks across all publishers).\n\n        :rtype: :class:`datetime.datetime`\n        :returns: timestamp (in UTC timezone) parsed from RFC 3339 timestamp\n        :raises: ValueError if timestamp not in ``attributes``, or if it does\n                 not match the RFC 3339 format.\n        \"\"\"\n        stamp = self.attributes.get('timestamp')\n        if stamp is None:\n            raise ValueError('No timestamp')\n        return _rfc3339_to_datetime(stamp)\n\n    @classmethod\n    def from_api_repr(cls, api_repr):\n        \"\"\"Factory:  construct message from API representation.\n\n        :type api_repr: dict or None\n        :param api_repr: The API representation of the message\n        \"\"\"\n        data = base64.b64decode(api_repr.get('data', b''))\n        return cls(data=data, message_id=api_repr['messageId'],\n                   attributes=api_repr.get('attributes'))\n", "path": "gcloud/pubsub/message.py"}]}