# -*- coding: utf-8 -*- # import os import json import simplejson import requests from requests.structures import CaseInsensitiveDict from .exception import RequestError, ResponseError, RegisterError from .url import API_URL_MAPPING from .utils import get_logger _USER_AGENT = 'jms-sdk-py' CACHED_TTL = os.environ.get('CACHED_TTL', 30) logger = get_logger(__file__) class HttpRequest(object): methods = { 'get': requests.get, 'post': requests.post, 'patch': requests.patch, 'put': requests.put, 'delete': requests.delete, } def __init__(self, url, method='get', data=None, params=None, headers=None, content_type='application/json', **kwargs): self.url = url self.method = method self.params = params or {} self.kwargs = kwargs if not isinstance(headers, dict): headers = {} self.headers = CaseInsensitiveDict(headers) if content_type: self.headers['Content-Type'] = content_type if data: self.data = json.dumps(data) else: self.data = {} def do(self): # logging.debug("{} {}: \n\tHeaders {}, \n\tData {}, \n\tParams {}, \n\tOther: {}".format( # self.method.upper(), self.url, self.headers, # self.data, self.params, self.kwargs # )) result = self.methods.get(self.method)( url=self.url, headers=self.headers, data=self.data, params=self.params, **self.kwargs ) return result class Http(object): def __init__(self, endpoint, auth=None, default_headers=None): self.auth = auth self.endpoint = endpoint self.default_headers = default_headers or {} def set_auth(self, auth): self.auth = auth def set_header(self, k, v): self.default_headers[k] = v @staticmethod def clean_result(resp): if resp.status_code >= 500: msg = "Response code is {0.status_code}: {0.text}".format(resp) logger.error(msg) raise ResponseError(msg) try: _ = resp.json() except (json.JSONDecodeError, simplejson.scanner.JSONDecodeError): msg = "Response json couldn't be decode: {0.text}".format(resp) logger.error(msg) raise ResponseError(msg) else: return resp def do(self, api_name=None, pk=None, method='get', use_auth=True, data=None, params=None, content_type='application/json', **kwargs): if api_name in API_URL_MAPPING: path = API_URL_MAPPING.get(api_name) if pk and '%s' in path: path = path % pk else: path = api_name request_headers = kwargs.get('headers', {}) default_headers = self.default_headers or {} headers = {k: v for k, v in default_headers.items()} headers.update(request_headers) kwargs['headers'] = headers url = self.endpoint.rstrip('/') + path req = HttpRequest(url, method=method, data=data, params=params, content_type=content_type, **kwargs) if use_auth: if not self.auth: msg = 'Authentication required, but not provide' logger.error(msg) raise RequestError(msg) else: self.auth.sign_request(req) try: resp = req.do() except (requests.ConnectionError, requests.ConnectTimeout) as e: msg = "Connect endpoint {} error: {}".format(self.endpoint, e) logger.error(msg) raise RequestError(msg) return self.clean_result(resp) def get(self, *args, **kwargs): kwargs['method'] = 'get' return self.do(*args, **kwargs) def post(self, *args, **kwargs): kwargs['method'] = 'post' return self.do(*args, **kwargs) def put(self, *args, **kwargs): kwargs['method'] = 'put' return self.do(*args, **kwargs) def patch(self, *args, **kwargs): kwargs['method'] = 'patch' return self.do(*args, **kwargs)