We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
googleapiclient/channel.py has no license header
There is no license header at all in channel.py

googleapiclient/channel.py has no license header
There is no license header at all in channel.py


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `googleapiclient/channel.py`
Content:
```
1 """Channel notifications support.
2 
3 Classes and functions to support channel subscriptions and notifications
4 on those channels.
5 
6 Notes:
7   - This code is based on experimental APIs and is subject to change.
8   - Notification does not do deduplication of notification ids, that's up to
9     the receiver.
10   - Storing the Channel between calls is up to the caller.
11 
12 
13 Example setting up a channel:
14 
15   # Create a new channel that gets notifications via webhook.
16   channel = new_webhook_channel("https://example.com/my_web_hook")
17 
18   # Store the channel, keyed by 'channel.id'. Store it before calling the
19   # watch method because notifications may start arriving before the watch
20   # method returns.
21   ...
22 
23   resp = service.objects().watchAll(
24     bucket="some_bucket_id", body=channel.body()).execute()
25   channel.update(resp)
26 
27   # Store the channel, keyed by 'channel.id'. Store it after being updated
28   # since the resource_id value will now be correct, and that's needed to
29   # stop a subscription.
30   ...
31 
32 
33 An example Webhook implementation using webapp2. Note that webapp2 puts
34 headers in a case insensitive dictionary, as headers aren't guaranteed to
35 always be upper case.
36 
37   id = self.request.headers[X_GOOG_CHANNEL_ID]
38 
39   # Retrieve the channel by id.
40   channel = ...
41 
42   # Parse notification from the headers, including validating the id.
43   n = notification_from_headers(channel, self.request.headers)
44 
45   # Do app specific stuff with the notification here.
46   if n.resource_state == 'sync':
47     # Code to handle sync state.
48   elif n.resource_state == 'exists':
49     # Code to handle the exists state.
50   elif n.resource_state == 'not_exists':
51     # Code to handle the not exists state.
52 
53 
54 Example of unsubscribing.
55 
56   service.channels().stop(channel.body())
57 """
58 from __future__ import absolute_import
59 
60 import datetime
61 import uuid
62 
63 from googleapiclient import errors
64 from googleapiclient import _helpers as util
65 import six
66 
67 
68 # The unix time epoch starts at midnight 1970.
69 EPOCH = datetime.datetime.utcfromtimestamp(0)
70 
71 # Map the names of the parameters in the JSON channel description to
72 # the parameter names we use in the Channel class.
73 CHANNEL_PARAMS = {
74     'address': 'address',
75     'id': 'id',
76     'expiration': 'expiration',
77     'params': 'params',
78     'resourceId': 'resource_id',
79     'resourceUri': 'resource_uri',
80     'type': 'type',
81     'token': 'token',
82     }
83 
84 X_GOOG_CHANNEL_ID     = 'X-GOOG-CHANNEL-ID'
85 X_GOOG_MESSAGE_NUMBER = 'X-GOOG-MESSAGE-NUMBER'
86 X_GOOG_RESOURCE_STATE = 'X-GOOG-RESOURCE-STATE'
87 X_GOOG_RESOURCE_URI   = 'X-GOOG-RESOURCE-URI'
88 X_GOOG_RESOURCE_ID    = 'X-GOOG-RESOURCE-ID'
89 
90 
91 def _upper_header_keys(headers):
92   new_headers = {}
93   for k, v in six.iteritems(headers):
94     new_headers[k.upper()] = v
95   return new_headers
96 
97 
98 class Notification(object):
99   """A Notification from a Channel.
100 
101   Notifications are not usually constructed directly, but are returned
102   from functions like notification_from_headers().
103 
104   Attributes:
105     message_number: int, The unique id number of this notification.
106     state: str, The state of the resource being monitored.
107     uri: str, The address of the resource being monitored.
108     resource_id: str, The unique identifier of the version of the resource at
109       this event.
110   """
111   @util.positional(5)
112   def __init__(self, message_number, state, resource_uri, resource_id):
113     """Notification constructor.
114 
115     Args:
116       message_number: int, The unique id number of this notification.
117       state: str, The state of the resource being monitored. Can be one
118         of "exists", "not_exists", or "sync".
119       resource_uri: str, The address of the resource being monitored.
120       resource_id: str, The identifier of the watched resource.
121     """
122     self.message_number = message_number
123     self.state = state
124     self.resource_uri = resource_uri
125     self.resource_id = resource_id
126 
127 
128 class Channel(object):
129   """A Channel for notifications.
130 
131   Usually not constructed directly, instead it is returned from helper
132   functions like new_webhook_channel().
133 
134   Attributes:
135     type: str, The type of delivery mechanism used by this channel. For
136       example, 'web_hook'.
137     id: str, A UUID for the channel.
138     token: str, An arbitrary string associated with the channel that
139       is delivered to the target address with each event delivered
140       over this channel.
141     address: str, The address of the receiving entity where events are
142       delivered. Specific to the channel type.
143     expiration: int, The time, in milliseconds from the epoch, when this
144       channel will expire.
145     params: dict, A dictionary of string to string, with additional parameters
146       controlling delivery channel behavior.
147     resource_id: str, An opaque id that identifies the resource that is
148       being watched. Stable across different API versions.
149     resource_uri: str, The canonicalized ID of the watched resource.
150   """
151 
152   @util.positional(5)
153   def __init__(self, type, id, token, address, expiration=None,
154                params=None, resource_id="", resource_uri=""):
155     """Create a new Channel.
156 
157     In user code, this Channel constructor will not typically be called
158     manually since there are functions for creating channels for each specific
159     type with a more customized set of arguments to pass.
160 
161     Args:
162       type: str, The type of delivery mechanism used by this channel. For
163         example, 'web_hook'.
164       id: str, A UUID for the channel.
165       token: str, An arbitrary string associated with the channel that
166         is delivered to the target address with each event delivered
167         over this channel.
168       address: str,  The address of the receiving entity where events are
169         delivered. Specific to the channel type.
170       expiration: int, The time, in milliseconds from the epoch, when this
171         channel will expire.
172       params: dict, A dictionary of string to string, with additional parameters
173         controlling delivery channel behavior.
174       resource_id: str, An opaque id that identifies the resource that is
175         being watched. Stable across different API versions.
176       resource_uri: str, The canonicalized ID of the watched resource.
177     """
178     self.type = type
179     self.id = id
180     self.token = token
181     self.address = address
182     self.expiration = expiration
183     self.params = params
184     self.resource_id = resource_id
185     self.resource_uri = resource_uri
186 
187   def body(self):
188     """Build a body from the Channel.
189 
190     Constructs a dictionary that's appropriate for passing into watch()
191     methods as the value of body argument.
192 
193     Returns:
194       A dictionary representation of the channel.
195     """
196     result = {
197         'id': self.id,
198         'token': self.token,
199         'type': self.type,
200         'address': self.address
201         }
202     if self.params:
203       result['params'] = self.params
204     if self.resource_id:
205       result['resourceId'] = self.resource_id
206     if self.resource_uri:
207       result['resourceUri'] = self.resource_uri
208     if self.expiration:
209       result['expiration'] = self.expiration
210 
211     return result
212 
213   def update(self, resp):
214     """Update a channel with information from the response of watch().
215 
216     When a request is sent to watch() a resource, the response returned
217     from the watch() request is a dictionary with updated channel information,
218     such as the resource_id, which is needed when stopping a subscription.
219 
220     Args:
221       resp: dict, The response from a watch() method.
222     """
223     for json_name, param_name in six.iteritems(CHANNEL_PARAMS):
224       value = resp.get(json_name)
225       if value is not None:
226         setattr(self, param_name, value)
227 
228 
229 def notification_from_headers(channel, headers):
230   """Parse a notification from the webhook request headers, validate
231     the notification, and return a Notification object.
232 
233   Args:
234     channel: Channel, The channel that the notification is associated with.
235     headers: dict, A dictionary like object that contains the request headers
236       from the webhook HTTP request.
237 
238   Returns:
239     A Notification object.
240 
241   Raises:
242     errors.InvalidNotificationError if the notification is invalid.
243     ValueError if the X-GOOG-MESSAGE-NUMBER can't be converted to an int.
244   """
245   headers = _upper_header_keys(headers)
246   channel_id = headers[X_GOOG_CHANNEL_ID]
247   if channel.id != channel_id:
248     raise errors.InvalidNotificationError(
249         'Channel id mismatch: %s != %s' % (channel.id, channel_id))
250   else:
251     message_number = int(headers[X_GOOG_MESSAGE_NUMBER])
252     state = headers[X_GOOG_RESOURCE_STATE]
253     resource_uri = headers[X_GOOG_RESOURCE_URI]
254     resource_id = headers[X_GOOG_RESOURCE_ID]
255     return Notification(message_number, state, resource_uri, resource_id)
256 
257 
258 @util.positional(2)
259 def new_webhook_channel(url, token=None, expiration=None, params=None):
260     """Create a new webhook Channel.
261 
262     Args:
263       url: str, URL to post notifications to.
264       token: str, An arbitrary string associated with the channel that
265         is delivered to the target address with each notification delivered
266         over this channel.
267       expiration: datetime.datetime, A time in the future when the channel
268         should expire. Can also be None if the subscription should use the
269         default expiration. Note that different services may have different
270         limits on how long a subscription lasts. Check the response from the
271         watch() method to see the value the service has set for an expiration
272         time.
273       params: dict, Extra parameters to pass on channel creation. Currently
274         not used for webhook channels.
275     """
276     expiration_ms = 0
277     if expiration:
278       delta = expiration - EPOCH
279       expiration_ms = delta.microseconds/1000 + (
280           delta.seconds + delta.days*24*3600)*1000
281       if expiration_ms < 0:
282         expiration_ms = 0
283 
284     return Channel('web_hook', str(uuid.uuid4()),
285                    token, url, expiration=expiration_ms,
286                    params=params)
287 
288
```
--- 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/googleapiclient/channel.py b/googleapiclient/channel.py
--- a/googleapiclient/channel.py
+++ b/googleapiclient/channel.py
@@ -1,3 +1,17 @@
+# Copyright 2014 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
 """Channel notifications support.
 
 Classes and functions to support channel subscriptions and notifications

{"golden_diff": "diff --git a/googleapiclient/channel.py b/googleapiclient/channel.py\n--- a/googleapiclient/channel.py\n+++ b/googleapiclient/channel.py\n@@ -1,3 +1,17 @@\n+# Copyright 2014 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 \"\"\"Channel notifications support.\n \n Classes and functions to support channel subscriptions and notifications\n", "issue": "googleapiclient/channel.py has no license header\nThere is no license header at all in channel.py\n\ngoogleapiclient/channel.py has no license header\nThere is no license header at all in channel.py\n\n", "before_files": [{"content": "\"\"\"Channel notifications support.\n\nClasses and functions to support channel subscriptions and notifications\non those channels.\n\nNotes:\n  - This code is based on experimental APIs and is subject to change.\n  - Notification does not do deduplication of notification ids, that's up to\n    the receiver.\n  - Storing the Channel between calls is up to the caller.\n\n\nExample setting up a channel:\n\n  # Create a new channel that gets notifications via webhook.\n  channel = new_webhook_channel(\"https://example.com/my_web_hook\")\n\n  # Store the channel, keyed by 'channel.id'. Store it before calling the\n  # watch method because notifications may start arriving before the watch\n  # method returns.\n  ...\n\n  resp = service.objects().watchAll(\n    bucket=\"some_bucket_id\", body=channel.body()).execute()\n  channel.update(resp)\n\n  # Store the channel, keyed by 'channel.id'. Store it after being updated\n  # since the resource_id value will now be correct, and that's needed to\n  # stop a subscription.\n  ...\n\n\nAn example Webhook implementation using webapp2. Note that webapp2 puts\nheaders in a case insensitive dictionary, as headers aren't guaranteed to\nalways be upper case.\n\n  id = self.request.headers[X_GOOG_CHANNEL_ID]\n\n  # Retrieve the channel by id.\n  channel = ...\n\n  # Parse notification from the headers, including validating the id.\n  n = notification_from_headers(channel, self.request.headers)\n\n  # Do app specific stuff with the notification here.\n  if n.resource_state == 'sync':\n    # Code to handle sync state.\n  elif n.resource_state == 'exists':\n    # Code to handle the exists state.\n  elif n.resource_state == 'not_exists':\n    # Code to handle the not exists state.\n\n\nExample of unsubscribing.\n\n  service.channels().stop(channel.body())\n\"\"\"\nfrom __future__ import absolute_import\n\nimport datetime\nimport uuid\n\nfrom googleapiclient import errors\nfrom googleapiclient import _helpers as util\nimport six\n\n\n# The unix time epoch starts at midnight 1970.\nEPOCH = datetime.datetime.utcfromtimestamp(0)\n\n# Map the names of the parameters in the JSON channel description to\n# the parameter names we use in the Channel class.\nCHANNEL_PARAMS = {\n    'address': 'address',\n    'id': 'id',\n    'expiration': 'expiration',\n    'params': 'params',\n    'resourceId': 'resource_id',\n    'resourceUri': 'resource_uri',\n    'type': 'type',\n    'token': 'token',\n    }\n\nX_GOOG_CHANNEL_ID     = 'X-GOOG-CHANNEL-ID'\nX_GOOG_MESSAGE_NUMBER = 'X-GOOG-MESSAGE-NUMBER'\nX_GOOG_RESOURCE_STATE = 'X-GOOG-RESOURCE-STATE'\nX_GOOG_RESOURCE_URI   = 'X-GOOG-RESOURCE-URI'\nX_GOOG_RESOURCE_ID    = 'X-GOOG-RESOURCE-ID'\n\n\ndef _upper_header_keys(headers):\n  new_headers = {}\n  for k, v in six.iteritems(headers):\n    new_headers[k.upper()] = v\n  return new_headers\n\n\nclass Notification(object):\n  \"\"\"A Notification from a Channel.\n\n  Notifications are not usually constructed directly, but are returned\n  from functions like notification_from_headers().\n\n  Attributes:\n    message_number: int, The unique id number of this notification.\n    state: str, The state of the resource being monitored.\n    uri: str, The address of the resource being monitored.\n    resource_id: str, The unique identifier of the version of the resource at\n      this event.\n  \"\"\"\n  @util.positional(5)\n  def __init__(self, message_number, state, resource_uri, resource_id):\n    \"\"\"Notification constructor.\n\n    Args:\n      message_number: int, The unique id number of this notification.\n      state: str, The state of the resource being monitored. Can be one\n        of \"exists\", \"not_exists\", or \"sync\".\n      resource_uri: str, The address of the resource being monitored.\n      resource_id: str, The identifier of the watched resource.\n    \"\"\"\n    self.message_number = message_number\n    self.state = state\n    self.resource_uri = resource_uri\n    self.resource_id = resource_id\n\n\nclass Channel(object):\n  \"\"\"A Channel for notifications.\n\n  Usually not constructed directly, instead it is returned from helper\n  functions like new_webhook_channel().\n\n  Attributes:\n    type: str, The type of delivery mechanism used by this channel. For\n      example, 'web_hook'.\n    id: str, A UUID for the channel.\n    token: str, An arbitrary string associated with the channel that\n      is delivered to the target address with each event delivered\n      over this channel.\n    address: str, The address of the receiving entity where events are\n      delivered. Specific to the channel type.\n    expiration: int, The time, in milliseconds from the epoch, when this\n      channel will expire.\n    params: dict, A dictionary of string to string, with additional parameters\n      controlling delivery channel behavior.\n    resource_id: str, An opaque id that identifies the resource that is\n      being watched. Stable across different API versions.\n    resource_uri: str, The canonicalized ID of the watched resource.\n  \"\"\"\n\n  @util.positional(5)\n  def __init__(self, type, id, token, address, expiration=None,\n               params=None, resource_id=\"\", resource_uri=\"\"):\n    \"\"\"Create a new Channel.\n\n    In user code, this Channel constructor will not typically be called\n    manually since there are functions for creating channels for each specific\n    type with a more customized set of arguments to pass.\n\n    Args:\n      type: str, The type of delivery mechanism used by this channel. For\n        example, 'web_hook'.\n      id: str, A UUID for the channel.\n      token: str, An arbitrary string associated with the channel that\n        is delivered to the target address with each event delivered\n        over this channel.\n      address: str,  The address of the receiving entity where events are\n        delivered. Specific to the channel type.\n      expiration: int, The time, in milliseconds from the epoch, when this\n        channel will expire.\n      params: dict, A dictionary of string to string, with additional parameters\n        controlling delivery channel behavior.\n      resource_id: str, An opaque id that identifies the resource that is\n        being watched. Stable across different API versions.\n      resource_uri: str, The canonicalized ID of the watched resource.\n    \"\"\"\n    self.type = type\n    self.id = id\n    self.token = token\n    self.address = address\n    self.expiration = expiration\n    self.params = params\n    self.resource_id = resource_id\n    self.resource_uri = resource_uri\n\n  def body(self):\n    \"\"\"Build a body from the Channel.\n\n    Constructs a dictionary that's appropriate for passing into watch()\n    methods as the value of body argument.\n\n    Returns:\n      A dictionary representation of the channel.\n    \"\"\"\n    result = {\n        'id': self.id,\n        'token': self.token,\n        'type': self.type,\n        'address': self.address\n        }\n    if self.params:\n      result['params'] = self.params\n    if self.resource_id:\n      result['resourceId'] = self.resource_id\n    if self.resource_uri:\n      result['resourceUri'] = self.resource_uri\n    if self.expiration:\n      result['expiration'] = self.expiration\n\n    return result\n\n  def update(self, resp):\n    \"\"\"Update a channel with information from the response of watch().\n\n    When a request is sent to watch() a resource, the response returned\n    from the watch() request is a dictionary with updated channel information,\n    such as the resource_id, which is needed when stopping a subscription.\n\n    Args:\n      resp: dict, The response from a watch() method.\n    \"\"\"\n    for json_name, param_name in six.iteritems(CHANNEL_PARAMS):\n      value = resp.get(json_name)\n      if value is not None:\n        setattr(self, param_name, value)\n\n\ndef notification_from_headers(channel, headers):\n  \"\"\"Parse a notification from the webhook request headers, validate\n    the notification, and return a Notification object.\n\n  Args:\n    channel: Channel, The channel that the notification is associated with.\n    headers: dict, A dictionary like object that contains the request headers\n      from the webhook HTTP request.\n\n  Returns:\n    A Notification object.\n\n  Raises:\n    errors.InvalidNotificationError if the notification is invalid.\n    ValueError if the X-GOOG-MESSAGE-NUMBER can't be converted to an int.\n  \"\"\"\n  headers = _upper_header_keys(headers)\n  channel_id = headers[X_GOOG_CHANNEL_ID]\n  if channel.id != channel_id:\n    raise errors.InvalidNotificationError(\n        'Channel id mismatch: %s != %s' % (channel.id, channel_id))\n  else:\n    message_number = int(headers[X_GOOG_MESSAGE_NUMBER])\n    state = headers[X_GOOG_RESOURCE_STATE]\n    resource_uri = headers[X_GOOG_RESOURCE_URI]\n    resource_id = headers[X_GOOG_RESOURCE_ID]\n    return Notification(message_number, state, resource_uri, resource_id)\n\n\n@util.positional(2)\ndef new_webhook_channel(url, token=None, expiration=None, params=None):\n    \"\"\"Create a new webhook Channel.\n\n    Args:\n      url: str, URL to post notifications to.\n      token: str, An arbitrary string associated with the channel that\n        is delivered to the target address with each notification delivered\n        over this channel.\n      expiration: datetime.datetime, A time in the future when the channel\n        should expire. Can also be None if the subscription should use the\n        default expiration. Note that different services may have different\n        limits on how long a subscription lasts. Check the response from the\n        watch() method to see the value the service has set for an expiration\n        time.\n      params: dict, Extra parameters to pass on channel creation. Currently\n        not used for webhook channels.\n    \"\"\"\n    expiration_ms = 0\n    if expiration:\n      delta = expiration - EPOCH\n      expiration_ms = delta.microseconds/1000 + (\n          delta.seconds + delta.days*24*3600)*1000\n      if expiration_ms < 0:\n        expiration_ms = 0\n\n    return Channel('web_hook', str(uuid.uuid4()),\n                   token, url, expiration=expiration_ms,\n                   params=params)\n\n", "path": "googleapiclient/channel.py"}], "after_files": [{"content": "# Copyright 2014 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\"\"\"Channel notifications support.\n\nClasses and functions to support channel subscriptions and notifications\non those channels.\n\nNotes:\n  - This code is based on experimental APIs and is subject to change.\n  - Notification does not do deduplication of notification ids, that's up to\n    the receiver.\n  - Storing the Channel between calls is up to the caller.\n\n\nExample setting up a channel:\n\n  # Create a new channel that gets notifications via webhook.\n  channel = new_webhook_channel(\"https://example.com/my_web_hook\")\n\n  # Store the channel, keyed by 'channel.id'. Store it before calling the\n  # watch method because notifications may start arriving before the watch\n  # method returns.\n  ...\n\n  resp = service.objects().watchAll(\n    bucket=\"some_bucket_id\", body=channel.body()).execute()\n  channel.update(resp)\n\n  # Store the channel, keyed by 'channel.id'. Store it after being updated\n  # since the resource_id value will now be correct, and that's needed to\n  # stop a subscription.\n  ...\n\n\nAn example Webhook implementation using webapp2. Note that webapp2 puts\nheaders in a case insensitive dictionary, as headers aren't guaranteed to\nalways be upper case.\n\n  id = self.request.headers[X_GOOG_CHANNEL_ID]\n\n  # Retrieve the channel by id.\n  channel = ...\n\n  # Parse notification from the headers, including validating the id.\n  n = notification_from_headers(channel, self.request.headers)\n\n  # Do app specific stuff with the notification here.\n  if n.resource_state == 'sync':\n    # Code to handle sync state.\n  elif n.resource_state == 'exists':\n    # Code to handle the exists state.\n  elif n.resource_state == 'not_exists':\n    # Code to handle the not exists state.\n\n\nExample of unsubscribing.\n\n  service.channels().stop(channel.body())\n\"\"\"\nfrom __future__ import absolute_import\n\nimport datetime\nimport uuid\n\nfrom googleapiclient import errors\nfrom googleapiclient import _helpers as util\nimport six\n\n\n# The unix time epoch starts at midnight 1970.\nEPOCH = datetime.datetime.utcfromtimestamp(0)\n\n# Map the names of the parameters in the JSON channel description to\n# the parameter names we use in the Channel class.\nCHANNEL_PARAMS = {\n    'address': 'address',\n    'id': 'id',\n    'expiration': 'expiration',\n    'params': 'params',\n    'resourceId': 'resource_id',\n    'resourceUri': 'resource_uri',\n    'type': 'type',\n    'token': 'token',\n    }\n\nX_GOOG_CHANNEL_ID     = 'X-GOOG-CHANNEL-ID'\nX_GOOG_MESSAGE_NUMBER = 'X-GOOG-MESSAGE-NUMBER'\nX_GOOG_RESOURCE_STATE = 'X-GOOG-RESOURCE-STATE'\nX_GOOG_RESOURCE_URI   = 'X-GOOG-RESOURCE-URI'\nX_GOOG_RESOURCE_ID    = 'X-GOOG-RESOURCE-ID'\n\n\ndef _upper_header_keys(headers):\n  new_headers = {}\n  for k, v in six.iteritems(headers):\n    new_headers[k.upper()] = v\n  return new_headers\n\n\nclass Notification(object):\n  \"\"\"A Notification from a Channel.\n\n  Notifications are not usually constructed directly, but are returned\n  from functions like notification_from_headers().\n\n  Attributes:\n    message_number: int, The unique id number of this notification.\n    state: str, The state of the resource being monitored.\n    uri: str, The address of the resource being monitored.\n    resource_id: str, The unique identifier of the version of the resource at\n      this event.\n  \"\"\"\n  @util.positional(5)\n  def __init__(self, message_number, state, resource_uri, resource_id):\n    \"\"\"Notification constructor.\n\n    Args:\n      message_number: int, The unique id number of this notification.\n      state: str, The state of the resource being monitored. Can be one\n        of \"exists\", \"not_exists\", or \"sync\".\n      resource_uri: str, The address of the resource being monitored.\n      resource_id: str, The identifier of the watched resource.\n    \"\"\"\n    self.message_number = message_number\n    self.state = state\n    self.resource_uri = resource_uri\n    self.resource_id = resource_id\n\n\nclass Channel(object):\n  \"\"\"A Channel for notifications.\n\n  Usually not constructed directly, instead it is returned from helper\n  functions like new_webhook_channel().\n\n  Attributes:\n    type: str, The type of delivery mechanism used by this channel. For\n      example, 'web_hook'.\n    id: str, A UUID for the channel.\n    token: str, An arbitrary string associated with the channel that\n      is delivered to the target address with each event delivered\n      over this channel.\n    address: str, The address of the receiving entity where events are\n      delivered. Specific to the channel type.\n    expiration: int, The time, in milliseconds from the epoch, when this\n      channel will expire.\n    params: dict, A dictionary of string to string, with additional parameters\n      controlling delivery channel behavior.\n    resource_id: str, An opaque id that identifies the resource that is\n      being watched. Stable across different API versions.\n    resource_uri: str, The canonicalized ID of the watched resource.\n  \"\"\"\n\n  @util.positional(5)\n  def __init__(self, type, id, token, address, expiration=None,\n               params=None, resource_id=\"\", resource_uri=\"\"):\n    \"\"\"Create a new Channel.\n\n    In user code, this Channel constructor will not typically be called\n    manually since there are functions for creating channels for each specific\n    type with a more customized set of arguments to pass.\n\n    Args:\n      type: str, The type of delivery mechanism used by this channel. For\n        example, 'web_hook'.\n      id: str, A UUID for the channel.\n      token: str, An arbitrary string associated with the channel that\n        is delivered to the target address with each event delivered\n        over this channel.\n      address: str,  The address of the receiving entity where events are\n        delivered. Specific to the channel type.\n      expiration: int, The time, in milliseconds from the epoch, when this\n        channel will expire.\n      params: dict, A dictionary of string to string, with additional parameters\n        controlling delivery channel behavior.\n      resource_id: str, An opaque id that identifies the resource that is\n        being watched. Stable across different API versions.\n      resource_uri: str, The canonicalized ID of the watched resource.\n    \"\"\"\n    self.type = type\n    self.id = id\n    self.token = token\n    self.address = address\n    self.expiration = expiration\n    self.params = params\n    self.resource_id = resource_id\n    self.resource_uri = resource_uri\n\n  def body(self):\n    \"\"\"Build a body from the Channel.\n\n    Constructs a dictionary that's appropriate for passing into watch()\n    methods as the value of body argument.\n\n    Returns:\n      A dictionary representation of the channel.\n    \"\"\"\n    result = {\n        'id': self.id,\n        'token': self.token,\n        'type': self.type,\n        'address': self.address\n        }\n    if self.params:\n      result['params'] = self.params\n    if self.resource_id:\n      result['resourceId'] = self.resource_id\n    if self.resource_uri:\n      result['resourceUri'] = self.resource_uri\n    if self.expiration:\n      result['expiration'] = self.expiration\n\n    return result\n\n  def update(self, resp):\n    \"\"\"Update a channel with information from the response of watch().\n\n    When a request is sent to watch() a resource, the response returned\n    from the watch() request is a dictionary with updated channel information,\n    such as the resource_id, which is needed when stopping a subscription.\n\n    Args:\n      resp: dict, The response from a watch() method.\n    \"\"\"\n    for json_name, param_name in six.iteritems(CHANNEL_PARAMS):\n      value = resp.get(json_name)\n      if value is not None:\n        setattr(self, param_name, value)\n\n\ndef notification_from_headers(channel, headers):\n  \"\"\"Parse a notification from the webhook request headers, validate\n    the notification, and return a Notification object.\n\n  Args:\n    channel: Channel, The channel that the notification is associated with.\n    headers: dict, A dictionary like object that contains the request headers\n      from the webhook HTTP request.\n\n  Returns:\n    A Notification object.\n\n  Raises:\n    errors.InvalidNotificationError if the notification is invalid.\n    ValueError if the X-GOOG-MESSAGE-NUMBER can't be converted to an int.\n  \"\"\"\n  headers = _upper_header_keys(headers)\n  channel_id = headers[X_GOOG_CHANNEL_ID]\n  if channel.id != channel_id:\n    raise errors.InvalidNotificationError(\n        'Channel id mismatch: %s != %s' % (channel.id, channel_id))\n  else:\n    message_number = int(headers[X_GOOG_MESSAGE_NUMBER])\n    state = headers[X_GOOG_RESOURCE_STATE]\n    resource_uri = headers[X_GOOG_RESOURCE_URI]\n    resource_id = headers[X_GOOG_RESOURCE_ID]\n    return Notification(message_number, state, resource_uri, resource_id)\n\n\n@util.positional(2)\ndef new_webhook_channel(url, token=None, expiration=None, params=None):\n    \"\"\"Create a new webhook Channel.\n\n    Args:\n      url: str, URL to post notifications to.\n      token: str, An arbitrary string associated with the channel that\n        is delivered to the target address with each notification delivered\n        over this channel.\n      expiration: datetime.datetime, A time in the future when the channel\n        should expire. Can also be None if the subscription should use the\n        default expiration. Note that different services may have different\n        limits on how long a subscription lasts. Check the response from the\n        watch() method to see the value the service has set for an expiration\n        time.\n      params: dict, Extra parameters to pass on channel creation. Currently\n        not used for webhook channels.\n    \"\"\"\n    expiration_ms = 0\n    if expiration:\n      delta = expiration - EPOCH\n      expiration_ms = delta.microseconds/1000 + (\n          delta.seconds + delta.days*24*3600)*1000\n      if expiration_ms < 0:\n        expiration_ms = 0\n\n    return Channel('web_hook', str(uuid.uuid4()),\n                   token, url, expiration=expiration_ms,\n                   params=params)\n\n", "path": "googleapiclient/channel.py"}]}