1- # coding: utf-8
2-
31import base64
42import calendar
53import datetime
64import json
75import logging
86import platform
9- import time
107import random
8+ import time
119from urllib .parse import urlencode , urlsplit , urlunsplit
1210
1311import payjp
14- from . import (
15- error ,
16- http_client ,
17- version ,
18- )
1912
20- logger = logging . getLogger ( 'payjp' )
13+ from . import error , http_client , version
2114
15+ logger = logging .getLogger ("payjp" )
2216
23- class APIRequestor (object ):
2417
18+ class APIRequestor :
2519 def __init__ (self , key = None , client = None , api_base = None , account = None ):
2620 if api_base :
2721 self .api_base = api_base
@@ -38,142 +32,161 @@ def _get_retry_delay(self, retry_count):
3832 Based on "Exponential backoff with equal jitter" algorithm.
3933 https://aws.amazon.com/jp/blogs/architecture/exponential-backoff-and-jitter/
4034 """
41- wait = min (payjp .retry_max_delay , payjp .retry_initial_delay * 2 ** retry_count )
42- return (wait / 2 + random .uniform (0 , wait / 2 ))
35+ wait = min (
36+ payjp .retry_max_delay ,
37+ payjp .retry_initial_delay * 2 ** retry_count ,
38+ )
39+ return wait / 2 + random .uniform (0 , wait / 2 )
4340
4441 def request (self , method , url , params = None , headers = None ):
4542 max_retry = payjp .max_retry or 0
4643 for i in range (max_retry + 1 ):
4744 body , code , my_api_key = self .request_raw (
48- method .lower (), url , params , headers )
45+ method .lower (), url , params , headers
46+ )
4947 if code != 429 :
5048 break
5149 elif i != max_retry :
5250 wait = self ._get_retry_delay (i )
53- logger .debug (' Retry after %s seconds.' % wait )
51+ logger .debug (" Retry after %s seconds." % wait )
5452 time .sleep (wait )
5553
5654 response = self .interpret_response (body , code )
5755 return response , my_api_key
5856
5957 def handle_api_error (self , body , code , response ):
6058 try :
61- err = response [' error' ]
59+ err = response [" error" ]
6260 except (KeyError , TypeError ):
6361 raise error .APIError (
6462 "Invalid response object from API: %r (HTTP response code "
6563 "was %d)" % (body , code ),
66- body , code , response )
64+ body ,
65+ code ,
66+ response ,
67+ )
6768
6869 if code in [400 , 404 ]:
6970 raise error .InvalidRequestError (
70- err .get ('message' ), err .get ('param' ), body , code , response )
71+ err .get ("message" ), err .get ("param" ), body , code , response
72+ )
7173 elif code == 401 :
72- raise error .AuthenticationError (
73- err .get ('message' ), body , code , response )
74+ raise error .AuthenticationError (err .get ("message" ), body , code , response )
7475 elif code == 402 :
75- raise error .CardError (err .get ('message' ), err .get ('param' ),
76- err .get ('code' ), body , code , response )
76+ raise error .CardError (
77+ err .get ("message" ),
78+ err .get ("param" ),
79+ err .get ("code" ),
80+ body ,
81+ code ,
82+ response ,
83+ )
7784 else :
78- raise error .APIError (err .get (' message' ), body , code , response )
85+ raise error .APIError (err .get (" message" ), body , code , response )
7986
8087 def request_raw (self , method , url , params = None , supplied_headers = None ):
81-
8288 from payjp import api_version
8389
8490 if self .api_key :
8591 my_api_key = self .api_key
8692 else :
8793 from payjp import api_key
94+
8895 my_api_key = api_key
8996
9097 if my_api_key is None :
9198 raise error .AuthenticationError (
92- ' No API key provided. (HINT: set your API key using '
99+ " No API key provided. (HINT: set your API key using "
93100 '"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.' )
101+ "from the Payjp web interface. See https://docs.pay.jp"
102+ "for details, or email support@pay.jp if you have any "
103+ "questions."
104+ )
97105
98- abs_url = '%s%s' % ( self .api_base , url )
106+ abs_url = f" { self .api_base } { url } "
99107
100108 encoded_params = urlencode (list (_api_encode (params or {})))
101109
102- if method in (' get' , ' delete' ):
110+ if method in (" get" , " delete" ):
103111 if params :
104112 abs_url = _build_api_url (abs_url , encoded_params )
105113 post_data = None
106- elif method == ' post' :
114+ elif method == " post" :
107115 post_data = encoded_params
108116 else :
109- raise error .APIConnectionError (
110- 'Unrecognized HTTP method %r.' % (method ,))
117+ raise error .APIConnectionError (f"Unrecognized HTTP method { method !r} ." )
111118
112119 ua = {
113- ' bindings_version' : version .VERSION ,
114- ' lang' : ' python' ,
115- ' publisher' : ' payjp' ,
116- ' httplib' : self ._client .name ,
120+ " bindings_version" : version .VERSION ,
121+ " lang" : " python" ,
122+ " publisher" : " payjp" ,
123+ " httplib" : self ._client .name ,
117124 }
118125
119- for attr , func in [['lang_version' , platform .python_version ],
120- ['platform' , platform .platform ],
121- ['uname' , lambda : ' ' .join (platform .uname ())]]:
126+ for attr , func in [
127+ ["lang_version" , platform .python_version ],
128+ ["platform" , platform .platform ],
129+ ["uname" , lambda : " " .join (platform .uname ())],
130+ ]:
122131 try :
123132 val = func ()
124133 except Exception as e :
125- val = ' !! %s' % ( e ,)
134+ val = f" !! { e } "
126135 ua [attr ] = val
127136
128137 encoded_api_key = str (
129- base64 .b64encode (
130- bytes ( '' . join ([ my_api_key , ':' ]), 'utf-8' )), 'utf-8' )
138+ base64 .b64encode (bytes ( "" . join ([ my_api_key , ":" ]), "utf-8" )), "utf-8"
139+ )
131140
132141 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
142+ " X-Payjp-Client-User-Agent" : json .dumps (ua ),
143+ " User-Agent" : f" Payjp/v1 PythonBindings/{ version .VERSION } " ,
144+ " Authorization" : " Basic %s" % encoded_api_key ,
136145 }
137146
138147 if self .payjp_account :
139- headers [' Payjp-Account' ] = self .payjp_account
148+ headers [" Payjp-Account" ] = self .payjp_account
140149
141- if method == ' post' :
142- headers [' Content-Type' ] = ' application/x-www-form-urlencoded'
150+ if method == " post" :
151+ headers [" Content-Type" ] = " application/x-www-form-urlencoded"
143152
144153 if api_version is not None :
145- headers [' Payjp-Version' ] = api_version
154+ headers [" Payjp-Version" ] = api_version
146155
147156 if supplied_headers is not None :
148157 for key , value in supplied_headers .items ():
149158 headers [key ] = value
150159
151- body , code = self ._client .request (
152- method , abs_url , headers , post_data )
160+ body , code = self ._client .request (method , abs_url , headers , post_data )
153161
154- logger .info (' %s %s %d' , method .upper (), abs_url , code )
162+ logger .info (" %s %s %d" , method .upper (), abs_url , code )
155163 logger .debug (
156- 'API request to %s returned (response code, response body) of '
157- '(%d, %r)' ,
158- abs_url , code , body )
164+ "API request to %s returned (response code, response body) of (%d, %r)" ,
165+ abs_url ,
166+ code ,
167+ body ,
168+ )
159169
160170 return body , code , my_api_key
161171
162172 def interpret_response (self , body , code ):
163173 try :
164- if hasattr (body , ' decode' ):
165- body = body .decode (' utf-8' )
174+ if hasattr (body , " decode" ):
175+ body = body .decode (" utf-8" )
166176 response = json .loads (body )
167177 except Exception :
168178 raise error .APIError (
169179 "Invalid response body from API: %s "
170180 "(HTTP response code was %d)" % (body , code ),
171- body , code )
181+ body ,
182+ code ,
183+ )
172184 if not (200 <= code < 300 ):
173185 self .handle_api_error (body , code , response )
174186
175187 return response
176188
189+
177190def _encode_datetime (dttime ):
178191 if dttime .tzinfo and dttime .tzinfo .utcoffset (dttime ) is not None :
179192 utc_timestamp = calendar .timegm (dttime .utctimetuple ())
@@ -182,29 +195,32 @@ def _encode_datetime(dttime):
182195
183196 return int (utc_timestamp )
184197
198+
185199def _api_encode (data ):
186200 for key , value in data .items ():
187201 if value is None :
188202 continue
189- elif hasattr (value , ' payjp_id' ):
203+ elif hasattr (value , " payjp_id" ):
190204 yield (key , value .payjp_id )
191205 elif isinstance (value , list ) or isinstance (value , tuple ):
192206 for subvalue in value :
193- yield ("%s []" % ( key ,) , subvalue )
207+ yield (f" { key } []" , subvalue )
194208 elif isinstance (value , dict ):
195- subdict = dict (('%s[%s]' % (key , subkey ), subvalue ) for
196- subkey , subvalue in value .items ())
209+ subdict = dict (
210+ (f"{ key } [{ subkey } ]" , subvalue ) for subkey , subvalue in value .items ()
211+ )
197212 for subkey , subvalue in _api_encode (subdict ):
198213 yield (subkey , subvalue )
199214 elif isinstance (value , datetime .datetime ):
200215 yield (key , _encode_datetime (value ))
201216 else :
202217 yield (key , value )
203218
219+
204220def _build_api_url (url , query ):
205221 scheme , netloc , path , base_query , fragment = urlsplit (url )
206222
207223 if base_query :
208- query = '%s&%s' % ( base_query , query )
224+ query = f" { base_query } & { query } "
209225
210226 return urlunsplit ((scheme , netloc , path , query , fragment ))
0 commit comments