diff --git a/.travis.yml b/.travis.yml index 63f7247..4fd7679 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,8 +16,8 @@ deploy: - LICENSE - kwikapi/api.py - kwikapi/__init__.py - name: kwikapi-0.4.4 - tag_name: 0.4.4 + name: kwikapi-0.4.5 + tag_name: 0.4.5 on: repo: deep-compute/kwikapi - provider: pypi diff --git a/README.md b/README.md index a3b94c3..798f3ba 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ True ## Features - Versioning support -- Type checking +- Type annotations - Namespace - Customizing request and response - Streaming @@ -171,7 +171,7 @@ True ``` -We can specify the default version so that when you don't mention version in the request URL then default version will be used. +We can specify the default version so that when you don't mention version in the request URL then the default version will be used. ```python >>> import json @@ -196,7 +196,7 @@ True ``` -### Type checking +### Type annotations Specifying type for parameters and for return value will exactly meet the functionality. This is mandatory in KwikAPI (If the method don't return anything then `None` should be specified as return type) ```python @@ -271,7 +271,7 @@ Here are some examples of how to use type hints. ``` -- If we don't need to bother about type checking then we can simply use Any from typing +- If we don't need to bother about type annotations then we can simply use Any from typing ```python >>> from typing import Any >>> class Calc(object): @@ -509,7 +509,7 @@ $ wget "http://localhost:8888/api/v1/add" --header="X-KwikAPI-Protocol: numpy" - ``` ### API Doc -Using API Doc we can look at what are the all API methods available +Using the API Doc we can look at what are the all API methods available To see available API methods the URL will be http://localhost:8888/api/v1/apidoc for default version @@ -585,7 +585,7 @@ bulk. ### KwikAPI Client `KwikAPI` provides client tool which will help in making calls to server. The `KwikAPI Client` will take -care of serialization and deserialization of the data. +care of the serialization and the deserialization of the data. Usage: ```python diff --git a/kwikapi/__init__.py b/kwikapi/__init__.py index d95a7af..9ac9763 100644 --- a/kwikapi/__init__.py +++ b/kwikapi/__init__.py @@ -1,7 +1,9 @@ from .api import API, BaseRequestHandler from .api import MockRequest, BaseRequest, BaseResponse, Request + from .protocols import BaseProtocol, JsonProtocol, MessagePackProtocol from .protocols import PickleProtocol, NumpyProtocol +from .protocols import PROTOCOLS from .client import Client, DNSCache from . import exception diff --git a/kwikapi/api.py b/kwikapi/api.py index 6e6ee74..7f77a7f 100644 --- a/kwikapi/api.py +++ b/kwikapi/api.py @@ -97,7 +97,6 @@ def write(self, data, protocol, stream=False): self._data = protocol.serialize(data) return C(len(self._data)), C(time.time() - t) - n = C(0) t = C(0.0) @@ -453,6 +452,24 @@ def _find_request_protocol(self, request): protocol = request.headers.get(PROTOCOL_HEADER, self.default_protocol) return self.PROTOCOLS[protocol] + def _handle_exception(self, req, e): + message = e.message if hasattr(e, 'message') else str(e) + message = '[(%s) %s: %s]' % (self.api._id, e.__class__.__name__, message) + + _log = req.log if hasattr(req, 'log') else self.log + _log.exception('handle_request_error', message=message, + __params=get_loggable_params(req.fn_params or {})) + + return message + + def _wrap_stream(self, req, res): + try: + for r in res: + yield dict(success=True, result=r) + except Exception as e: + m = self._handle_exception(req, e) + yield dict(success=False, message=m) + def handle_request(self, request): if self.api._auth: request.auth = self.api._auth.authenticate(request) @@ -474,6 +491,7 @@ def handle_request(self, request): # Serialize the response if request.fn.__func__.func_info['gives_stream']: + result = self._wrap_stream(request, result) n, t = response.write(result, protocol, stream=True) else: n, t = response.write(dict(success=True, result=result), protocol) @@ -487,13 +505,8 @@ def handle_request(self, request): **request.metrics) except Exception as e: - message = e.message if hasattr(e, 'message') else str(e) - message = '[(%s) %s: %s]' % (self.api._id, e.__class__.__name__, message) - - _log = request.log if hasattr(request, 'log') else self.log - _log.exception('handle_request_error', message=message, - __params=get_loggable_params(request.fn_params or {})) - response.write(dict(success=False, message=message), protocol) + m = self._handle_exception(request, e) + response.write(dict(success=False, message=m), protocol) response.flush() response.close() diff --git a/kwikapi/client.py b/kwikapi/client.py index 7030492..48e589b 100644 --- a/kwikapi/client.py +++ b/kwikapi/client.py @@ -111,6 +111,7 @@ def _make_request(self, url, post_body, headers): if self._stream: proto = PROTOCOLS[self._protocol] res = proto.deserialize_stream(res) + res = Client._extract_stream_response(res) else: res = self._deserialize_response(res.read(), self._protocol) @@ -126,12 +127,17 @@ def _deserialize_response(data, protocol): def _extract_response(r): success = r['success'] if not success: - r = Exception(r['message']) # FIXME: raise proper exc + raise Exception(r['message']) # FIXME: raise proper exc else: r = r['result'] return r + @staticmethod + def _extract_stream_response(res): + for r in res: + yield Client._extract_response(r) + @staticmethod def _serialize_params(params, protocol): proto = PROTOCOLS[protocol] @@ -144,6 +150,7 @@ def __call__(self, *args, **kwargs): if self._path: # FIXME: support streaming in both directions _kwargs = get_loggable_params(kwargs or {}) + self._log.debug('kwikapi.client.__call__', path=self._path, kwargs=_kwargs, url=self._url, version=self._version, protocol=self._protocol) @@ -152,10 +159,8 @@ def __call__(self, *args, **kwargs): url, post_body, headers = self._prepare_request(post_body) res = self._make_request(url, post_body, headers) - if isinstance(res, Exception): - raise res - else: - return res + return res + else: return self._copy(**kwargs) diff --git a/setup.py b/setup.py index 5ddf68b..11e6a64 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ from setuptools import setup, find_packages -version = '0.4.4' +version = '0.4.5' setup( name="kwikapi", version=version, @@ -21,9 +21,9 @@ 'requests==2.18.4', ], extras_require={ - 'django': ['kwikapi-django==0.2.3'], - 'tornado': ['kwikapi-tornado==0.3'], - 'all': ['kwikapi-django==0.2.3', 'kwikapi-tornado==0.3'] + 'django': ['kwikapi-django==0.2.5'], + 'tornado': ['kwikapi-tornado==0.3.1'], + 'all': ['kwikapi-django==0.2.5', 'kwikapi-tornado==0.3.1'] }, classifiers=[ 'Environment :: Web Environment',