diff -r ffb01a6c0960 Lib/test/test_xmlrpc.py --- a/Lib/test/test_xmlrpc.py Sun Aug 25 00:04:06 2013 +0100 +++ b/Lib/test/test_xmlrpc.py Sun Aug 25 15:28:27 2013 +0300 @@ -563,6 +563,20 @@ # protocol error; provide additional information in test output self.fail("%s\n%s" % (e, getattr(e, "headers", ""))) + def test_use_python_exceptions(self): + try: + p = xmlrpclib.ServerProxy(URL, use_python_exceptions=True) + with self.assertRaises(TypeError) as exc: + p.add(2, 'builtin') + self.assertEqual(exc.exception.args[0], + "unsupported operand type(s) for +: 'int' and 'str'") + + except (xmlrpclib.ProtocolError, OSError) as e: + # ignore failures due to non-blocking socket 'unavailable' errors + if not is_unavailable_exception(e): + # protocol error; provide additional information in test output + self.fail("%s\n%s" % (e, getattr(e, "headers", ""))) + def test_nonascii(self): start_string = 'P\N{LATIN SMALL LETTER Y WITH CIRCUMFLEX}t' end_string = 'h\N{LATIN SMALL LETTER O WITH HORN}n' diff -r ffb01a6c0960 Lib/xmlrpc/client.py --- a/Lib/xmlrpc/client.py Sun Aug 25 00:04:06 2013 +0100 +++ b/Lib/xmlrpc/client.py Sun Aug 25 15:28:27 2013 +0300 @@ -239,6 +239,19 @@ def __repr__(self): return "" % (self.faultCode, self.faultString) +def _exceptions_repr(): + # get a dictionary of builtin exceptions + # and their string representation + import builtins + exceptions = {} + + for obj in vars(builtins).values(): + if isinstance(obj, type) and issubclass(obj, BaseException): + exceptions[str(obj)] = obj + return exceptions + +_BUILTIN_EXCEPTIONS = _exceptions_repr() + # -------------------------------------------------------------------- # Special values @@ -638,7 +651,8 @@ # and again, if you don't understand what's going on in here, # that's perfectly ok. - def __init__(self, use_datetime=False, use_builtin_types=False): + def __init__(self, use_datetime=False, use_builtin_types=False, + use_python_exceptions=False): self._type = None self._stack = [] self._marks = [] @@ -648,12 +662,22 @@ self.append = self._stack.append self._use_datetime = use_builtin_types or use_datetime self._use_bytes = use_builtin_types + self._use_python_exceptions = use_python_exceptions def close(self): # return response tuple and target method if self._type is None or self._marks: raise ResponseError() if self._type == "fault": + if self._use_python_exceptions: + fault_string = self._stack[0]['faultString'] + if self._stack[0]['faultCode'] == 1: + klass, arg = fault_string.split(":", 1) + builtin = _BUILTIN_EXCEPTIONS.get(klass) + if builtin: + raise builtin(arg) + # Otherwise, fallback? + raise Fault(**self._stack[0]) return tuple(self._stack) @@ -872,7 +896,7 @@ # # return A (parser, unmarshaller) tuple. -def getparser(use_datetime=False, use_builtin_types=False): +def getparser(use_datetime=False, use_builtin_types=False, use_python_exceptions=False): """getparser() -> parser, unmarshaller Create an instance of the fastest available parser, and attach it @@ -891,7 +915,9 @@ target = FastUnmarshaller(True, False, mkbytes, mkdatetime, Fault) parser = FastParser(target) else: - target = Unmarshaller(use_datetime=use_datetime, use_builtin_types=use_builtin_types) + target = Unmarshaller(use_datetime=use_datetime, + use_builtin_types=use_builtin_types, + use_python_exceptions=use_python_exceptions) if FastParser: parser = FastParser(target) else: @@ -1109,9 +1135,11 @@ # that they can decode such a request encode_threshold = None #None = don't encode - def __init__(self, use_datetime=False, use_builtin_types=False): + def __init__(self, use_datetime=False, use_builtin_types=False, + use_python_exceptions=False): self._use_datetime = use_datetime self._use_builtin_types = use_builtin_types + self._use_python_exceptions = use_python_exceptions self._connection = (None, None) self._extra_headers = [] @@ -1174,7 +1202,8 @@ def getparser(self): # get parser and unmarshaller return getparser(use_datetime=self._use_datetime, - use_builtin_types=self._use_builtin_types) + use_builtin_types=self._use_builtin_types, + use_python_exceptions=self._use_python_exceptions) ## # Get authorization info from host parameter @@ -1380,7 +1409,8 @@ """ def __init__(self, uri, transport=None, encoding=None, verbose=False, - allow_none=False, use_datetime=False, use_builtin_types=False): + allow_none=False, use_datetime=False, use_builtin_types=False, + use_python_exceptions=False): # establish a "logical" server connection # get the url @@ -1397,7 +1427,8 @@ else: handler = Transport transport = handler(use_datetime=use_datetime, - use_builtin_types=use_builtin_types) + use_builtin_types=use_builtin_types, + use_python_exceptions=use_python_exceptions) self.__transport = transport self.__encoding = encoding or 'utf-8'