Skip to content

Commit

Permalink
merged
Browse files Browse the repository at this point in the history
  • Loading branch information
vladcalin committed Jan 9, 2017
2 parents 70057b3 + 872b04f commit d261225
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 20 deletions.
8 changes: 8 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@
- added the ``pymicroservice.PyMicroService.get_cli`` method
- improved documentation a little bit

0.0.4
=====

- fixed bug when sending a notification that would result in an error
was causing the microservice to respond abnormally (see #10)
- fixed a bug that was causing the service to never respond with the
invalid parameters status when calling a method with invalid parameters

0.0.3
=====

Expand Down
26 changes: 13 additions & 13 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import os
import sys
import pymicroservice

sys.path.insert(0, os.path.abspath('.'))

autoclass_content = 'both'
Expand Down Expand Up @@ -120,7 +121,6 @@
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = True


# -- Options for HTML output ----------------------------------------------

# The theme to use for HTML and HTML Help pages. See the documentation for
Expand Down Expand Up @@ -245,21 +245,21 @@
# -- Options for LaTeX output ---------------------------------------------

latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',

# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',

# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',

# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}

# Grouping the document tree into LaTeX files. List of tuples
Expand Down
3 changes: 1 addition & 2 deletions pymicroservice/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
from pymicroservice.core.handlers import TornadoJsonRpcHandler
from pymicroservice.client.remote_service import RemoteService


__author__ = "Vlad Calin"
__email__ = "[email protected]"

__version__ = "0.1.0"
__version__ = "0.1.0"
2 changes: 0 additions & 2 deletions pymicroservice/client/remote_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ def __call__(self, *args, **kwargs):
}
if self.req_id:
request_body["id"] = self.req_id

response = self.service.make_request_sync(self.url, json_body=request_body, headers=request_headers)

if not self.req_id:
Expand All @@ -44,7 +43,6 @@ def __call__(self, *args, **kwargs):
response = json.loads(response)
if response["error"]:
raise CalledServiceError(response["error"])

return response["result"]


Expand Down
25 changes: 22 additions & 3 deletions pymicroservice/core/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
'TornadoJsonRpcHandler'
]


class TornadoJsonRpcHandler(RequestHandler):
methods = None
executor = None
Expand Down Expand Up @@ -42,12 +43,17 @@ class _ErrorMessages:
INTERNAL_ERROR = "Internal error"
ACCESS_DENIED = "Access denied"

def __init__(self, *args, **kwargs):
self.request_is_finished = False
super(TornadoJsonRpcHandler, self).__init__(*args, **kwargs)

# noinspection PyMethodOverriding
def initialize(self, methods, executor, api_token_header, api_token_handler):
self.methods = methods
self.executor = executor
self.api_token_header = api_token_header
self.api_token_handler = api_token_handler
self.request_is_finished = False

@coroutine
def post(self):
Expand Down Expand Up @@ -126,6 +132,15 @@ def handle_single_request(self, single_request):
return
try:
result = yield self.call_method(method)
except TypeError as e:
# TODO: find a proper way to check that the function got the wrong parameters (with **kwargs)
if "got an unexpected keyword argument" in e.args[0]:
err = self.get_generic_jsonrpc_response(self._GenericErrorId.INVALID_PARAMS)
return self.make_response_dict(None, err, id_)
# TODO: find a proper way to check that the function got the wrong parameters (with *args)
if "takes" in e.args[0] and "positional argument" in e.args[0] and "were given" in e.args[0]:
err = self.get_generic_jsonrpc_response(self._GenericErrorId.INVALID_PARAMS)
return self.make_response_dict(None, err, id_)
except Exception as e:
err = self.get_generic_jsonrpc_response(self._GenericErrorId.INTERNAL_ERROR)
err["data"] = {
Expand Down Expand Up @@ -188,15 +203,19 @@ def write_response(self, result=None, error=None, id=None):
"""
Writes a json rpc response ``{"result": result, "error": error, "id": id}``.
If the ``id`` is ``None``, the response will not contain an ``id`` field.
The response is sent to the client as an ``application/json`` response.
The response is sent to the client as an ``application/json`` response. Only one call per
response is allowed
:param result: :py:class:`dict` representing the method call result, ``None`` if an error occurred.
:param error: :py:class:`dict` representing the error resulted in the method call, ``None`` if no error occurred
:param id: the ``id`` of the request that generated this response
:return:
"""
self.set_header("Content-Type", "application/json")
self.write(json.dumps(self.make_response_dict(result, error, id)))
if not self.request_is_finished:
self.set_header("Content-Type", "application/json")
self.write(json.dumps(self.make_response_dict(result, error, id)))
self.request_is_finished = True


def write_batch_response(self, *results):
self.set_header("Content-Type", "application/json")
Expand Down
60 changes: 60 additions & 0 deletions tests/test_jsonrpc_specs.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,46 @@ def test_bad_params_struct(self):
self.assertEqual(resp["error"]["code"], -32600)
self.assertEqual(resp["error"]["message"].lower(), "invalid request")

def test_bad_parameters_names(self):
payload = {
"jsonrpc": "2.0",
"id": 8,
"method": "test_method_params",
"params": {
"param_invalid_name": "invalid_name",
"param1": "test"
}
}
resp = self.fetch("/api", method="POST", headers={"Content-Type": "application/json"}, body=json.dumps(payload))
resp = json.loads(resp.body.decode())
self.assertEqual(resp["result"], None)
self.assertEqual(resp["id"], 8)
self.assertEqual(resp["jsonrpc"], "2.0")
self.assertEqual(resp["error"]["code"], -32602)
self.assertEqual(resp["error"]["message"].lower(), "invalid params")

def test_bad_parameters_count(self):
payload = {
"jsonrpc": "2.0",
"id": 8,
"method": "test_method_params",
"params": {
"param0": "invalid_name",
"param1": "test",
"param2": "test",
"param3": "test",
"param4": "test",
"param5": "test"
}
}
resp = self.fetch("/api", method="POST", headers={"Content-Type": "application/json"}, body=json.dumps(payload))
resp = json.loads(resp.body.decode())
self.assertEqual(resp["result"], None)
self.assertEqual(resp["id"], 8)
self.assertEqual(resp["jsonrpc"], "2.0")
self.assertEqual(resp["error"]["code"], -32602)
self.assertEqual(resp["error"]["message"].lower(), "invalid params")

def test_bad_jsonrpc_version(self):
payload = {
"jsonrpc": "1.0",
Expand Down Expand Up @@ -162,6 +202,26 @@ def test_notification(self):
self.assertEqual(resp["error"], None)
self.assertTrue("id" not in resp)

def test_notification_with_error(self):
"""
:return:
"""
payload = {
"jsonrpc": "2.0",
"id": None,
"method": "test_method_no_params",
"params": {
"param_1": True
}
}
resp = self.fetch("/api", method="POST", headers={"Content-Type": "application/json"}, body=json.dumps(payload))
resp = json.loads(resp.body.decode())
self.assertEqual(resp["jsonrpc"], "2.0")
self.assertEqual(resp["result"], "received")
self.assertEqual(resp["error"], None)
self.assertTrue("id" not in resp)

def test_public_method_with_no_params(self):
payload = {
"jsonrpc": "2.0",
Expand Down

0 comments on commit d261225

Please sign in to comment.