Permalink
Browse files

PyFlakes, adding Travis.

  • Loading branch information...
1 parent ea6a8f3 commit 00aea69d3f7e72630c5ab0b322d72e645a32ae25 @joshmarshall committed Jan 25, 2014
Showing with 336 additions and 338 deletions.
  1. +3 −0 .gitignore
  2. +3 −0 .travis.yml
  3. +1 −0 README.md
  4. +5 −0 requirements.txt
  5. +0 −12 run_tests.py
  6. +20 −19 setup.py
  7. +93 −0 tests/helpers.py
  8. +0 −32 tests/json.py
  9. +35 −0 tests/test_json.py
  10. +23 −22 tests/{utils.py → test_utils.py}
  11. +71 −0 tests/test_xml.py
  12. +0 −151 tests/xml.py
  13. +56 −55 tornadorpc/base.py
  14. +14 −24 tornadorpc/json.py
  15. +5 −5 tornadorpc/utils.py
  16. +7 −18 tornadorpc/xml.py
View
3 .gitignore
@@ -1,2 +1,5 @@
*.pyc
+*.swp
+*.swo
build/
+.venv
View
3 .travis.yml
@@ -0,0 +1,3 @@
+language: python
+install: pip install -r requirements.txt
+script: nosetests tests/
View
1 README.md
@@ -1,3 +1,4 @@
+[![Build Status](https://travis-ci.org/joshmarshall/tornadorpc.png?branch=master)](https://travis-ci.org/joshmarshall/tornadorpc)
TORNADO-RPC
===========
This library is an implementation of both the JSON-RPC and the
View
5 requirements.txt
@@ -0,0 +1,5 @@
+backports.ssl-match-hostname==3.4.0.2
+jsonrpclib==0.1.3
+nose==1.3.0
+tornado==3.2
+wsgiref==0.1.2
View
12 run_tests.py
@@ -1,12 +0,0 @@
-import unittest
-from tests.utils import *
-import sys
-
-if __name__ == "__main__":
- if '--json' in sys.argv:
- sys.argv.pop(sys.argv.index('--json'))
- from tests.json import *
- else:
- from tests.xml import *
-
- unittest.main()
View
39 setup.py
@@ -1,29 +1,30 @@
#!/usr/bin/env/python
"""
-Copyright 2009 Josh Marshall
-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
+Copyright 2009 Josh Marshall
+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
+ 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.
+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.
"""
import distutils.core
distutils.core.setup(
- name = "tornadorpc",
- version = "0.1",
- packages = ["tornadorpc"],
- author = "Josh Marshall",
- author_email = "catchjosh@gmail.com",
- url = "http://code.google.com/p/tornadorpc/",
- license = "http://www.apache.org/licenses/LICENSE-2.0",
- description = "TornadoRPC is a an implementation of both JSON-RPC " +
- "and XML-RPC handlers for the Tornado framework.",
+ name="tornadorpc",
+ version="0.1.1",
+ packages=["tornadorpc"],
+ author="Josh Marshall",
+ install_requires=["tornado", "jsonrpclib"],
+ author_email="catchjosh@gmail.com",
+ url="http://code.google.com/p/tornadorpc/",
+ license="http://www.apache.org/licenses/LICENSE-2.0",
+ description="TornadoRPC is a an implementation of both JSON-RPC "
+ "and XML-RPC handlers for the Tornado framework."
)
View
93 tests/helpers.py
@@ -0,0 +1,93 @@
+import threading
+import time
+from tornado.httpclient import AsyncHTTPClient
+from tornadorpc import start_server, private, async
+
+
+class Tree(object):
+
+ def power(self, base, power, modulo=None):
+ result = pow(base, power, modulo)
+ return result
+
+ def _private(self):
+ # Should not be callable
+ return False
+
+
+class TestHandler(object):
+
+ tree = Tree()
+
+ def add(self, x, y):
+ return x+y
+
+ @async
+ def async(self, url):
+ async_client = AsyncHTTPClient()
+ async_client.fetch(url, self._handle_response)
+
+ def _handle_response(self, response):
+ self.result(response.code)
+
+ @private
+ def private(self):
+ # Should not be callable
+ return False
+
+ def _private(self):
+ # Should not be callable
+ return False
+
+ def internal_error(self):
+ raise Exception("Yar matey!")
+
+
+class TestServer(object):
+
+ threads = {}
+
+ @classmethod
+ def start(cls, handler, port):
+ if not cls.threads.get(port):
+ cls.threads[port] = threading.Thread(
+ target=start_server,
+ args=[handler],
+ kwargs={'port': port}
+ )
+ cls.threads[port].daemon = True
+ cls.threads[port].start()
+ # Giving it time to start up
+ time.sleep(1)
+
+
+class RPCTests(object):
+
+ server = None
+ handler = None
+ port = 8002
+
+ def setUp(self):
+ self.server = TestServer.start(self.handler, self.port)
+
+ def get_url(self):
+ return 'http://localhost:%d' % self.port
+
+ def get_client(self):
+ raise NotImplementedError("Must return an XML / JSON RPC client.")
+
+ def test_tree(self):
+ client = self.get_client()
+ result = client.tree.power(2, 6)
+ self.assertEqual(result, 64)
+
+ def test_add(self):
+ client = self.get_client()
+ result = client.add(5, 6)
+ self.assertEqual(result, 11)
+
+ def test_async(self):
+ url = 'http://www.google.com'
+ client = self.get_client()
+ result = client.async(url)
+ self.assertEqual(result, 200)
View
32 tests/json.py
@@ -1,32 +0,0 @@
-from tests.xml import TestHandler, RPCTests
-from tornadorpc.json import JSONRPCHandler
-import jsonrpclib
-import unittest
-
-class TestJSONHandler(TestHandler, JSONRPCHandler):
- def testOrder(self, a=1, b=2, c=3):
- return {'a': a, 'b': b, 'c': c}
-
-class JSONRPCTests(RPCTests, unittest.TestCase):
- port = 8003
- handler = TestJSONHandler
-
- def get_client(self):
- client = jsonrpclib.Server('http://localhost:%d' % self.port)
- return client
-
- def test_private(self):
- client = self.get_client()
- self.assertRaises(jsonrpclib.ProtocolError, client.private)
-
- def test_order(self):
- client = self.get_client()
- self.assertEqual(client.testOrder(),
- {'a': 1, 'b': 2, 'c': 3})
- self.assertEqual(client.testOrder(a=10),
- {'a': 10, 'b': 2, 'c': 3})
- self.assertEqual(client.testOrder(c=10),
- {'a': 1, 'b': 2, 'c': 10})
- self.assertEqual(client.testOrder(a=10,b=11,c=12),
- {'a': 10, 'b': 11, 'c': 12})
-
View
35 tests/test_json.py
@@ -0,0 +1,35 @@
+from tests.helpers import TestHandler, RPCTests
+from tornadorpc.json import JSONRPCHandler
+import jsonrpclib
+import unittest
+
+
+class JSONTestHandler(TestHandler, JSONRPCHandler):
+
+ def order(self, a=1, b=2, c=3):
+ return {'a': a, 'b': b, 'c': c}
+
+
+class JSONRPCTests(RPCTests, unittest.TestCase):
+
+ port = 8003
+ handler = JSONTestHandler
+
+ def get_client(self):
+ client = jsonrpclib.Server('http://localhost:%d' % self.port)
+ return client
+
+ def test_private(self):
+ client = self.get_client()
+ self.assertRaises(jsonrpclib.ProtocolError, client.private)
+
+ def test_order(self):
+ client = self.get_client()
+ self.assertEqual(
+ client.order(), {'a': 1, 'b': 2, 'c': 3})
+ self.assertEqual(
+ client.order(a=10), {'a': 10, 'b': 2, 'c': 3})
+ self.assertEqual(
+ client.order(c=10), {'a': 1, 'b': 2, 'c': 10})
+ self.assertEqual(
+ client.order(a=10, b=11, c=12), {'a': 10, 'b': 11, 'c': 12})
View
45 tests/utils.py → tests/test_utils.py
@@ -1,71 +1,72 @@
import unittest
from tornadorpc.utils import getcallargs
+
class TestCallArgs(unittest.TestCase):
""" Tries various argument settings """
def test_no_args(self):
def test():
pass
kwargs, xtra = getcallargs(test)
- self.assertTrue(kwargs == {})
- self.assertTrue(xtra == [])
-
+ self.assertEqual(kwargs, {})
+ self.assertEqual(xtra, [])
+
def test_bad_no_args(self):
def test():
pass
self.assertRaises(TypeError, getcallargs, test, 5)
-
+
def test_positional_args(self):
def test(a, b):
pass
kwargs, xtra = getcallargs(test, 5, 6)
- self.assertTrue(kwargs == {'a':5, 'b': 6})
- self.assertTrue(xtra == [])
-
+ self.assertEqual(kwargs, {'a': 5, 'b': 6})
+ self.assertEqual(xtra, [])
+
def test_extra_positional_args(self):
def test(a, b, *args):
pass
kwargs, xtra = getcallargs(test, 5, 6, 7, 8)
- self.assertTrue(kwargs == {'a': 5, 'b': 6})
- self.assertTrue(xtra == [7, 8])
-
+ self.assertEqual(kwargs, {'a': 5, 'b': 6})
+ self.assertEqual(xtra, [7, 8])
+
def test_bad_positional_args(self):
def test(a, b):
pass
self.assertRaises(TypeError, getcallargs, test, 5)
-
+
def test_keyword_args(self):
def test(a, b):
pass
kwargs, xtra = getcallargs(test, a=5, b=6)
- self.assertTrue(kwargs == {'a': 5, 'b':6})
- self.assertTrue(xtra == [])
+ self.assertEqual(kwargs, {'a': 5, 'b': 6})
+ self.assertEqual(xtra, [])
def test_extra_keyword_args(self):
def test(a, b, **kwargs):
pass
kwargs, xtra = getcallargs(test, a=5, b=6, c=7, d=8)
- self.assertTrue(kwargs == {'a':5, 'b':6, 'c':7, 'd':8})
- self.assertTrue(xtra == [])
-
+ self.assertEqual(kwargs, {'a': 5, 'b': 6, 'c': 7, 'd': 8})
+ self.assertEqual(xtra, [])
+
def test_bad_keyword_args(self):
def test(a, b):
pass
self.assertRaises(TypeError, getcallargs, test, a=1, b=2, c=5)
-
+
def test_method(self):
class Foo(object):
def test(myself, a, b):
pass
foo = Foo()
kwargs, xtra = getcallargs(foo.test, 5, 6)
- self.assertTrue(kwargs == {'a':5, 'b':6})
- self.assertTrue(xtra == [])
-
+ self.assertEqual(kwargs, {'a': 5, 'b': 6})
+ self.assertEqual(xtra, [])
+
def test_default(self):
def test(a, b, default=None):
pass
kwargs, xtra = getcallargs(test, a=5, b=6)
- self.assertTrue(kwargs == {'a':5, 'b':6, 'default':None})
- self.assertTrue(xtra == [])
+ self.assertEqual(kwargs, {'a': 5, 'b': 6, 'default': None})
+ self.assertEqual(xtra, [])
View
71 tests/test_xml.py
@@ -0,0 +1,71 @@
+import unittest
+import xmlrpclib
+import urllib2
+from tornadorpc.xml import XMLRPCHandler
+
+from tests.helpers import TestHandler, RPCTests
+
+
+class XMLTestHandler(XMLRPCHandler, TestHandler):
+
+ def return_fault(self, code, msg):
+ return xmlrpclib.Fault(code, msg)
+
+
+class XMLRPCTests(RPCTests, unittest.TestCase):
+
+ handler = XMLTestHandler
+
+ def get_client(self):
+ client = xmlrpclib.ServerProxy(self.get_url())
+ return client
+
+ def test_private(self):
+ client = self.get_client()
+ try:
+ client.private()
+ self.fail('xmlrpclib.Fault should have been raised')
+ except xmlrpclib.Fault, f:
+ self.assertEqual(-32601, f.faultCode)
+
+ def test_private_by_underscore(self):
+ client = self.get_client()
+ try:
+ client._private()
+ self.fail('xmlrpclib.Fault should have been raised')
+ except xmlrpclib.Fault, f:
+ self.assertEqual(-32601, f.faultCode)
+
+ def test_invalid_params(self):
+ client = self.get_client()
+ try:
+ client.return_fault('a', 'b', 'c')
+ self.fail('xmlrpclib.Fault should have been raised')
+ except xmlrpclib.Fault, f:
+ self.assertEqual(-32602, f.faultCode)
+
+ def test_internal_error(self):
+ client = self.get_client()
+ try:
+ client.internal_error()
+ self.fail('xmlrpclib.Fault should have been raised')
+ except xmlrpclib.Fault, f:
+ self.assertEqual(-32603, f.faultCode)
+
+ def test_parse_error(self):
+ try:
+ print self.get_url()
+ urllib2.urlopen(self.get_url(), '<garbage/>')
+ except xmlrpclib.Fault, f:
+ self.assertEqual(-32700, f.faultCode)
+
+ def test_handler_return_fault(self):
+ client = self.get_client()
+ fault_code = 100
+ fault_string = 'Yar matey!'
+ try:
+ client.return_fault(fault_code, fault_string)
+ self.fail('xmlrpclib.Fault should have been raised')
+ except xmlrpclib.Fault, f:
+ self.assertEqual(fault_code, f.faultCode)
+ self.assertEqual(fault_string, f.faultString)
View
151 tests/xml.py
@@ -1,151 +0,0 @@
-import unittest
-import xmlrpclib
-import urllib2
-import time
-import threading
-from tornadorpc.xml import XMLRPCHandler
-from tornado.httpclient import AsyncHTTPClient
-from tornadorpc import start_server, private, async
-
-class Tree(object):
-
- def power(self, base, power, modulo=None):
- result = pow(base, power, modulo)
- return result
-
- def _private(self):
- # Should not be callable
- return False
-
-class TestHandler(object):
-
- tree = Tree()
-
- def add(self, x, y):
- return x+y
-
- @async
- def async(self, url):
- async_client = AsyncHTTPClient()
- async_client.fetch(url, self._handle_response)
-
- def _handle_response(self, response):
- self.result(response.code)
-
- @private
- def private(self):
- # Should not be callable
- return False
-
- def _private(self):
- # Should not be callable
- return False
-
- def internal_error(self):
- raise Exception("Yar matey!")
-
-class TestXMLHandler(XMLRPCHandler, TestHandler):
-
- def return_fault(self, code, msg):
- return xmlrpclib.Fault(code, msg)
-
-class TestServer(object):
-
- threads = {}
-
- @classmethod
- def start(cls, handler, port):
- if not cls.threads.get(port):
- cls.threads[port] = threading.Thread(
- target=start_server,
- args=[handler,],
- kwargs={'port':port}
- )
- cls.threads[port].daemon = True
- cls.threads[port].start()
- # Giving it time to start up
- time.sleep(1)
-
-class RPCTests(object):
-
- server = None
- handler = TestXMLHandler
- port = 8002
-
- def setUp(self):
- server = TestServer.start(self.handler, self.port)
-
- def get_url(self):
- return 'http://localhost:%d' % self.port
-
- def get_client(self):
- client = xmlrpclib.ServerProxy(self.get_url())
- return client
-
- def test_tree(self):
- client = self.get_client()
- result = client.tree.power(2, 6)
- self.assertTrue(result == 64)
-
- def test_add(self):
- client = self.get_client()
- result = client.add(5, 6)
- self.assertTrue(result == 11)
-
- def test_async(self):
- url = 'http://www.google.com'
- client = self.get_client()
- result = client.async(url)
- self.assertTrue(result == 200)
-
-class XMLRPCTests(RPCTests, unittest.TestCase):
-
- def test_private(self):
- client = self.get_client()
- try:
- client.private()
- self.fail('xmlrpclib.Fault should have been raised')
- except xmlrpclib.Fault, f:
- self.assertEqual(-32601, f.faultCode)
-
- def test_private_by_underscore(self):
- client = self.get_client()
- try:
- client._private()
- self.fail('xmlrpclib.Fault should have been raised')
- except xmlrpclib.Fault, f:
- self.assertEqual(-32601, f.faultCode)
-
- def test_invalid_params(self):
- client = self.get_client()
- try:
- client.return_fault('a', 'b', 'c')
- self.fail('xmlrpclib.Fault should have been raised')
- except xmlrpclib.Fault, f:
- self.assertEqual(-32602, f.faultCode)
-
- def test_internal_error(self):
- client = self.get_client()
- try:
- client.internal_error()
- self.fail('xmlrpclib.Fault should have been raised')
- except xmlrpclib.Fault, f:
- self.assertEqual(-32603, f.faultCode)
-
- def test_parse_error(self):
- try:
- print self.get_url()
- urllib2.urlopen(self.get_url(), '<garbage/>')
- except xmlrpclib.Fault, f:
- self.assertEqual(-32700, f.faultCode)
-
- def test_handler_return_fault(self):
- client = self.get_client()
- fault_code = 100
- fault_string = 'Yar matey!'
- try:
- client.return_fault(fault_code, fault_string)
- self.fail('xmlrpclib.Fault should have been raised')
- except xmlrpclib.Fault, f:
- self.assertEqual(fault_code, f.faultCode)
- self.assertEqual(fault_string, f.faultString)
View
111 tornadorpc/base.py
@@ -1,26 +1,14 @@
"""
-Copyright 2009 Josh Marshall
-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.
-
============================
-Base RPC Handler for Tornado
+Base RPC Handler for Tornado
============================
-This is a basic server implementation, designed for use within the
+This is a basic server implementation, designed for use within the
Tornado framework. The classes in this library should not be used
directly, but rather though the XML or JSON RPC implementations.
You can use the utility functions like 'private' and 'start_server'.
"""
+import logging
from tornado.web import RequestHandler
import tornado.web
import tornado.ioloop
@@ -29,6 +17,7 @@
import traceback
from tornadorpc.utils import getcallargs
+
# Configuration element
class Config(object):
verbose = True
@@ -40,9 +29,9 @@ class Config(object):
class BaseRPCParser(object):
"""
This class is responsible for managing the request, dispatch,
- and response formatting of the system. It is tied into the
- _RPC_ attribute of the BaseRPCHandler (or subclasses) and
- populated as necessary throughout the request. Use the
+ and response formatting of the system. It is tied into the
+ _RPC_ attribute of the BaseRPCHandler (or subclasses) and
+ populated as necessary throughout the request. Use the
.faults attribute to take advantage of the built-in error
codes.
"""
@@ -80,11 +69,12 @@ def run(self, handler, request_body):
except:
self.traceback()
return self.handler.result(self.faults.parse_error())
- if type(requests) is not types.TupleType:
+ if not isinstance(requests, types.TupleType):
# SHOULD be the result of a fault call,
# according tothe parse_request spec below.
- if type(requests) in types.StringTypes:
+ if isinstance(requests, basestring):
# Should be the response text of a fault
+ # This will break in Python 3.x
return requests
elif hasattr(requests, 'response'):
# Fault types should have a 'response' method
@@ -101,14 +91,14 @@ def run(self, handler, request_body):
self.handler._requests = len(requests)
for request in requests:
self.dispatch(request[0], request[1])
-
+
def dispatch(self, method_name, params):
"""
- This method walks the attribute tree in the method
+ This method walks the attribute tree in the method
and passes the parameters, either in positional or
keyword form, into the appropriate method on the
Handler class. Currently supports only positional
- or keyword arguments, not mixed.
+ or keyword arguments, not mixed.
"""
if method_name in dir(RequestHandler):
# Pre-existing, not an implemented attribute
@@ -131,7 +121,7 @@ def dispatch(self, method_name, params):
return self.handler.result(self.faults.method_not_found())
args = []
kwargs = {}
- if type(params) is types.DictType:
+ if isinstance(params, dict):
# The parameters are keyword-based
kwargs = params
elif type(params) in (list, tuple):
@@ -150,25 +140,25 @@ def dispatch(self, method_name, params):
except Exception:
self.traceback(method_name, params)
return self.handler.result(self.faults.internal_error())
-
+
if 'async' in dir(method) and method.async:
# Asynchronous response -- the method should have called
# self.result(RESULT_VALUE)
- if response != None:
+ if response is not None:
# This should be deprecated to use self.result
message = "Async results should use 'self.result()'"
message += " Return result will be ignored."
logging.warning(message)
else:
# Synchronous result -- we call result manually.
return self.handler.result(response)
-
+
def response(self, handler):
- """
+ """
This is the callback for a single finished dispatch.
Once all the dispatches have been run, it calls the
parser library to parse responses and then calls the
- handler's asynch method.
+ handler's async method.
"""
handler._requests -= 1
if handler._requests > 0:
@@ -183,7 +173,7 @@ def response(self, handler):
if type(response_text) not in types.StringTypes:
# Likely a fault, or something messed up
response_text = self.encode(response_text)
- # Calling the asynch callback
+ # Calling the async callback
handler.on_result(response_text)
def traceback(self, method_name='REQUEST', params=[]):
@@ -193,7 +183,7 @@ def traceback(self, method_name='REQUEST', params=[]):
err_title = '%s - (PARAMS: %s)' % (err_title, repr(params))
err_sep = ('-'*len(err_title))[:79]
err_lines = [err_sep, err_title, err_sep]+err_lines
- if config.verbose == True:
+ if config.verbose:
if len(err_lines) >= 7 and config.short_errors:
# Minimum number of lines to see what happened
# Plus title and separators
@@ -207,7 +197,7 @@ def parse_request(self, request_body):
"""
Extend this on the implementing protocol. If it
should error out, return the output of the
- 'self.faults.fault_name' response. Otherwise,
+ 'self.faults.fault_name' response. Otherwise,
it MUST return a TUPLE of TUPLE. Each entry
tuple must have the following structure:
('method_name', params)
@@ -218,28 +208,30 @@ def parse_request(self, request_body):
( ('add', [5,4]), ('add', {'x':5, 'y':4}) )
"""
return ([], [])
-
+
def parse_responses(self, responses):
"""
- Extend this on the implementing protocol. It must
- return a response that can be returned as output to
+ Extend this on the implementing protocol. It must
+ return a response that can be returned as output to
the client.
"""
- return self.encode(responses, methodresponse = True)
+ return self.encode(responses, methodresponse=True)
def check_method(self, attr_name, obj):
"""
- Just checks to see whether an attribute is private
- (by the decorator or by a leading underscore) and
+ Just checks to see whether an attribute is private
+ (by the decorator or by a leading underscore) and
returns boolean result.
"""
if attr_name.startswith('_'):
raise AttributeError('Private object or method.')
attr = getattr(obj, attr_name)
- if 'private' in dir(attr) and attr.private == True:
+
+ if 'private' in dir(attr) and attr.private:
raise AttributeError('Private object or method.')
return attr
+
class BaseRPCHandler(RequestHandler):
"""
This is the base handler to be subclassed by the actual
@@ -249,29 +241,30 @@ class BaseRPCHandler(RequestHandler):
_results = None
_requests = 0
_RPC_finished = False
-
+
@tornado.web.asynchronous
def post(self):
# Very simple -- dispatches request body to the parser
# and returns the output
self._results = []
request_body = self.request.body
self._RPC_.run(self, request_body)
-
+
def result(self, result, *results):
""" Use this to return a result. """
if results:
- results = [result,]+results
+ results = [result] + results
else:
results = result
self._results.append(results)
self._RPC_.response(self)
-
+
def on_result(self, response_text):
""" Asynchronous callback. """
self.set_header('Content-Type', self._RPC_.content_type)
self.finish(response_text)
-
+
+
class FaultMethod(object):
"""
This is the 'dynamic' fault method so that the message can
@@ -287,23 +280,24 @@ def __call__(self, message=None):
self.message = message
return self.fault(self.code, self.message)
+
class Faults(object):
"""
This holds the codes and messages for the RPC implementation.
It is attached (dynamically) to the Parser when called via the
parser.faults query, and returns a FaultMethod to be called so
that the message can be changed. If the 'dynamic' attribute is
not a key in the codes list, then it will error.
-
+
USAGE:
parser.fault.parse_error('Error parsing content.')
-
+
If no message is passed in, it will check the messages dictionary
for the same key as the codes dict. Otherwise, it just prettifies
the code 'key' from the codes dict.
-
+
"""
- codes = {
+ codes = {
'parse_error': -32700,
'method_not_found': -32601,
'invalid_request': -32600,
@@ -312,13 +306,13 @@ class Faults(object):
}
messages = {}
-
+
def __init__(self, parser, fault=None):
self.library = parser.library
self.fault = fault
if not self.fault:
self.fault = getattr(self.library, 'Fault')
-
+
def __getattr__(self, attr):
message = 'Error'
if attr in self.messages.keys():
@@ -328,21 +322,24 @@ def __getattr__(self, attr):
fault = FaultMethod(self.fault, self.codes[attr], message)
return fault
+
"""
Utility Functions
"""
+
def private(func):
"""
Use this to make a method private.
It is intended to be used as a decorator.
If you wish to make a method tree private, just
- create and set the 'private' variable to True
+ create and set the 'private' variable to True
on the tree object itself.
"""
func.private = True
return func
-
+
+
def async(func):
"""
Use this to make a method asynchronous
@@ -354,6 +351,7 @@ def async(func):
func.async = True
return func
+
def start_server(handlers, route=r'/', port=8080):
"""
This is just a friendly wrapper around the default
@@ -364,7 +362,7 @@ def start_server(handlers, route=r'/', port=8080):
"""
if type(handlers) not in (types.ListType, types.TupleType):
handler = handlers
- handlers = [(route, handler),]
+ handlers = [(route, handler)]
if route != '/RPC2':
# friendly addition for /RPC2 if it's the only one
handlers.append(('/RPC2', handler))
@@ -375,17 +373,19 @@ def start_server(handlers, route=r'/', port=8080):
""" Setting the '_server' attribute if not set """
for (route, handler) in handlers:
try:
- server_attrib = setattr(handler, '_server', loop_instance)
+ setattr(handler, '_server', loop_instance)
except AttributeError:
handler._server = loop_instance
loop_instance.start()
return loop_instance
+
"""
The following is a test implementation which should work
for both the XMLRPC and the JSONRPC clients.
"""
+
class TestMethodTree(object):
def power(self, x, y=2):
return pow(x, y)
@@ -395,6 +395,7 @@ def private(self):
# Shouldn't be called
return False
+
class TestRPCHandler(BaseRPCHandler):
_RPC_ = None
@@ -404,7 +405,7 @@ def add(self, x, y):
def ping(self, x):
return x
-
+
def noargs(self):
return 'Works!'
View
38 tornadorpc/json.py
@@ -1,21 +1,8 @@
"""
-Copyright 2009 Josh Marshall
-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.
-
============================
JSON-RPC Handler for Tornado
============================
-This is a JSON-RPC server implementation, designed for use within the
+This is a JSON-RPC server implementation, designed for use within the
Tornado framework. Usage is pretty simple:
>>> from tornadorpc.json import JSONRPCHandler
@@ -30,30 +17,30 @@
It requires the jsonrpclib, which you can get from:
http://github.com/joshmarshall/jsonrpclib
-
+
Also, you will need one of the following JSON modules:
* cjson
* simplejson
-From Python 2.6 on, simplejson is included in the standard
+From Python 2.6 on, simplejson is included in the standard
distribution as the "json" module.
"""
from tornadorpc.base import BaseRPCParser, BaseRPCHandler
import jsonrpclib
from jsonrpclib.jsonrpc import isbatch, isnotification, Fault
from jsonrpclib.jsonrpc import dumps, loads
-import types
+
class JSONRPCParser(BaseRPCParser):
-
+
content_type = 'application/json-rpc'
def parse_request(self, request_body):
try:
request = loads(request_body)
except:
- # Bad request formatting. Bad.
+ # Bad request formatting
self.traceback()
return self.faults.parse_error()
self._requests = request
@@ -65,7 +52,7 @@ def parse_request(self, request_body):
req_tuple = (req['method'], req.get('params', []))
request_list.append(req_tuple)
else:
- self._requests = [request,]
+ self._requests = [request]
request_list.append(
(request['method'], request.get('params', []))
)
@@ -108,20 +95,23 @@ def parse_responses(self, responses):
return response_list[0]
# Batch, return list
return '[ %s ]' % ', '.join(response_list)
-
+
+
class JSONRPCLibraryWrapper(object):
-
+
dumps = dumps
loads = loads
Fault = Fault
+
class JSONRPCHandler(BaseRPCHandler):
"""
Subclass this to add methods -- you can treat them
just like normal methods, this handles the JSON formatting.
"""
_RPC_ = JSONRPCParser(JSONRPCLibraryWrapper)
+
if __name__ == '__main__':
# Example Implementation
import sys
@@ -130,10 +120,10 @@ class JSONRPCHandler(BaseRPCHandler):
class TestJSONRPC(TestRPCHandler):
_RPC_ = JSONRPCParser(JSONRPCLibraryWrapper)
-
+
port = 8181
if len(sys.argv) > 1:
port = int(sys.argv[1])
-
+
print 'Starting server on port %s' % port
start_server(TestJSONRPC, port=port)
View
10 tornadorpc/utils.py
@@ -4,24 +4,24 @@
import inspect
+
def getcallargs(func, *positional, **named):
"""
- Simple implementation of inspect.getcallargs function in
+ Simple implementation of inspect.getcallargs function in
the Python 2.7 standard library.
-
+
Takes a function and the position and keyword arguments and
returns a dictionary with the appropriate named arguments.
Raises an exception if invalid arguments are passed.
"""
args, varargs, varkw, defaults = inspect.getargspec(func)
- fname = func.__name__
final_kwargs = {}
extra_args = []
has_self = inspect.ismethod(func) and func.im_self is not None
if has_self:
- self_key = args.pop(0)
-
+ args.pop(0)
+
# (Since our RPC supports only positional OR named.)
if named:
for key, value in named.iteritems():
View
25 tornadorpc/xml.py
@@ -1,21 +1,8 @@
"""
-Copyright 2009 Josh Marshall
-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.
-
===========================
-XML-RPC Handler for Tornado
+XML-RPC Handler for Tornado
===========================
-This is a XML-RPC server implementation, designed for use within the
+This is a XML-RPC server implementation, designed for use within the
Tornado framework. Usage is pretty simple:
>>> from tornadorpc.xml import XMLRPCHandler
@@ -34,7 +21,7 @@
from tornadorpc.base import BaseRPCParser, BaseRPCHandler
import xmlrpclib
-import types
+
class XMLRPCSystem(object):
# Multicall functions and, eventually, introspection
@@ -43,7 +30,6 @@ def __init__(self, handler):
self._dispatch = handler._RPC_.dispatch
def multicall(self, calls):
- response_list = []
for call in calls:
method_name = call['methodName']
params = call['params']
@@ -74,6 +60,7 @@ def parse_responses(self, responses):
return self.faults.internal_error()
return response_xml
+
class XMLRPCHandler(BaseRPCHandler):
"""
Subclass this to add methods -- you can treat them
@@ -85,17 +72,19 @@ class XMLRPCHandler(BaseRPCHandler):
def system(self):
return XMLRPCSystem(self)
+
if __name__ == '__main__':
# Test implementation
from tornadorpc.base import TestRPCHandler, start_server
import sys
-
+
port = 8282
if len(sys.argv) > 1:
port = int(sys.argv[1])
class TestXMLRPC(TestRPCHandler):
_RPC_ = XMLRPCParser(xmlrpclib)
+
@property
def system(self):
return XMLRPCSystem(self)

0 comments on commit 00aea69

Please sign in to comment.