From 5668df91ddd56a65b8910bba581cc40f2b984caa Mon Sep 17 00:00:00 2001 From: Bart van den Dool <2692194+bcvandendool@users.noreply.github.com> Date: Mon, 4 Jan 2021 15:57:51 +0100 Subject: [PATCH 1/2] fix: add reduce to allow errors to be pickled --- python_http_client/exceptions.py | 22 +++++++++++++++++----- tests/test_unit.py | 20 ++++++++++++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/python_http_client/exceptions.py b/python_http_client/exceptions.py index b6343f2..2a8c179 100644 --- a/python_http_client/exceptions.py +++ b/python_http_client/exceptions.py @@ -4,11 +4,23 @@ class HTTPError(Exception): """ Base of all other errors""" - def __init__(self, error): - self.status_code = error.code - self.reason = error.reason - self.body = error.read() - self.headers = error.hdrs + def __init__(self, *args): + if len(args) == 4: + self.status_code = args[0] + self.reason = args[1] + self.body = args[2] + self.headers = args[3] + else: + self.status_code = args[0].code + self.reason = args[0].reason + self.body = args[0].read() + self.headers = args[0].hdrs + + def __reduce__(self): + return ( + HTTPError, + (self.status_code, self.reason, self.body, self.headers) + ) @property def to_dict(self): diff --git a/tests/test_unit.py b/tests/test_unit.py index 36b115f..f5e47c2 100644 --- a/tests/test_unit.py +++ b/tests/test_unit.py @@ -7,6 +7,7 @@ BadRequestsError, NotFoundError, ServiceUnavailableError, + UnauthorizedError, UnsupportedMediaTypeError, ) @@ -208,6 +209,25 @@ def test_client_pickle_unpickle(self): "original client and unpickled client must have the same state" ) + @mock.patch('python_http_client.client.urllib') + def test_pickle_error(self, mock_lib): + mock_opener = MockOpener() + mock_lib.build_opener.return_value = mock_opener + + client = self.client.__getattr__('hello') + + mock_opener.response_code = 401 + try: + client.get() + except UnauthorizedError as e: + pickled_error = pickle.dumps(e) + unpickled_error = pickle.loads(pickled_error) + self.assertDictEqual( + e.__dict__, + unpickled_error.__dict__, + "original error and unpickled error must have the same state" + ) + if __name__ == '__main__': unittest.main() From c75074c200e242b1cbd2ebfbd18e96d80a302c87 Mon Sep 17 00:00:00 2001 From: Bart van den Dool <2692194+bcvandendool@users.noreply.github.com> Date: Tue, 12 Jan 2021 19:36:21 +0100 Subject: [PATCH 2/2] fix: pickling test case handle python 2 python 2 adds a __cause__ that is None to the __dict__ of the thrown error, failing the assertion --- tests/test_unit.py | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/tests/test_unit.py b/tests/test_unit.py index f5e47c2..be85543 100644 --- a/tests/test_unit.py +++ b/tests/test_unit.py @@ -222,10 +222,26 @@ def test_pickle_error(self, mock_lib): except UnauthorizedError as e: pickled_error = pickle.dumps(e) unpickled_error = pickle.loads(pickled_error) - self.assertDictEqual( - e.__dict__, - unpickled_error.__dict__, - "original error and unpickled error must have the same state" + + self.assertEqual( + e.status_code, + unpickled_error.status_code, + "unpickled error must have the same status code", + ) + self.assertEqual( + e.reason, + unpickled_error.reason, + "unpickled error must have the same reason", + ) + self.assertEqual( + e.body, + unpickled_error.body, + "unpickled error must have the same body", + ) + self.assertEqual( + e.headers, + unpickled_error.headers, + "unpickled error must have the same headers", )