Coverage for beyonic.api_client: 66%

# Coverage for beyonic.api_client : 66%

## 116 statements 77 run 39 missing 0 excluded

Hot-keys on this page

r m x p toggle line displays

j k next/prev highlighted chunk

0 (zero) top of page

1 (one) first highlighted chunk

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | ''' # This return the api client. It should first check if requests is installed, if its installed then returns RequestsClient, # if requests is not installed then check for urlfetch lib, if its installed then return its client UrlfetchClient # if both of them not installed then throws the exception ''' import textwrap from beyonic.errors import BeyonicError, ResponseError from beyonic.resources import GenericObject import os # let's try to import requests if its available try: import requests except ImportError: requests = None # let's try to import urlfetch try: from google.appengine.api import urlfetch except ImportError: urlfetch = None class BaseClient(object): def __init__(self, verify_ssl_certs=True): self._verify_ssl_certs = verify_ssl_certs class RequestsClient(BaseClient): name = 'requests' def request(self, method, url, headers, params=None): if not requests: raise BeyonicError('requests is not installed. Please install/setup it first using pip. e.g. pip install requests>=1.0') kwargs = {} if self._verify_ssl_certs: kwargs['verify'] = True else: kwargs['verify'] = False try: try: if method.upper() == 'GET': result = requests.request(method, url, headers=headers, params=params, timeout=80, **kwargs) else: result = requests.request(method, url, headers=headers, data=params, timeout=80, **kwargs) except TypeError, e: raise TypeError( 'Please upgrade your request library. The ' 'underlying error was: %s' % (e,)) content = result.content status_code = result.status_code except Exception, e: # Would catch just requests.exceptions.RequestException, but can # also raise ValueError, RuntimeError, etc. self._handle_request_error(e) return content, status_code def _handle_request_error(self, e): msg = ("Unexpected error communicating with Beyonic API.") err = "A %s was raised" % (type(e).__name__,) if str(e): err += " with error message %s" % (str(e),) else: err += " with no error message" msg = textwrap.fill(msg) + "\n\n(error: %s)" % (err,) raise BeyonicError(msg) class UrlFetchClient(BaseClient): name = 'urlfetch' def request(self, method, url, headers, params=None): if not urlfetch: raise BeyonicError('urlfetch is not installed. Please install/setup it first.') try: result = urlfetch.fetch( url=url, method=method, headers=headers, validate_certificate=self._verify_ssl_certs, deadline=55, payload=params ) except urlfetch.Error, e: self._handle_request_error(e, url) return result.content, result.status_code def _handle_request_error(self, e, url): if isinstance(e, urlfetch.InvalidURLError): msg = ("Unexpected error communicating with Beyonic API.") elif isinstance(e, urlfetch.DownloadError): msg = "There was a problem retrieving data from Beyonic." elif isinstance(e, urlfetch.ResponseTooLargeError): msg = ("Unexpected error communicating with Beyonic API.") else: msg = ("Unexpected error communicating with Beyonic API.") msg = textwrap.fill(msg) + "\n\n(error: " + str(e) + ")" raise BeyonicError(msg) def get_default_http_client(*args, **kwargs): if urlfetch: impl = UrlFetchClient elif requests: impl = RequestsClient else: # none of them is available so let's throw an error raise BeyonicError( 'Either of requests or urlfetch is not installed. Please install either of them using requirements.txt') return impl(*args, **kwargs) ''' 'API Client class interacts with api using available RequestClient or UrlFetchClient ''' class ApiClient(object): """ A client for the api """ def __init__(self, api_key=None, url=None, client=None, verify_ssl_certs=True, api_version=None): # if not passed then let's try to get it from env variable if not api_key: try: api_key = os.environ['BEYONIC_ACCESS_KEY'] except KeyError: raise BeyonicError('BEYONIC_ACCESS_KEY not set.') self._api_key = api_key self._api_version = api_version if not url: raise BeyonicError('Base url can\'t be empty. You should set base url using beyonic.api_endpoint_base') self._url = url self._client = client or get_default_http_client(verify_ssl_certs=verify_ssl_certs) def set_url(self, url): self._url = url def get(self, **kwargs): ''' Makes an HTTP GET request to the API. Any keyword arguments will be converted to query string parameters. ''' return self._request("get", **kwargs) def post(self, **kwargs): ''' Makes an HTTP POST request to the API. ''' return self._request("post", **kwargs) def put(self, **kwargs): ''' Makes an HTTP PUT request to the API. ''' return self._request("put", **kwargs) def patch(self, **kwargs): ''' Makes an HTTP patch request to the API. ''' return self._request("patch", **kwargs) def delete(self, **kwargs): ''' Makes an HTTP DELETE request to the API. ''' return self._request("delete", **kwargs) def _request(self, method, **kwargs): response_content, status_code = self._client.request( method=method, url=self._url, headers=self._build_headers(), params=kwargs, ) return self._parse_response(response_content, status_code) def _build_headers(self): headers = {} if self._api_key: headers.update({"Authorization": "Token %s" % self._api_key, }) if self._api_version: headers.update({"Beyonic-Version": self._api_version, }) return headers def _parse_response(self, response_content, status_code): # TODO: need exact status code for different type error if 200 <= status_code < 300: return self._value_for_response(response_content, status_code) else: raise self._exception_for_response(response_content, status_code) def _value_for_response(self, response_content, status_code): #status_code 204 is for delete so for it retruning True if response_content and status_code != 204: return GenericObject.from_json(response_content) else: return True def _exception_for_response(self, response_content, status_code): # TODO need to handle the all the status return ResponseError("%d error: %s" % (status_code, response_content,))