Skip to content

Commit

Permalink
Merge 72c7037 into 8f8a7e1
Browse files Browse the repository at this point in the history
  • Loading branch information
dpnova committed Jan 7, 2016
2 parents 8f8a7e1 + 72c7037 commit 902839d
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 6 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
language: python
python:
- "2.6"
- "2.7"
- "pypy"

Expand Down
37 changes: 33 additions & 4 deletions cyclone/jsonrpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,21 @@
class JsonrpcRequestHandler(RequestHandler):
"""Subclass this class and define jsonrpc_* to make a handler.
The response and request for your jsonrpc_* methods will be de/encoded with
JsonrpcRequestHandler.encoder. By default that is set to cyclone.escape
but you can override that for all JsonrpcRequestHandlers by setting it
at the class level, or in each subclass (see the example):
JsonrpcRequestHandler.encoder = myencoder
The only requirement of setting a custom encoder is that it has
two callable attributes: json_encode and json_decode.
Example::
class MyRequestHandler(JsonrpcRequestHandler):
encoder = MyCustomEncoder() # optional
def jsonrpc_echo(self, text):
return text
Expand All @@ -50,18 +62,35 @@ def jsonrpc_geoip_lookup(self, address):
response = yield cyclone.httpclient.fetch(
"http://freegeoip.net/json/%s" % address.encode("utf-8"))
defer.returnValue(response.body)
Example hybrid encoder::
class DateTimeAwareEncoder(object):
json_decode = lambda self, *args, **kwargs:\
cyclone.escape.json_decode(*args, **kwargs)
def default_encode(self, value):
if isinstance(value, datetime):
return value.isoformat()
json_encode = lambda self, *args, **kwargs:\
json.dumps(default=self.default_encode, *args, **kwargs)
"""

encoder = cyclone.escape

def post(self, *args):
self._auto_finish = False
try:
req = cyclone.escape.json_decode(self.request.body)
req = self.encoder.json_decode(self.request.body)
jsonid = req["id"]
method = req["method"]
assert isinstance(method, types.StringTypes), \
"Invalid method type: %s" % type(method)
"Invalid method type: %s" % type(method)
params = req.get("params", [])
assert isinstance(params, (types.ListType, types.TupleType)), \
"Invalid params type: %s" % type(params)
"Invalid params type: %s" % type(params)
except Exception, e:
log.msg("Bad Request: %s" % str(e))
raise HTTPError(400)
Expand All @@ -82,4 +111,4 @@ def _cbResult(self, result, jsonid):
else:
error = None
data = {"result": result, "error": error, "id": jsonid}
self.finish(cyclone.escape.json_encode(data))
self.finish(self.encoder.json_encode(data))
39 changes: 39 additions & 0 deletions cyclone/tests/test_jsonrpc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#
# Copyright 2014 David Novakovic
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

from twisted.trial import unittest
from mock import Mock
from cyclone.jsonrpc import JsonrpcRequestHandler
from cyclone.web import Application
import json


class TestJsonrpcRequestHandler(unittest.TestCase):

def setUp(self):
self.request = Mock()
self.app = Application()
self.handler = JsonrpcRequestHandler(self.app, self.request)
self.handler.finish = Mock()

def test_post(self):
self.handler.jsonrpc_foo = lambda: "value"
self.handler.request.body = '{"id":1, "method":"foo"}'
self.handler.post()
arg = self.handler.finish.call_args[0][0]
self.assertEqual(
json.loads(arg),
{"error": None, "id": 1, "result": "value"}
)
3 changes: 2 additions & 1 deletion cyclone/tests/test_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
mock
twisted>=12.0
twisted>=12.0
pyopenssl

0 comments on commit 902839d

Please sign in to comment.