blob: b01cc36072b7f87412c75c589d3b00e4f4745549 [file] [log] [blame]
mblighe8819cd2008-02-15 16:48:40 +00001
2"""
3 Copyright (c) 2007 Jan-Klaas Kollhof
4
5 This file is part of jsonrpc.
6
7 jsonrpc is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 This software is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with this software; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20"""
21
22import urllib2
mblighe8819cd2008-02-15 16:48:40 +000023
24class JSONRPCException(Exception):
25 pass
26
Chris Masone47c9e642012-04-25 14:22:18 -070027class ValidationError(JSONRPCException):
28 """Raised when the RPC is malformed."""
29 def __init__(self, error, formatted_message):
30 """Constructor.
31
32 @param error: a dict of error info like so:
33 {error['name']: 'ErrorKind',
34 error['message']: 'Pithy error description.',
35 error['traceback']: 'Multi-line stack trace'}
36 @formatted_message: string representation of this exception.
37 """
38 self.problem_keys = eval(error['message'])
39 self.traceback = error['traceback']
40 super(ValidationError, self).__init__(formatted_message)
41
42def BuildException(error):
43 """Exception factory.
44
45 Given a dict of error info, determine which subclass of
46 JSONRPCException to build and return. If can't determine the right one,
47 just return a JSONRPCException with a pretty-printed error string.
48
49 @param error: a dict of error info like so:
50 {error['name']: 'ErrorKind',
51 error['message']: 'Pithy error description.',
52 error['traceback']: 'Multi-line stack trace'}
53 """
54 error_message = '%(name)s: %(message)s\n%(traceback)s' % error
55 for cls in JSONRPCException.__subclasses__():
56 if error['name'] == cls.__name__:
57 return cls(error, error_message)
58 return JSONRPCException(error_message)
59
mblighe8819cd2008-02-15 16:48:40 +000060class ServiceProxy(object):
61 def __init__(self, serviceURL, serviceName=None, headers=None):
62 self.__serviceURL = serviceURL
63 self.__serviceName = serviceName
showard8e855a22008-04-15 17:32:20 +000064 self.__headers = headers or {}
mblighe8819cd2008-02-15 16:48:40 +000065
66 def __getattr__(self, name):
mblighd876f452008-12-03 15:09:17 +000067 if self.__serviceName is not None:
mblighe8819cd2008-02-15 16:48:40 +000068 name = "%s.%s" % (self.__serviceName, name)
69 return ServiceProxy(self.__serviceURL, name, self.__headers)
70
71 def __call__(self, *args, **kwargs):
jadmanski656b3b82010-01-27 23:42:27 +000072 # pull in simplejson imports lazily so that the library isn't required
73 # unless you actually need to do encoding and decoding
74 from simplejson import decoder, encoder
75
jadmanski08ff9ad2010-01-27 23:42:42 +000076 postdata = encoder.JSONEncoder().encode({"method": self.__serviceName,
77 'params': args + (kwargs,),
78 'id':'jsonrpc'})
jadmanski0afbb632008-06-06 21:10:57 +000079 request = urllib2.Request(self.__serviceURL, data=postdata,
80 headers=self.__headers)
81 respdata = urllib2.urlopen(request).read()
82 try:
jadmanski08ff9ad2010-01-27 23:42:42 +000083 resp = decoder.JSONDecoder().decode(respdata)
jadmanski0afbb632008-06-06 21:10:57 +000084 except ValueError:
85 raise JSONRPCException('Error decoding JSON reponse:\n' + respdata)
mblighd876f452008-12-03 15:09:17 +000086 if resp['error'] is not None:
Chris Masone47c9e642012-04-25 14:22:18 -070087 raise BuildException(resp['error'])
jadmanski0afbb632008-06-06 21:10:57 +000088 else:
89 return resp['result']