From edaa7550f04cee82e416f5632478e24204702f57 Mon Sep 17 00:00:00 2001 From: Uri Okrent Date: Thu, 9 Jun 2016 10:52:42 -0400 Subject: [PATCH] xmlrpc.client: make Errors pickleable Fault and other xmlrpc Errors weren't passing their arguments up to the BaseException constructor which sets the `args` attribute. As a result attempting to unpickle a Fault, for example, would raise: TypeError: __init__() missing 2 required positional arguments: 'faultCode' and 'faultString' Signed-off-by: Uri Okrent --- Lib/test/test_xmlrpc.py | 23 +++++++++++++++++++++++ Lib/xmlrpc/client.py | 4 ++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py index f2fdc44..3086ac9 100644 --- a/Lib/test/test_xmlrpc.py +++ b/Lib/test/test_xmlrpc.py @@ -13,6 +13,7 @@ import re import io import contextlib from test import support +import pickle try: import gzip @@ -316,6 +317,15 @@ class FaultTestCase(unittest.TestCase): s = xmlrpclib.Marshaller().dumps(f) self.assertRaises(xmlrpclib.Fault, xmlrpclib.loads, s) + def test_pickle_fault(self): + f = xmlrpclib.Fault(42, 'Test Fault') + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + s = pickle.dumps(f, proto) + newf = pickle.loads(s) + self.assertIsInstance(newf, xmlrpclib.Fault) + self.assertEqual(newf.faultCode, 42) + self.assertEqual(newf.faultString, 'Test Fault') + def test_dotted_attribute(self): # this will raise AttributeError because code don't want us to use # private methods @@ -323,6 +333,19 @@ class FaultTestCase(unittest.TestCase): xmlrpc.server.resolve_dotted_attribute, str, '__add') self.assertTrue(xmlrpc.server.resolve_dotted_attribute(str, 'title')) +class ProtocolErrorTestCase(unittest.TestCase): + def test_pickle_protocol_error(self): + f = xmlrpclib.ProtocolError('http://fake', 42, 'Some Error', + 'X-Fake-Header: foo') + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + s = pickle.dumps(f, proto) + newf = pickle.loads(s) + self.assertIsInstance(newf, xmlrpclib.ProtocolError) + self.assertEqual(newf.url, 'http://fake') + self.assertEqual(newf.errcode, 42) + self.assertEqual(newf.errmsg, 'Some Error') + self.assertEqual(newf.headers, 'X-Fake-Header: foo') + class DateTimeTestCase(unittest.TestCase): def test_default(self): with mock.patch('time.localtime') as localtime_mock: diff --git a/Lib/xmlrpc/client.py b/Lib/xmlrpc/client.py index 581a3b9..7ebd374 100644 --- a/Lib/xmlrpc/client.py +++ b/Lib/xmlrpc/client.py @@ -201,7 +201,7 @@ class Error(Exception): class ProtocolError(Error): """Indicates an HTTP protocol error.""" def __init__(self, url, errcode, errmsg, headers): - Error.__init__(self) + Error.__init__(self, url, errcode, errmsg, headers) self.url = url self.errcode = errcode self.errmsg = errmsg @@ -233,7 +233,7 @@ class ResponseError(Error): class Fault(Error): """Indicates an XML-RPC fault package.""" def __init__(self, faultCode, faultString, **extra): - Error.__init__(self) + Error.__init__(self, faultCode, faultString, **extra) self.faultCode = faultCode self.faultString = faultString def __repr__(self): -- 2.8.2