--- Lib/xmlrpclib.py 2007-11-20 08:34:46.000000000 -0500 +++ Lib/xmlrpclib.py.orig 2008-03-21 15:36:01.000000000 -0400 @@ -236,6 +236,29 @@ (self.url, self.errcode, self.errmsg) ) + +class MarshallError(Error): + """Indicates an error occurred while marshalling to/from XML""" + def __init__(self, message, value, key=None, slot=None): + self.message = message + self.value = value + self.slot = slot + self.key = key + + def __str__(self): + message = str(self.message) + + if self.slot is not None: + message += "; slot %s" % self.slot + + if self.key is not None: + message += "; key %s" % self.key + + message += "; value='%s'" % self.value + + return ' %s ' % message + + ## # Indicates a broken XML-RPC response package. This exception is # raised by the unmarshalling layer, if the XML-RPC response is @@ -579,17 +602,26 @@ dispatch = {} + def dump_fault(self, fault, write, dump): + '''dumps the fault provided to the writer''' + self._dump_fault(fault.faultCode, fault.faultString, write, dump) + + + def _dump_fault(self, faultCode, faultString, write, dump): + '''dumps the fault code and string to the writer provided''' + write("\n") + dump({'faultCode': faultCode, + 'faultString': faultString}, + write) + write("\n") + + def dumps(self, values): out = [] write = out.append dump = self.__dump if isinstance(values, Fault): - # fault instance - write("\n") - dump({'faultCode': values.faultCode, - 'faultString': values.faultString}, - write) - write("\n") + self.dump_fault(values, write, dump) else: # parameter block # FIXME: the xml-rpc specification allows us to leave out @@ -597,15 +629,32 @@ # however, changing this may break older code (including # old versions of xmlrpclib.py), so this is better left as # is for now. See @XMLRPC3 for more information. /F - write("\n") - for v in values: - write("\n") - dump(v, write) - write("\n") - write("\n") + pos = 0 + try: + params = [] + write = params.append + + write("\n") + for pos, v in enumerate(values): + write("\n") + dump(v, write) + write("\n") + write("\n") + + out.extend(params) + + except MarshallError, e: + fault = [] + write = fault.append + message = "could not serialize value #%d: %s" % (pos, str(e)) + self._dump_fault(8002, message, write, dump) + + out.extend(fault) + result = string.join(out, "") return result + def __dump(self, value, write): try: f = self.dispatch[type(value)] @@ -671,8 +720,12 @@ self.memo[i] = None dump = self.__dump write("\n") - for v in value: - dump(v, write) + for pos, v in enumerate(value): + try: + dump(v, write) + except Exception, e: + raise MarshallError(e, v, slot=pos) + write("\n") del self.memo[i] dispatch[TupleType] = dump_array @@ -693,7 +746,11 @@ else: raise TypeError, "dictionary key must be string" write("%s\n" % escape(k)) - dump(v, write) + try: + dump(v, write) + except Exception, e: + raise MarshallError(e, v, key=k) + write("\n") write("\n") del self.memo[i]