66import json
77import logging
88import platform
9- import time
109import random
10+ import time
1111from urllib .parse import urlencode , urlsplit , urlunsplit
1212
1313import payjp
14+
1415from . import (
1516 error ,
1617 http_client ,
1718 version ,
1819)
1920
20- logger = logging .getLogger (' payjp' )
21+ logger = logging .getLogger (" payjp" )
2122
2223
2324class APIRequestor (object ):
24-
2525 def __init__ (self , key = None , client = None , api_base = None , account = None ):
2626 if api_base :
2727 self .api_base = api_base
@@ -38,142 +38,158 @@ def _get_retry_delay(self, retry_count):
3838 Based on "Exponential backoff with equal jitter" algorithm.
3939 https://aws.amazon.com/jp/blogs/architecture/exponential-backoff-and-jitter/
4040 """
41- wait = min (payjp .retry_max_delay , payjp .retry_initial_delay * 2 ** retry_count )
42- return ( wait / 2 + random .uniform (0 , wait / 2 ) )
41+ wait = min (payjp .retry_max_delay , payjp .retry_initial_delay * 2 ** retry_count )
42+ return wait / 2 + random .uniform (0 , wait / 2 )
4343
4444 def request (self , method , url , params = None , headers = None ):
4545 max_retry = payjp .max_retry or 0
4646 for i in range (max_retry + 1 ):
4747 body , code , my_api_key = self .request_raw (
48- method .lower (), url , params , headers )
48+ method .lower (), url , params , headers
49+ )
4950 if code != 429 :
5051 break
5152 elif i != max_retry :
5253 wait = self ._get_retry_delay (i )
53- logger .debug (' Retry after %s seconds.' % wait )
54+ logger .debug (" Retry after %s seconds." % wait )
5455 time .sleep (wait )
5556
5657 response = self .interpret_response (body , code )
5758 return response , my_api_key
5859
5960 def handle_api_error (self , body , code , response ):
6061 try :
61- err = response [' error' ]
62+ err = response [" error" ]
6263 except (KeyError , TypeError ):
6364 raise error .APIError (
6465 "Invalid response object from API: %r (HTTP response code "
6566 "was %d)" % (body , code ),
66- body , code , response )
67+ body ,
68+ code ,
69+ response ,
70+ )
6771
6872 if code in [400 , 404 ]:
6973 raise error .InvalidRequestError (
70- err .get ('message' ), err .get ('param' ), body , code , response )
74+ err .get ("message" ), err .get ("param" ), body , code , response
75+ )
7176 elif code == 401 :
72- raise error .AuthenticationError (
73- err .get ('message' ), body , code , response )
77+ raise error .AuthenticationError (err .get ("message" ), body , code , response )
7478 elif code == 402 :
75- raise error .CardError (err .get ('message' ), err .get ('param' ),
76- err .get ('code' ), body , code , response )
79+ raise error .CardError (
80+ err .get ("message" ),
81+ err .get ("param" ),
82+ err .get ("code" ),
83+ body ,
84+ code ,
85+ response ,
86+ )
7787 else :
78- raise error .APIError (err .get (' message' ), body , code , response )
88+ raise error .APIError (err .get (" message" ), body , code , response )
7989
8090 def request_raw (self , method , url , params = None , supplied_headers = None ):
81-
8291 from payjp import api_version
8392
8493 if self .api_key :
8594 my_api_key = self .api_key
8695 else :
8796 from payjp import api_key
97+
8898 my_api_key = api_key
8999
90100 if my_api_key is None :
91101 raise error .AuthenticationError (
92- ' No API key provided. (HINT: set your API key using '
102+ " No API key provided. (HINT: set your API key using "
93103 '"payjp.api_key = <API-KEY>"). You can generate API keys '
94- 'from the Payjp web interface. See https://docs.pay.jp'
95- 'for details, or email support@pay.jp if you have any '
96- 'questions.' )
104+ "from the Payjp web interface. See https://docs.pay.jp"
105+ "for details, or email support@pay.jp if you have any "
106+ "questions."
107+ )
97108
98- abs_url = ' %s%s' % (self .api_base , url )
109+ abs_url = " %s%s" % (self .api_base , url )
99110
100111 encoded_params = urlencode (list (_api_encode (params or {})))
101112
102- if method in (' get' , ' delete' ):
113+ if method in (" get" , " delete" ):
103114 if params :
104115 abs_url = _build_api_url (abs_url , encoded_params )
105116 post_data = None
106- elif method == ' post' :
117+ elif method == " post" :
107118 post_data = encoded_params
108119 else :
109- raise error .APIConnectionError (
110- 'Unrecognized HTTP method %r.' % (method ,))
120+ raise error .APIConnectionError ("Unrecognized HTTP method %r." % (method ,))
111121
112122 ua = {
113- ' bindings_version' : version .VERSION ,
114- ' lang' : ' python' ,
115- ' publisher' : ' payjp' ,
116- ' httplib' : self ._client .name ,
123+ " bindings_version" : version .VERSION ,
124+ " lang" : " python" ,
125+ " publisher" : " payjp" ,
126+ " httplib" : self ._client .name ,
117127 }
118128
119- for attr , func in [['lang_version' , platform .python_version ],
120- ['platform' , platform .platform ],
121- ['uname' , lambda : ' ' .join (platform .uname ())]]:
129+ for attr , func in [
130+ ["lang_version" , platform .python_version ],
131+ ["platform" , platform .platform ],
132+ ["uname" , lambda : " " .join (platform .uname ())],
133+ ]:
122134 try :
123135 val = func ()
124136 except Exception as e :
125- val = ' !! %s' % (e ,)
137+ val = " !! %s" % (e ,)
126138 ua [attr ] = val
127139
128140 encoded_api_key = str (
129- base64 .b64encode (
130- bytes ( '' . join ([ my_api_key , ':' ]), 'utf-8' )), 'utf-8' )
141+ base64 .b64encode (bytes ( "" . join ([ my_api_key , ":" ]), "utf-8" )), "utf-8"
142+ )
131143
132144 headers = {
133- ' X-Payjp-Client-User-Agent' : json .dumps (ua ),
134- ' User-Agent' : ' Payjp/v1 PythonBindings/%s' % (version .VERSION ,),
135- ' Authorization' : ' Basic %s' % encoded_api_key
145+ " X-Payjp-Client-User-Agent" : json .dumps (ua ),
146+ " User-Agent" : " Payjp/v1 PythonBindings/%s" % (version .VERSION ,),
147+ " Authorization" : " Basic %s" % encoded_api_key ,
136148 }
137149
138150 if self .payjp_account :
139- headers [' Payjp-Account' ] = self .payjp_account
151+ headers [" Payjp-Account" ] = self .payjp_account
140152
141- if method == ' post' :
142- headers [' Content-Type' ] = ' application/x-www-form-urlencoded'
153+ if method == " post" :
154+ headers [" Content-Type" ] = " application/x-www-form-urlencoded"
143155
144156 if api_version is not None :
145- headers [' Payjp-Version' ] = api_version
157+ headers [" Payjp-Version" ] = api_version
146158
147159 if supplied_headers is not None :
148160 for key , value in supplied_headers .items ():
149161 headers [key ] = value
150162
151- body , code = self ._client .request (
152- method , abs_url , headers , post_data )
163+ body , code = self ._client .request (method , abs_url , headers , post_data )
153164
154- logger .info (' %s %s %d' , method .upper (), abs_url , code )
165+ logger .info (" %s %s %d" , method .upper (), abs_url , code )
155166 logger .debug (
156- 'API request to %s returned (response code, response body) of '
157- '(%d, %r)' ,
158- abs_url , code , body )
167+ "API request to %s returned (response code, response body) of (%d, %r)" ,
168+ abs_url ,
169+ code ,
170+ body ,
171+ )
159172
160173 return body , code , my_api_key
161174
162175 def interpret_response (self , body , code ):
163176 try :
164- if hasattr (body , ' decode' ):
165- body = body .decode (' utf-8' )
177+ if hasattr (body , " decode" ):
178+ body = body .decode (" utf-8" )
166179 response = json .loads (body )
167180 except Exception :
168181 raise error .APIError (
169182 "Invalid response body from API: %s "
170183 "(HTTP response code was %d)" % (body , code ),
171- body , code )
184+ body ,
185+ code ,
186+ )
172187 if not (200 <= code < 300 ):
173188 self .handle_api_error (body , code , response )
174189
175190 return response
176191
192+
177193def _encode_datetime (dttime ):
178194 if dttime .tzinfo and dttime .tzinfo .utcoffset (dttime ) is not None :
179195 utc_timestamp = calendar .timegm (dttime .utctimetuple ())
@@ -182,29 +198,33 @@ def _encode_datetime(dttime):
182198
183199 return int (utc_timestamp )
184200
201+
185202def _api_encode (data ):
186203 for key , value in data .items ():
187204 if value is None :
188205 continue
189- elif hasattr (value , ' payjp_id' ):
206+ elif hasattr (value , " payjp_id" ):
190207 yield (key , value .payjp_id )
191208 elif isinstance (value , list ) or isinstance (value , tuple ):
192209 for subvalue in value :
193210 yield ("%s[]" % (key ,), subvalue )
194211 elif isinstance (value , dict ):
195- subdict = dict (('%s[%s]' % (key , subkey ), subvalue ) for
196- subkey , subvalue in value .items ())
212+ subdict = dict (
213+ ("%s[%s]" % (key , subkey ), subvalue )
214+ for subkey , subvalue in value .items ()
215+ )
197216 for subkey , subvalue in _api_encode (subdict ):
198217 yield (subkey , subvalue )
199218 elif isinstance (value , datetime .datetime ):
200219 yield (key , _encode_datetime (value ))
201220 else :
202221 yield (key , value )
203222
223+
204224def _build_api_url (url , query ):
205225 scheme , netloc , path , base_query , fragment = urlsplit (url )
206226
207227 if base_query :
208- query = ' %s&%s' % (base_query , query )
228+ query = " %s&%s" % (base_query , query )
209229
210230 return urlunsplit ((scheme , netloc , path , query , fragment ))
0 commit comments