Browse code
fixing bug (undefined variable)
Ed L authored on 06/06/2011 17:55:07
Showing 7 changed files
Showing 7 changed files
- jsonrpc/__init__.py
- jsonrpc/common.py
- jsonrpc/proxy.py
- jsonrpc/server.py
- jsonrpc/tests/test_jsonutil.py
- jsonrpc/tests/test_proxy.py
- jsonrpc/tests/test_server.py
... | ... |
@@ -32,4 +32,10 @@ |
32 | 32 |
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
33 | 33 |
# |
34 | 34 |
# |
35 |
+try: import json |
|
36 |
+except ImportError: |
|
37 |
+ import simplejson as json |
|
38 |
+ import sys |
|
39 |
+ sys.modules['json'] = json |
|
40 |
+ |
|
35 | 41 |
__version__ = "$Revision: 1.2 $".split(":")[1][:-1].strip() |
... | ... |
@@ -30,6 +30,7 @@ |
30 | 30 |
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
31 | 31 |
# |
32 | 32 |
# |
33 |
+import warnings |
|
33 | 34 |
from jsonrpc.utilities import public |
34 | 35 |
import jsonrpc.jsonutil |
35 | 36 |
|
... | ... |
@@ -80,18 +81,20 @@ codemap = {0: RPCError} |
80 | 81 |
codemap.update( (e.code, e) for e in RPCError.__subclasses__() ) |
81 | 82 |
|
82 | 83 |
class JsonInstantiate: |
83 |
- @classmethod |
|
84 |
- def from_json(cls, json): |
|
85 |
- data = jsonrpc.jsonutil.decode(json) |
|
86 |
- if isinstance(data, list): |
|
87 |
- result = cls.from_list(data) |
|
88 |
- else: |
|
89 |
- result = cls.from_dict(data) |
|
90 |
- return result |
|
84 |
+ @classmethod |
|
85 |
+ def from_json(cls, json): |
|
86 |
+ data = json |
|
87 |
+ if hasattr(json, 'upper'): |
|
88 |
+ data = jsonrpc.jsonutil.decode(json) |
|
89 |
+ if isinstance(data, list): |
|
90 |
+ result = cls.from_list(data) |
|
91 |
+ else: |
|
92 |
+ result = cls.from_dict(data) |
|
93 |
+ return result |
|
91 | 94 |
|
92 |
- @classmethod |
|
93 |
- def from_list(cls, responses): |
|
94 |
- return [cls.from_dict(r) for r in responses] |
|
95 |
+ @classmethod |
|
96 |
+ def from_list(cls, responses): |
|
97 |
+ return [cls.from_dict(r) for r in responses] |
|
95 | 98 |
|
96 | 99 |
|
97 | 100 |
class Request(object, JsonInstantiate): |
... | ... |
@@ -127,6 +130,9 @@ class Request(object, JsonInstantiate): |
127 | 130 |
def check(self): |
128 | 131 |
if self.version != '2.0': raise InvalidRequest |
129 | 132 |
if not isinstance(self.method, (str, unicode)): raise InvalidRequest |
133 |
+ if not isinstance(self.id, (str, unicode, int, type(None))): |
|
134 |
+ self.id = None |
|
135 |
+ raise InvalidRequest |
|
130 | 136 |
|
131 | 137 |
|
132 | 138 |
def json_equivalent(self): |
... | ... |
@@ -137,7 +143,7 @@ class Request(object, JsonInstantiate): |
137 | 143 |
if self.args and self.kwargs: |
138 | 144 |
self.kwargs['__args'] = self.args |
139 | 145 |
if self.kwargs: |
140 |
- result['params'] = self.kwargs |
|
146 |
+ params = self.kwargs |
|
141 | 147 |
|
142 | 148 |
return dict( |
143 | 149 |
jsonrpc = self.version, |
... | ... |
@@ -82,7 +82,7 @@ class ProxyEvents(object): |
82 | 82 |
self.IDGen = self.IDGen() |
83 | 83 |
self.proxy = proxy |
84 | 84 |
|
85 |
- def get_postdata(self, args, kwargs): |
|
85 |
+ def get_params(self, args, kwargs): |
|
86 | 86 |
'''allow a subclass to modify the method's arguments |
87 | 87 |
|
88 | 88 |
e.g. if an authentication token is necessary, the subclass can automatically insert it into every call''' |
... | ... |
@@ -108,14 +108,15 @@ class JSONRPCProxy(object): |
108 | 108 |
_eventhandler = ProxyEvents |
109 | 109 |
def customize(self, eventhandler): |
110 | 110 |
self._eventhandler = eventhandler(self) |
111 |
+ return self |
|
111 | 112 |
|
112 | 113 |
def _transformURL(self, serviceURL, path): |
113 |
- if serviceURL[-1] == '/': |
|
114 |
+ if serviceURL.endswith('/'): |
|
114 | 115 |
serviceURL = serviceURL[:-1] |
115 |
- if path[0] != '/': |
|
116 |
- path = '/%s'%path |
|
117 |
- if path[-1] != '/' and '?' not in path: |
|
118 |
- path = '%s/'%path |
|
116 |
+ if path.endswith('/'): |
|
117 |
+ path = path[:-1] |
|
118 |
+ if path.startswith('/'): |
|
119 |
+ path = path[1:] |
|
119 | 120 |
return serviceURL, path |
120 | 121 |
|
121 | 122 |
|
... | ... |
@@ -131,7 +132,7 @@ class JSONRPCProxy(object): |
131 | 132 |
return cls(url, path, serviceName, ctxid) |
132 | 133 |
|
133 | 134 |
|
134 |
- def __init__(self, host, path='/jsonrpc', serviceName=None, *args, **kwargs): |
|
135 |
+ def __init__(self, host, path='jsonrpc', serviceName=None, *args, **kwargs): |
|
135 | 136 |
self.serviceURL = host |
136 | 137 |
self._serviceName = serviceName |
137 | 138 |
self._path = path |
... | ... |
@@ -143,19 +144,25 @@ class JSONRPCProxy(object): |
143 | 144 |
def __getattr__(self, name): |
144 | 145 |
if self._serviceName != None: |
145 | 146 |
name = "%s.%s" % (self._serviceName, name) |
146 |
- return self.__class__(self.serviceURL, path=self._path, serviceName=name) |
|
147 |
+ return self.__class__(self.serviceURL, path=self._path, serviceName=name).customize(type(self._eventhandler)) |
|
147 | 148 |
|
148 | 149 |
|
149 | 150 |
def _get_postdata(self, args=None, kwargs=None): |
150 |
- args,kwargs = self._eventhandler.get_postdata(args, kwargs) |
|
151 |
+ _args, _kwargs = self._eventhandler.get_params(args, kwargs) |
|
151 | 152 |
id = self._eventhandler.IDGen |
152 |
- result = Request(id, self._serviceName, args, kwargs) |
|
153 |
+ result = Request(id, self._serviceName, _args, _kwargs) |
|
153 | 154 |
return jsonrpc.jsonutil.encode(result) |
154 | 155 |
|
156 |
+ def _get_url(self): |
|
157 |
+ result = [self.serviceURL] |
|
158 |
+ if self._path: |
|
159 |
+ result.append(self._path) |
|
160 |
+ result.append('') |
|
161 |
+ return '/'.join(result) |
|
155 | 162 |
|
156 | 163 |
def __call__(self, *args, **kwargs): |
157 | 164 |
|
158 |
- url = '%(host)s%(path)s' % dict(host = self.serviceURL, path = self._path) |
|
165 |
+ url = self._get_url() |
|
159 | 166 |
postdata = self._get_postdata(args, kwargs) |
160 | 167 |
respdata = urllib.urlopen(url, postdata).read() |
161 | 168 |
resp = Response.from_dict(jsonrpc.jsonutil.decode(respdata)) |
... | ... |
@@ -184,7 +191,7 @@ class JSONRPCProxy(object): |
184 | 191 |
if hasattr(methods, 'items'): methods = methods.items() |
185 | 192 |
data = [ getattr(self, k)._get_postdata(*v) for k, v in methods ] |
186 | 193 |
postdata = '[%s]' % ','.join(data) |
187 |
- respdata = urllib.urlopen(self.serviceURL, postdata).read() |
|
194 |
+ respdata = urllib.urlopen(self._get_url(), postdata).read() |
|
188 | 195 |
resp = Response.from_json(respdata) |
189 | 196 |
try: |
190 | 197 |
result = resp.get_result() |
... | ... |
@@ -107,10 +107,7 @@ class JSON_RPC(Resource): |
107 | 107 |
|
108 | 108 |
content = self.eventhandler.processcontent(content, request) |
109 | 109 |
|
110 |
- if isinstance(content, list): |
|
111 |
- content = jsonrpc.common.Request.from_list(content) |
|
112 |
- else: |
|
113 |
- content = jsonrpc.common.Request.from_dict(content) |
|
110 |
+ content = jsonrpc.common.Request.from_json(content) |
|
114 | 111 |
|
115 | 112 |
try: |
116 | 113 |
if hasattr(content, 'check'): |
... | ... |
@@ -179,6 +176,7 @@ class JSON_RPC(Resource): |
179 | 176 |
except BaseException, e: |
180 | 177 |
err = e |
181 | 178 |
else: err = result |
179 |
+ |
|
182 | 180 |
err = self.render_error(err, id) |
183 | 181 |
self.eventhandler.log(err, request) |
184 | 182 |
|
38 | 38 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,95 @@ |
1 |
+import jsonrpc.common |
|
2 |
+import jsonrpc.proxy |
|
3 |
+from twisted.trial import unittest |
|
4 |
+import mock |
|
5 |
+import urllib |
|
6 |
+import StringIO |
|
7 |
+ |
|
8 |
+# Run example server before tests |
|
9 |
+ |
|
10 |
+class TestJSONRPCProxy(unittest.TestCase): |
|
11 |
+ |
|
12 |
+ def setUp(self): |
|
13 |
+ self.proxy = jsonrpc.proxy.JSONRPCProxy('http://localhost:8007', path='aaa') |
|
14 |
+ |
|
15 |
+ def test_eventhandler(self): |
|
16 |
+ eventhandler = mock.MagicMock(spec=jsonrpc.proxy.ProxyEvents) |
|
17 |
+ args = (1,2) |
|
18 |
+ kwargs = {'a':1, 'b':2} |
|
19 |
+ |
|
20 |
+ def get_params(self, args, kwargs): |
|
21 |
+ print args, kwargs |
|
22 |
+ return args, kwargs |
|
23 |
+ eventhandler.get_params.side_effect = get_params |
|
24 |
+ |
|
25 |
+ eventhandler.proc_response.side_effect = lambda _, data: data |
|
26 |
+ |
|
27 |
+ self.proxy = jsonrpc.proxy.JSONRPCProxy.from_url('http://localhost:8007') |
|
28 |
+ self.proxy.customize(lambda *a: eventhandler) |
|
29 |
+ self.assertEqual(self.proxy._get_url(), 'http://localhost:8007/') |
|
30 |
+ |
|
31 |
+ self.proxy.add(*args) |
|
32 |
+ self.assertTrue(eventhandler.get_params.called) |
|
33 |
+ eventhandler.get_params.assert_called_once_with( args, {} ) |
|
34 |
+ self.assertTrue(eventhandler.procresponse.called) |
|
35 |
+ |
|
36 |
+ eventhandler.reset_mock() |
|
37 |
+ |
|
38 |
+ self.proxy.add(**kwargs) |
|
39 |
+ self.assertTrue(eventhandler.get_params.called) |
|
40 |
+ eventhandler.get_params.assert_called_once_with( (), kwargs ) |
|
41 |
+ self.assertTrue(eventhandler.procresponse.called) |
|
42 |
+ |
|
43 |
+ |
|
44 |
+ def test_url(self): |
|
45 |
+ self.proxy = jsonrpc.proxy.JSONRPCProxy.from_url('http://localhost:8007') |
|
46 |
+ self.assertEqual(self.proxy._get_url(), 'http://localhost:8007/') |
|
47 |
+ |
|
48 |
+ self.proxy = jsonrpc.proxy.JSONRPCProxy.from_url('http://localhost:8007/aaa/') |
|
49 |
+ self.assertEqual(self.proxy._get_url(), 'http://localhost:8007/aaa/') |
|
50 |
+ |
|
51 |
+ self.proxy = jsonrpc.proxy.JSONRPCProxy.from_url('http://localhost:8007/aaa') |
|
52 |
+ self.assertEqual(self.proxy._get_url(), 'http://localhost:8007/aaa/') |
|
53 |
+ |
|
54 |
+ self.proxy = jsonrpc.proxy.JSONRPCProxy('http://localhost:8007') |
|
55 |
+ self.assertEqual(self.proxy._get_url(), 'http://localhost:8007/jsonrpc/') |
|
56 |
+ |
|
57 |
+ self.proxy = jsonrpc.proxy.JSONRPCProxy('http://localhost:8007', path='aaa') |
|
58 |
+ self.assertEqual(self.proxy._get_url(), 'http://localhost:8007/aaa/') |
|
59 |
+ |
|
60 |
+ def test_call(self): |
|
61 |
+ self.assertEqual(self.proxy.add(1,2), 3) |
|
62 |
+ self.assertEqual(self.proxy.subtract(2,1), 1) |
|
63 |
+ |
|
64 |
+ def test_exceptions(self): |
|
65 |
+ self.assertRaises(jsonrpc.common.RPCError, self.proxy.add, 1,'2') |
|
66 |
+ self.assertRaises(jsonrpc.common.MethodNotFound, self.proxy.missingmethod) |
|
67 |
+ |
|
68 |
+ def test_batchcall(self): |
|
69 |
+ batch =[ |
|
70 |
+ ('add', [ (1,2), {} ]), |
|
71 |
+ ('subtract', [ (2,1), {} ]), |
|
72 |
+ ('add', [ (1,3), {} ]) |
|
73 |
+ ] |
|
74 |
+ self.assertEqual(self.proxy.batch_call(batch), [(3, None), (1, None), (4, None)]) |
|
75 |
+ |
|
76 |
+ batch =[ |
|
77 |
+ ('add', [ (), dict(a=1,b=2) ]), |
|
78 |
+ ('subtract', [ (2,1), dict() ]), |
|
79 |
+ ('add', [ (1,3), dict() ]) |
|
80 |
+ ] |
|
81 |
+ self.assertEqual(self.proxy.batch_call(batch), [(3, None), (1, None), (4, None)]) |
|
82 |
+ |
|
83 |
+ batch =[ |
|
84 |
+ ('add', [ (), dict(a=1,b=2) ]), |
|
85 |
+ ('subtract', [ (), dict(a=2,b=1) ]), |
|
86 |
+ ('add', [ (), dict(a=1,b=3) ]) |
|
87 |
+ ] |
|
88 |
+ self.assertEqual(self.proxy.batch_call(batch), [(3, None), (1, None), (4, None)]) |
|
89 |
+ |
|
90 |
+ |
|
91 |
+ #def test_<testname here>(self): |
|
92 |
+ # pass |
|
93 |
+ |
|
94 |
+if __name__ == '__main__': |
|
95 |
+ unittest.main() |
... | ... |
@@ -39,7 +39,7 @@ import jsonrpc.server |
39 | 39 |
import jsonrpc.jsonutil |
40 | 40 |
|
41 | 41 |
from twisted.web.test.test_web import DummyRequest |
42 |
-from twisted.internet.defer import succeed |
|
42 |
+from twisted.internet.defer import succeed, DeferredList |
|
43 | 43 |
from twisted.web.static import server |
44 | 44 |
|
45 | 45 |
def _render(resource, request): |
... | ... |
@@ -99,6 +99,62 @@ class TestJSONRPCServer(unittest.TestCase): |
99 | 99 |
|
100 | 100 |
return d |
101 | 101 |
|
102 |
+ def test_requestid(self): |
|
103 |
+ resource = jsonrpc.server.JSON_RPC() |
|
104 |
+ resource.customize(SimpleEventHandler) |
|
105 |
+ |
|
106 |
+ request0 = DummyRequest(['']) |
|
107 |
+ request0.getCookie = mock.Mock() |
|
108 |
+ request0.content = StringIO.StringIO('{"jsonrpc": "2.0", "params": %s, "method": "echo", "id": "%s"}' % (jsonrpc.jsonutil.encode([self.param]), self.id_)) |
|
109 |
+ |
|
110 |
+ d0 = _render(resource, request0) |
|
111 |
+ @d0.addCallback |
|
112 |
+ def rendered(ignored): |
|
113 |
+ self.assertEqual(len(request0.written), 1) |
|
114 |
+ data = jsonrpc.jsonutil.decode(request0.written[0]) |
|
115 |
+ |
|
116 |
+ self.assertEqual(data["id"], self.id_) |
|
117 |
+ |
|
118 |
+ |
|
119 |
+ request1 = DummyRequest(['']) |
|
120 |
+ request1.getCookie = mock.Mock() |
|
121 |
+ request1.content = StringIO.StringIO('{"jsonrpc": "2.0", "params": %s, "method": "echo", "id": 1}' % jsonrpc.jsonutil.encode([self.param])) |
|
122 |
+ |
|
123 |
+ d1 = _render(resource, request1) |
|
124 |
+ @d1.addCallback |
|
125 |
+ def rendered(ignored): |
|
126 |
+ self.assertEqual(len(request1.written), 1) |
|
127 |
+ data = jsonrpc.jsonutil.decode(request1.written[0]) |
|
128 |
+ |
|
129 |
+ self.assertEqual(data["id"], 1) |
|
130 |
+ |
|
131 |
+ |
|
132 |
+ request3 = DummyRequest(['']) |
|
133 |
+ request3.getCookie = mock.Mock() |
|
134 |
+ request3.content = StringIO.StringIO('{"jsonrpc": "2.0", "params": %s, "method": "echo", "id": []}' % jsonrpc.jsonutil.encode([self.param])) |
|
135 |
+ |
|
136 |
+ d3 = _render(resource, request3) |
|
137 |
+ @d3.addCallback |
|
138 |
+ def rendered(ignored): |
|
139 |
+ self.assertEqual(len(request3.written), 1) |
|
140 |
+ data = jsonrpc.jsonutil.decode(request3.written[0]) |
|
141 |
+ |
|
142 |
+ self.assertNotEqual(data["id"], []) |
|
143 |
+ |
|
144 |
+ request4 = DummyRequest(['']) |
|
145 |
+ request4.getCookie = mock.Mock() |
|
146 |
+ request4.content = StringIO.StringIO('{"jsonrpc": "2.0", "params": %s, "method": "echo", "id": {}}' % jsonrpc.jsonutil.encode([self.param])) |
|
147 |
+ |
|
148 |
+ d4 = _render(resource, request4) |
|
149 |
+ @d4.addCallback |
|
150 |
+ def rendered(ignored): |
|
151 |
+ self.assertEqual(len(request4.written), 1) |
|
152 |
+ data = jsonrpc.jsonutil.decode(request4.written[0]) |
|
153 |
+ |
|
154 |
+ self.assertNotEqual(data["id"], {}) |
|
155 |
+ |
|
156 |
+ return DeferredList([d0,d1,d3,d4]) |
|
157 |
+ |
|
102 | 158 |
|
103 | 159 |
def test_invalid_data(self): |
104 | 160 |
resource = jsonrpc.server.JSON_RPC() |