Created
June 11, 2014 08:37
-
-
Save jasimmk/bf386f1a1902144aebfd to your computer and use it in GitHub Desktop.
Stripe save requests and responses to file, for mock api generation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import calendar | |
import datetime | |
import platform | |
import time | |
import urllib | |
import urlparse | |
import warnings | |
import stripe | |
from stripe import error, http_client, version, util | |
from functools import wraps | |
import json | |
def write_to_file(view_func): | |
def _decorator(request, *args, **kwargs): | |
with open('/tmp/api.json', 'a') as f: | |
f.write("\nREQUEST\n") | |
f.write(json.dumps(args)) | |
# maybe do something before the view_func call | |
response = view_func(request, *args, **kwargs) | |
# maybe do something after the view_func call | |
f.write("\nRESPONSE\n") | |
f.write(json.dumps(response)) | |
return response | |
return wraps(view_func)(_decorator) | |
def _encode_datetime(dttime): | |
if dttime.tzinfo and dttime.tzinfo.utcoffset(dttime) is not None: | |
utc_timestamp = calendar.timegm(dttime.utctimetuple()) | |
else: | |
utc_timestamp = time.mktime(dttime.timetuple()) | |
return int(utc_timestamp) | |
def _api_encode(data): | |
for key, value in data.iteritems(): | |
key = util.utf8(key) | |
if value is None: | |
continue | |
elif hasattr(value, 'stripe_id'): | |
yield (key, value.stripe_id) | |
elif isinstance(value, list) or isinstance(value, tuple): | |
for subvalue in value: | |
yield ("%s[]" % (key,), util.utf8(subvalue)) | |
elif isinstance(value, dict): | |
subdict = dict(('%s[%s]' % (key, subkey), subvalue) for | |
subkey, subvalue in value.iteritems()) | |
for subkey, subvalue in _api_encode(subdict): | |
yield (subkey, subvalue) | |
elif isinstance(value, datetime.datetime): | |
yield (key, _encode_datetime(value)) | |
else: | |
yield (key, util.utf8(value)) | |
def _build_api_url(url, query): | |
scheme, netloc, path, base_query, fragment = urlparse.urlsplit(url) | |
if base_query: | |
query = '%s&%s' % (base_query, query) | |
return urlparse.urlunsplit((scheme, netloc, path, query, fragment)) | |
class APIRequestor(object): | |
def __init__(self, key=None, client=None): | |
self.api_key = key | |
from stripe import verify_ssl_certs | |
self._client = client or http_client.new_default_http_client( | |
verify_ssl_certs=verify_ssl_certs) | |
@classmethod | |
def api_url(cls, url=''): | |
warnings.warn( | |
'The `api_url` class method of APIRequestor is ' | |
'deprecated and will be removed in version 2.0.' | |
'If you need public access to this function, please email us ' | |
'at [email protected].', | |
DeprecationWarning) | |
return '%s%s' % (stripe.api_base, url) | |
@classmethod | |
def _deprecated_encode(cls, stk, key, value): | |
warnings.warn( | |
'The encode_* class methods of APIRequestor are deprecated and ' | |
'will be removed in version 2.0. ' | |
'If you need public access to this function, please email us ' | |
'at [email protected].', | |
DeprecationWarning, stacklevel=2) | |
stk.extend(_api_encode({key: value})) | |
@classmethod | |
def encode_dict(cls, stk, key, value): | |
cls._deprecated_encode(stk, key, value) | |
@classmethod | |
def encode_list(cls, stk, key, value): | |
cls._deprecated_encode(stk, key, value) | |
@classmethod | |
def encode_datetime(cls, stk, key, value): | |
cls._deprecated_encode(stk, key, value) | |
@classmethod | |
def encode_none(cls, stk, key, value): | |
cls._deprecated_encode(stk, key, value) | |
@classmethod | |
def encode(cls, d): | |
""" | |
Internal: encode a string for url representation | |
""" | |
warnings.warn( | |
'The `encode` class method of APIRequestor is deprecated and ' | |
'will be removed in version 2.0.' | |
'If you need public access to this function, please email us ' | |
'at [email protected].', | |
DeprecationWarning) | |
return urllib.urlencode(list(_api_encode(d))) | |
@classmethod | |
def build_url(cls, url, params): | |
warnings.warn( | |
'The `build_url` class method of APIRequestor is deprecated and ' | |
'will be removed in version 2.0.' | |
'If you need public access to this function, please email us ' | |
'at [email protected].', | |
DeprecationWarning) | |
return _build_api_url(url, cls.encode(params)) | |
@write_to_file | |
def request(self, method, url, params=None): | |
rbody, rcode, my_api_key = self.request_raw( | |
method.lower(), url, params) | |
resp = self.interpret_response(rbody, rcode) | |
return resp, my_api_key | |
def handle_api_error(self, rbody, rcode, resp): | |
try: | |
err = resp['error'] | |
except (KeyError, TypeError): | |
raise error.APIError( | |
"Invalid response object from API: %r (HTTP response code " | |
"was %d)" % (rbody, rcode), | |
rbody, rcode, resp) | |
if rcode in [400, 404]: | |
raise error.InvalidRequestError( | |
err.get('message'), err.get('param'), rbody, rcode, resp) | |
elif rcode == 401: | |
raise error.AuthenticationError( | |
err.get('message'), rbody, rcode, resp) | |
elif rcode == 402: | |
raise error.CardError(err.get('message'), err.get('param'), | |
err.get('code'), rbody, rcode, resp) | |
else: | |
raise error.APIError(err.get('message'), rbody, rcode, resp) | |
def request_raw(self, method, url, params=None): | |
""" | |
Mechanism for issuing an API call | |
""" | |
from stripe import api_version | |
if self.api_key: | |
my_api_key = self.api_key | |
else: | |
from stripe import api_key | |
my_api_key = api_key | |
if my_api_key is None: | |
raise error.AuthenticationError( | |
'No API key provided. (HINT: set your API key using ' | |
'"stripe.api_key = <API-KEY>"). You can generate API keys ' | |
'from the Stripe web interface. See https://stripe.com/api ' | |
'for details, or email [email protected] if you have any ' | |
'questions.') | |
abs_url = '%s%s' % (stripe.api_base, url) | |
encoded_params = urllib.urlencode(list(_api_encode(params or {}))) | |
if method == 'get' or method == 'delete': | |
if params: | |
abs_url = _build_api_url(abs_url, encoded_params) | |
post_data = None | |
elif method == 'post': | |
post_data = encoded_params | |
else: | |
raise error.APIConnectionError( | |
'Unrecognized HTTP method %r. This may indicate a bug in the ' | |
'Stripe bindings. Please contact [email protected] for ' | |
'assistance.' % (method,)) | |
ua = { | |
'bindings_version': version.VERSION, | |
'lang': 'python', | |
'publisher': 'stripe', | |
'httplib': self._client.name, | |
} | |
for attr, func in [['lang_version', platform.python_version], | |
['platform', platform.platform], | |
['uname', lambda: ' '.join(platform.uname())]]: | |
try: | |
val = func() | |
except Exception, e: | |
val = "!! %s" % (e,) | |
ua[attr] = val | |
headers = { | |
'X-Stripe-Client-User-Agent': util.json.dumps(ua), | |
'User-Agent': 'Stripe/v1 PythonBindings/%s' % (version.VERSION,), | |
'Authorization': 'Bearer %s' % (my_api_key,) | |
} | |
if api_version is not None: | |
headers['Stripe-Version'] = api_version | |
rbody, rcode = self._client.request( | |
method, abs_url, headers, post_data) | |
util.logger.info( | |
'API request to %s returned (response code, response body) of ' | |
'(%d, %r)', | |
abs_url, rcode, rbody) | |
return rbody, rcode, my_api_key | |
def interpret_response(self, rbody, rcode): | |
try: | |
if hasattr(rbody, 'decode'): | |
rbody = rbody.decode('utf-8') | |
resp = util.json.loads(rbody) | |
except Exception: | |
raise error.APIError( | |
"Invalid response body from API: %s " | |
"(HTTP response code was %d)" % (rbody, rcode), | |
rbody, rcode) | |
if not (200 <= rcode < 300): | |
self.handle_api_error(rbody, rcode, resp) | |
return resp | |
# Deprecated request handling. Will all be removed in 2.0 | |
def _deprecated_request(self, impl, method, url, headers, params): | |
warnings.warn( | |
'The *_request functions of APIRequestor are deprecated and ' | |
'will be removed in version 2.0. Please use the client classes ' | |
' in `stripe.http_client` instead', | |
DeprecationWarning, stacklevel=2) | |
method = method.lower() | |
if method == 'get' or method == 'delete': | |
if params: | |
url = self.build_url(url, params) | |
post_data = None | |
elif method == 'post': | |
post_data = self.encode(params) | |
else: | |
raise error.APIConnectionError( | |
'Unrecognized HTTP method %r. This may indicate a bug in the ' | |
'Stripe bindings. Please contact [email protected] for ' | |
'assistance.' % (method,)) | |
client = impl(verify_ssl_certs=self._client._verify_ssl_certs) | |
return client.request(method, url, headers, post_data) | |
def _deprecated_handle_error(self, impl, *args): | |
warnings.warn( | |
'The handle_*_error functions of APIRequestor are deprecated and ' | |
'will be removed in version 2.0. Please use the client classes ' | |
' in `stripe.http_client` instead', | |
DeprecationWarning, stacklevel=2) | |
client = impl(verify_ssl_certs=self._client._verify_ssl_certs) | |
return client._handle_request_error(*args) | |
def requests_request(self, meth, abs_url, headers, params): | |
from stripe.http_client import RequestsClient | |
return self._deprecated_request(RequestsClient, meth, abs_url, | |
headers, params) | |
def handle_requests_error(self, err): | |
from stripe.http_client import RequestsClient | |
return self._deprecated_handle_error(RequestsClient, err) | |
def pycurl_request(self, meth, abs_url, headers, params): | |
from stripe.http_client import PycurlClient | |
return self._deprecated_request(PycurlClient, meth, abs_url, | |
headers, params) | |
def handle_pycurl_error(self, err): | |
from stripe.http_client import PycurlClient | |
return self._deprecated_handle_error(PycurlClient, err) | |
def urlfetch_request(self, meth, abs_url, headers, params): | |
from stripe.http_client import UrlFetchClient | |
return self._deprecated_request(UrlFetchClient, meth, abs_url, | |
headers, params) | |
def handle_urlfetch_error(self, err, abs_url): | |
from stripe.http_client import UrlFetchClient | |
return self._deprecated_handle_error(UrlFetchClient, err, abs_url) | |
def urllib2_request(self, meth, abs_url, headers, params): | |
from stripe.http_client import Urllib2Client | |
return self._deprecated_request(Urllib2Client, meth, abs_url, | |
headers, params) | |
def handle_urllib2_error(self, err, abs_url): | |
from stripe.http_client import Urllib2Client | |
return self._deprecated_handle_error(Urllib2Client, err) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment