Tweaked MultiCall so it takes a 'ServerProxy' instance instead of a string (like...
[invirt/packages/python-jsonrpclib.git] / jsonrpclib.py
index 7fc6177..c0bb381 100644 (file)
@@ -106,6 +106,9 @@ class Transport(XMLTransport):
             if self.verbose:
                 print 'body: %s' % response
             response_body += response
+        if response_body == '':
+            # Notification
+            return None
         return_obj = loads(response_body)
         return return_obj
 
@@ -153,6 +156,7 @@ class ServerProxy(XMLServerProxy):
     def __notify(self, methodname, params, rpcid=None):
         request = dumps(params, methodname, encoding=self.__encoding,
                         rpcid=rpcid, version=self.__version, notify=True)
+        print request
         response = self.__run_request(request, notify=True)
         return
 
@@ -161,9 +165,7 @@ class ServerProxy(XMLServerProxy):
         global _last_response
         _last_request = request
         
-        if notify is True:
-            _last_response = None
-            return None
+        print request
 
         response = self.__transport.request(
             self.__host,
@@ -179,7 +181,10 @@ class ServerProxy(XMLServerProxy):
         # outputting the response appropriately?
         
         _last_response = response
-        return response
+        if not response:
+            # notification, no result
+            return None
+        return check_for_errors(response)
 
     def __getattr__(self, name):
         # Same as original, just with new _Method and wrapper 
@@ -201,7 +206,7 @@ class _Method(XML_Method):
 
 # Batch implementation
 
-class Job(object):
+class MultiCallMethod(object):
     
     def __init__(self, method, notify=False):
         self.method = method
@@ -224,15 +229,15 @@ class Job(object):
     def __repr__(self):
         return '%s' % self.request()
 
-class BatchServerProxy(ServerProxy):
+class MultiCall(object):
     
-    def __init__(self, uri, *args, **kwargs):
+    def __init__(self, server):
+        self.__server = server
         self.__job_list = []
-        ServerProxy.__init__(self, uri, *args, **kwargs)
 
     def __run_request(self, request_body):
-        run_request = getattr(ServerProxy, '_ServerProxy__run_request')
-        return run_request(self, request_body)
+        run_request = getattr(self.__server, '_ServerProxy__run_request')
+        return run_request(request_body)
 
     def __request(self):
         if len(self.__job_list) < 1:
@@ -244,50 +249,42 @@ class BatchServerProxy(ServerProxy):
         del self.__job_list[:]
         return [ response['result'] for response in responses ]
 
-    def __notify(self, method, params):
-        new_job = Job(method, notify=True)
+    def __notify(self, method, params=[]):
+        new_job = MultiCallMethod(method, notify=True)
+        new_job.params = params
         self.__job_list.append(new_job)
-
+        
     def __getattr__(self, name):
         if name in ('__run', '__notify'):
             wrapped_name = '_%s%s' % (self.__class__.__name__, name)
             return getattr(self, wrapped_name)
-        new_job = Job(name)
+        new_job = MultiCallMethod(name)
         self.__job_list.append(new_job)
         return new_job
 
-    __run = __request
+    __call__ = __request
 
 # These lines conform to xmlrpclib's "compatibility" line. 
 # Not really sure if we should include these, but oh well.
 Server = ServerProxy
-BatchServer = BatchServerProxy
-
-def run(batch):
-    """
-    This method is just a caller for the __run() on the actual
-    BatchServer itself. Useful only for those who don't like
-    calling __ methods. :)
-    """
-    batch.__run()
-
-
 
-class Fault(dict):
+class Fault(object):
     # JSON-RPC error class
     def __init__(self, code=-32000, message='Server error'):
-        self.code = code
-        self.message = message
+        self.faultCode = code
+        self.faultString = message
 
     def error(self):
-        return {'code':self.code, 'message':self.message}
+        return {'code':self.faultCode, 'message':self.faultString}
 
     def response(self, rpcid=None, version=None):
         global _version
         if not version:
             version = _version
-        return dumps(self, rpcid=None, methodresponse=True,
-                     version=version)
+        return dumps(self, rpcid=rpcid, version=version)
+
+    def __repr__(self):
+        return '<Fault %s: %s>' % (self.faultCode, self.faultString)
 
 def random_id(length=8):
     import string
@@ -350,7 +347,7 @@ def dumps(params=[], methodname=None, methodresponse=None,
     """
     global _version
     if not version:
-        verion = _version
+        version = _version
     valid_params = (types.TupleType, types.ListType, types.DictType)
     if methodname in types.StringTypes and \
             type(params) not in valid_params and \
@@ -361,18 +358,16 @@ def dumps(params=[], methodname=None, methodresponse=None,
         """
         raise TypeError('Params must be a dict, list, tuple or Fault ' +
                         'instance.')
-    if type(methodname) not in types.StringTypes and methodresponse != True:
-        raise ValueError('Method name must be a string, or methodresponse '+
-                         'must be set to True.')
-    if isinstance(params, Fault) and not methodresponse:
-        raise TypeError('You can only use a Fault for responses.')
     # Begin parsing object
     payload = Payload(rpcid=rpcid, version=version)
     if not encoding:
         encoding = 'utf-8'
     if type(params) is Fault:
-        response = payload.error(params.code, params.message)
+        response = payload.error(params.faultCode, params.faultString)
         return jdumps(response, encoding=encoding)
+    if type(methodname) not in types.StringTypes and methodresponse != True:
+        raise ValueError('Method name must be a string, or methodresponse '+
+                         'must be set to True.')
     if methodresponse is True:
         if rpcid is None:
             raise ValueError('A method response must have an rpcid.')
@@ -391,11 +386,16 @@ def loads(data):
     the request structure in Dict format instead of the method, params.
     It will return a list in the case of a batch request / response.
     """
+    if data == '':
+        # notification
+        return None
     result = jloads(data)
     # if the above raises an error, the implementing server code 
     # should return something like the following:
     # { 'jsonrpc':'2.0', 'error': fault.error(), id: None }
-    
+    return result
+
+def check_for_errors(result):
     result_list = []
     if not isbatch(result):
         result_list.append(result)