88GCM_URL = 'https://android.googleapis.com/gcm/send'
99
1010
11- class GCMException (Exception ): pass
12- class GCMMalformedJsonException (GCMException ): pass
13- class GCMConnectionException (GCMException ): pass
14- class GCMAuthenticationException (GCMException ): pass
15- class GCMTooManyRegIdsException (GCMException ): pass
16- class GCMInvalidTtlException (GCMException ): pass
11+ class GCMException (Exception ):
12+ pass
13+
14+
15+ class GCMMalformedJsonException (GCMException ):
16+ pass
17+
18+
19+ class GCMConnectionException (GCMException ):
20+ pass
21+
22+
23+ class GCMAuthenticationException (GCMException ):
24+ pass
25+
26+
27+ class GCMTooManyRegIdsException (GCMException ):
28+ pass
29+
30+
31+ class GCMInvalidTtlException (GCMException ):
32+ pass
1733
1834# Exceptions from Google responses
19- class GCMMissingRegistrationException (GCMException ): pass
20- class GCMMismatchSenderIdException (GCMException ): pass
21- class GCMNotRegisteredException (GCMException ): pass
22- class GCMMessageTooBigException (GCMException ): pass
23- class GCMInvalidRegistrationException (GCMException ): pass
24- class GCMUnavailableException (GCMException ): pass
35+
36+
37+ class GCMMissingRegistrationException (GCMException ):
38+ pass
39+
40+
41+ class GCMMismatchSenderIdException (GCMException ):
42+ pass
43+
44+
45+ class GCMNotRegisteredException (GCMException ):
46+ pass
47+
48+
49+ class GCMMessageTooBigException (GCMException ):
50+ pass
51+
52+
53+ class GCMInvalidRegistrationException (GCMException ):
54+ pass
55+
56+
57+ class GCMUnavailableException (GCMException ):
58+ pass
2559
2660
2761# TODO: Refactor this to be more human-readable
2862def group_response (response , registration_ids , key ):
2963 # Pair up results and reg_ids
3064 mapping = zip (registration_ids , response ['results' ])
3165 # Filter by key
32- filtered = filter (lambda x : key in x [1 ], mapping )
33- # Only consider the value in the dict
34- tupled = [(s [0 ], s [1 ][key ]) for s in filtered ]
66+ filtered = ((reg_id , res [key ]) for reg_id , res in mapping if key in res )
3567 # Grouping of errors and mapping of ids
3668 if key is 'registration_id' :
37- grouping = {}
38- for k , v in tupled :
39- grouping [k ] = v
69+ grouping = dict (filtered )
4070 else :
4171 grouping = defaultdict (list )
42- for k , v in tupled :
72+ for k , v in filtered :
4373 grouping [v ].append (k )
4474
45- if len (grouping ) == 0 :
46- return
47- return grouping
75+ return grouping or None
4876
4977
5078def urlencode_utf8 (params ):
@@ -56,7 +84,7 @@ def urlencode_utf8(params):
5684 if hasattr (params , 'items' ):
5785 params = params .items ()
5886
59- params = (
87+ params = (
6088 '=' .join ((
6189 urllib .quote_plus (k .encode ('utf8' ), safe = '/' ),
6290 urllib .quote_plus (v .encode ('utf8' ), safe = '/' )
@@ -69,8 +97,8 @@ def urlencode_utf8(params):
6997class GCM (object ):
7098
7199 # Timeunit is milliseconds.
72- BACKOFF_INITIAL_DELAY = 1000 ;
73- MAX_BACKOFF_DELAY = 1024000 ;
100+ BACKOFF_INITIAL_DELAY = 1000
101+ MAX_BACKOFF_DELAY = 1024000
74102
75103 def __init__ (self , api_key , url = GCM_URL , proxy = None ):
76104 """ api_key : google api key
@@ -80,17 +108,17 @@ def __init__(self, api_key, url=GCM_URL, proxy=None):
80108 self .api_key = api_key
81109 self .url = url
82110 if proxy :
83- if isinstance (proxy ,basestring ):
111+ if isinstance (proxy , basestring ):
84112 protocol = url .split (':' )[0 ]
85- proxy = {protocol :proxy }
113+ proxy = {protocol : proxy }
86114
87115 auth = urllib2 .HTTPBasicAuthHandler ()
88- opener = urllib2 .build_opener (urllib2 .ProxyHandler (proxy ), auth , urllib2 .HTTPHandler )
116+ opener = urllib2 .build_opener (
117+ urllib2 .ProxyHandler (proxy ), auth , urllib2 .HTTPHandler )
89118 urllib2 .install_opener (opener )
90119
91-
92120 def construct_payload (self , registration_ids , data = None , collapse_key = None ,
93- delay_while_idle = False , time_to_live = None , is_json = True , dry_run = False ):
121+ delay_while_idle = False , time_to_live = None , is_json = True , dry_run = False ):
94122 """
95123 Construct the dictionary mapping of parameters.
96124 Encodes the dictionary into JSON if for json requests.
@@ -101,7 +129,8 @@ def construct_payload(self, registration_ids, data=None, collapse_key=None,
101129 """
102130
103131 if time_to_live :
104- if time_to_live > 2419200 or time_to_live < 0 :
132+ four_weeks_in_secs = 2419200
133+ if not (0 <= time_to_live <= four_weeks_in_secs ):
105134 raise GCMInvalidTtlException ("Invalid time to live value" )
106135
107136 if is_json :
@@ -119,7 +148,7 @@ def construct_payload(self, registration_ids, data=None, collapse_key=None,
119148 if delay_while_idle :
120149 payload ['delay_while_idle' ] = delay_while_idle
121150
122- if time_to_live >= 0 :
151+ if time_to_live :
123152 payload ['time_to_live' ] = time_to_live
124153
125154 if collapse_key :
@@ -146,7 +175,8 @@ def make_request(self, data, is_json=True):
146175 headers = {
147176 'Authorization' : 'key=%s' % self .api_key ,
148177 }
149- # Default Content-Type is defaulted to application/x-www-form-urlencoded;charset=UTF-8
178+ # Default Content-Type is defaulted to
179+ # application/x-www-form-urlencoded;charset=UTF-8
150180 if is_json :
151181 headers ['Content-Type' ] = 'application/json'
152182
@@ -158,16 +188,19 @@ def make_request(self, data, is_json=True):
158188 response = urllib2 .urlopen (req ).read ()
159189 except urllib2 .HTTPError as e :
160190 if e .code == 400 :
161- raise GCMMalformedJsonException ("The request could not be parsed as JSON" )
191+ raise GCMMalformedJsonException (
192+ "The request could not be parsed as JSON" )
162193 elif e .code == 401 :
163- raise GCMAuthenticationException ("There was an error authenticating the sender account" )
194+ raise GCMAuthenticationException (
195+ "There was an error authenticating the sender account" )
164196 elif e .code == 503 :
165197 raise GCMUnavailableException ("GCM service is unavailable" )
166198 else :
167199 error = "GCM service error: %d" % e .code
168200 raise GCMUnavailableException (error )
169201 except urllib2 .URLError as e :
170- raise GCMConnectionException ("There was an internal error in the GCM server while trying to process the request" )
202+ raise GCMConnectionException (
203+ "There was an internal error in the GCM server while trying to process the request" )
171204
172205 if is_json :
173206 response = json .loads (response )
@@ -179,11 +212,14 @@ def raise_error(self, error):
179212 elif error == 'Unavailable' :
180213 # Plain-text requests will never return Unavailable as the error code.
181214 # http://developer.android.com/guide/google/gcm/gcm.html#error_codes
182- raise GCMUnavailableException ("Server unavailable. Resent the message" )
215+ raise GCMUnavailableException (
216+ "Server unavailable. Resent the message" )
183217 elif error == 'NotRegistered' :
184- raise GCMNotRegisteredException ("Registration id is not valid anymore" )
218+ raise GCMNotRegisteredException (
219+ "Registration id is not valid anymore" )
185220 elif error == 'MismatchSenderId' :
186- raise GCMMismatchSenderIdException ("A Registration ID is tied to a certain group of senders" )
221+ raise GCMMismatchSenderIdException (
222+ "A Registration ID is tied to a certain group of senders" )
187223 elif error == 'MessageTooBig' :
188224 raise GCMMessageTooBigException ("Message can't exceed 4096 bytes" )
189225
@@ -202,7 +238,8 @@ def handle_plaintext_response(self, response):
202238
203239 def handle_json_response (self , response , registration_ids ):
204240 errors = group_response (response , registration_ids , 'error' )
205- canonical = group_response (response , registration_ids , 'registration_id' )
241+ canonical = group_response (
242+ response , registration_ids , 'registration_id' )
206243
207244 info = {}
208245 if errors :
@@ -218,7 +255,7 @@ def extract_unsent_reg_ids(self, info):
218255 return []
219256
220257 def plaintext_request (self , registration_id , data = None , collapse_key = None ,
221- delay_while_idle = False , time_to_live = None , retries = 5 , dry_run = False ):
258+ delay_while_idle = False , time_to_live = None , retries = 5 , dry_run = False ):
222259 """
223260 Makes a plaintext request to GCM servers
224261
@@ -251,7 +288,7 @@ def plaintext_request(self, registration_id, data=None, collapse_key=None,
251288 raise IOError ("Could not make request after %d attempts" % attempt )
252289
253290 def json_request (self , registration_ids , data = None , collapse_key = None ,
254- delay_while_idle = False , time_to_live = None , retries = 5 , dry_run = False ):
291+ delay_while_idle = False , time_to_live = None , retries = 5 , dry_run = False ):
255292 """
256293 Makes a JSON request to GCM servers
257294
@@ -265,7 +302,8 @@ def json_request(self, registration_ids, data=None, collapse_key=None,
265302 if not registration_ids :
266303 raise GCMMissingRegistrationException ("Missing registration_ids" )
267304 if len (registration_ids ) > 1000 :
268- raise GCMTooManyRegIdsException ("Exceded number of registration_ids" )
305+ raise GCMTooManyRegIdsException (
306+ "Exceded number of registration_ids" )
269307
270308 attempt = 0
271309 backoff = self .BACKOFF_INITIAL_DELAY
0 commit comments