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

Add test framework
author Ben Croston <ben@croston.org>
date Wed, 31 Aug 2011 21:35:14 +0100
parents client/ServerProxy.py@c7a236de5214
children
comparison
equal deleted inserted replaced
3:43595981978d 4:ad5a8748afcf
1 #!/usr/bin/env python3
2 from uuid import uuid4
3 from urllib.parse import urlparse
4 import json
5 import http.client
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.encode()).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 = http.client.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 = http.client.HTTPSConnection(self.connection_url.hostname+':'+str(port))
74 else:
75 raise Exception('unsupported transport')
76
77 connection.request('POST', self.request_path, body=request_body, headers=self.headers)
78 return connection.getresponse()
79
80 class BadRequestException(Exception):
81 """HTTP 400 - Bad Request"""
82 def __init__(self):
83 Exception.__init__(self,'HTTP 400 - Bad Request')
84
85 class UnauthorisedException(Exception):
86 """HTTP 401 - Unauthorised"""
87 def __init__(self):
88 Exception.__init__(self,'HTTP 401 - Unauthorised')
89
90 class ForbiddenException(Exception):
91 """HTTP 403 - Forbidden"""
92 def __init__(self):
93 Exception.__init__(self,'HTTP 403 - Forbidden')
94
95 class NotFoundException(Exception):
96 """HTTP 404 - Not Found"""
97 def __init__(self):
98 Exception.__init__(self,'HTTP 404 - Not Found')
99
100 class NetworkSocketException(Exception):
101 def __init__(self):
102 Exception.__init__(self,'Network socket exception')
103
104 class BadGatewayException(Exception):
105 """HTTP 502 - Bad Gateway"""
106 def __init__(self):
107 Exception.__init__(self,'HTTP 502 - Bad Gateway')
108
109 class ServerProxy(object):
110 def __init__(self, uri=None, transport=None, proxy_uri=None, user_agent=None, username=None, password=None):
111 if uri is None and transport is None:
112 raise Exception('either uri or transport needs to be specified')
113
114 if transport is None:
115 transport = _JSONRPCTransport(uri, proxy_uri=proxy_uri, user_agent=user_agent)
116 self.__transport = transport
117 self._username = username
118 self._password = password
119
120 def __request(self, request):
121 # call a method on the remote server
122 try:
123 response = self.__transport.request(request)
124 except socket.error:
125 raise NetworkSocketException
126 if response.status == 200:
127 return json.loads(response.read().decode())
128 elif response.status == 400:
129 raise BadRequestException
130 elif response.status == 401:
131 raise UnauthorisedException
132 elif response.status == 403:
133 raise ForbiddenException
134 elif response.status == 404:
135 raise NotFoundException
136 elif response.status == 500:
137 msg = json.loads(response.read().decode())
138 raise Exception('JSONRPCError\n%s'%msg['error']['error'])
139 elif response.status == 502:
140 raise BadGatewayException
141 else:
142 raise Exception('HTTP Status %s'%response.status)
143
144 def __repr__(self):
145 return (
146 "<ServerProxy for %s%s>" %
147 (self.__host, self.__handler)
148 )
149
150 __str__ = __repr__
151
152 def __getattr__(self, name):
153 # magic method dispatcher
154 return _Method(self.__request, name, self._username, self._password)
155
156 if __name__ == '__main__':
157 #### btc fixme
158 jsonrpc_client = ServerProxy('http://localhost:1337/', username='testuser', password='', user_agent='Py3NotInternetExploiter')
159 #jsonrpc_client = ServerProxy('https://www.croston.org/test/index.py',
160 # username='testuser',
161 # password='',
162 # user_agent='Py3NotInternetExploiter')
163 assert jsonrpc_client.api.mymethod() == jsonrpc_client.mymethod()
164 try:
165 print(jsonrpc_client.wibble('this should fail'))
166 except BadRequestException:
167 pass # test passed
168 else:
169 raise Exception('Test failed (calling unknown method)')
170
171 print('All tests passed')
172