comparison wibble/client/ServerProxy.py @ 4:ad5a8748afcf

Add test framework
author Ben Croston <ben@croston.org>
date Wed, 31 Aug 2011 21:35:14 +0100
parents client/ServerProxy2.py@c7a236de5214
children f5e3ba8cfcd0
comparison
equal deleted inserted replaced
3:43595981978d 4:ad5a8748afcf
1 #!/usr/bin/env python
2 from uuid import uuid4
3 from urlparse import urlparse
4 import json
5 import httplib
6 import copy
7 import socket
8 import hashlib
9
10 class _Method(object):
11 def __init__(self, call, name, username=None, password=None):
12 self.call = call
13 self.name = name
14 self._username = username
15 self._password = password
16
17 def __call__(self, *args, **kwargs):
18 request = {}
19 request['id'] = str(uuid4())
20 request['method'] = self.name
21
22 if len(kwargs) is not 0:
23 params = copy.copy(kwargs)
24 index = 0
25 for arg in args:
26 params[str(index)] = arg
27 index = index + 1
28 elif len(args) is not 0:
29 params = copy.copy(args)
30 else:
31 params = None
32 request['params'] = params
33
34 if self._username is not None:
35 request['username'] = self._username
36 if self._password is not None:
37 request['password'] = hashlib.md5(self._password).hexdigest()
38
39 resp = self.call(json.dumps(request))
40 if resp is not None and resp['error'] is None and resp['id'] == request['id']:
41 return resp['result']
42 else:
43 raise Exception('This is not supposed to happen -- btc') ########
44
45 def __getattr__(self, name):
46 return _Method(self.call, "%s.%s" % (self.name, name), self._username, self._password)
47
48 class _JSONRPCTransport(object):
49 headers = {'Content-Type':'application/json',
50 'Accept':'application/json'}
51
52 def __init__(self, uri, proxy_uri=None, user_agent=None):
53 self.headers['User-Agent'] = user_agent if user_agent is not None else 'jsonrpclib'
54 if proxy_uri is not None:
55 self.connection_url = urlparse(proxy_uri)
56 self.request_path = uri
57 else:
58 self.connection_url = urlparse(uri)
59 self.request_path = self.connection_url.path
60
61 def request(self, request_body):
62 if self.connection_url.scheme == 'http':
63 if self.connection_url.port is None:
64 port = 80
65 else:
66 port = self.connection_url.port
67 connection = httplib.HTTPConnection(self.connection_url.hostname+':'+str(port))
68 elif self.connection_url.scheme == 'https':
69 if self.connection_url.port is None:
70 port = 443
71 else:
72 port = self.connection_url.port
73 connection = httplib.HTTPSConnection(self.connection_url.hostname+':'+str(port))
74 else:
75 raise Exception('unsupported transport')
76 connection.request('POST', self.request_path, body=request_body, headers=self.headers)
77 return connection.getresponse()
78
79 class BadRequestException(Exception):
80 """HTTP 400 - Bad Request"""
81 def __init__(self):
82 Exception.__init__(self,'HTTP 400 - Bad Request')
83
84 class UnauthorisedException(Exception):
85 """HTTP 401 - Unauthorised"""
86 def __init__(self):
87 Exception.__init__(self,'HTTP 401 - Unauthorised')
88
89 class ForbiddenException(Exception):
90 """HTTP 403 - Forbidden"""
91 def __init__(self):
92 Exception.__init__(self,'HTTP 403 - Forbidden')
93
94 class NotFoundException(Exception):
95 """HTTP 404 - Not Found"""
96 def __init__(self):
97 Exception.__init__(self,'HTTP 404 - Not Found')
98
99 class NetworkSocketException(Exception):
100 def __init__(self):
101 Exception.__init__(self,'Network socket exception')
102
103 class BadGatewayException(Exception):
104 """HTTP 502 - Bad Gateway"""
105 def __init__(self):
106 Exception.__init__(self,'HTTP 502 - Bad Gateway')
107
108 class ServerProxy(object):
109 def __init__(self, uri=None, transport=None, proxy_uri=None, user_agent=None, username=None, password=None):
110 if uri is None and transport is None:
111 raise Exception('either uri or transport needs to be specified')
112
113 if transport is None:
114 transport = _JSONRPCTransport(uri, proxy_uri=proxy_uri, user_agent=user_agent)
115 self.__transport = transport
116 self._username = username
117 self._password = password
118
119 def __request(self, request):
120 # call a method on the remote server
121 try:
122 response = self.__transport.request(request)
123 except socket.error:
124 raise NetworkSocketException
125 if response.status == 200:
126 return json.loads(response.read())
127 elif response.status == 400:
128 raise BadRequestException
129 elif response.status == 401:
130 raise UnauthorisedException
131 elif response.status == 403:
132 raise ForbiddenException
133 elif response.status == 404:
134 raise NotFoundException
135 elif response.status == 500:
136 msg = json.loads(response.read())
137 raise Exception('JSONRPCError\n%s'%msg['error']['error'])
138 elif response.status == 502:
139 raise BadGatewayException
140 else:
141 raise Exception('HTTP Status %s'%response.status)
142
143 def __repr__(self):
144 return (
145 "<ServerProxy for %s%s>" %
146 (self.__host, self.__handler)
147 )
148
149 __str__ = __repr__
150
151 def __getattr__(self, name):
152 # magic method dispatcher
153 return _Method(self.__request, name, self._username, self._password)
154
155 if __name__ == '__main__':
156 ##### btc fixme
157 jsonrpc_client = ServerProxy2('http://localhost:1337/', username='testuser', password='', user_agent='Py2NotInternetExploiter')
158 #jsonrpc_client = ServerProxy2('https://www.croston.org/test/index.py',
159 # username='testuser',
160 # password='',
161 # user_agent='Py2NotInternetExploiter')
162 assert jsonrpc_client.api.mymethod() == jsonrpc_client.mymethod()
163 try:
164 print(jsonrpc_client.wibble('this should fail'))
165 except BadRequestException:
166 pass # test passed
167 else:
168 raise Exception('Test failed (calling unknown method)')
169
170 print 'All tests passed'
171