Skip to content

Commit a01f905

Browse files
committed
Merge branch 'dev' of https://github.com/osmlab/maproulette-python-client into batch_add_tasks
2 parents 8d23207 + 47ac6e3 commit a01f905

3 files changed

Lines changed: 91 additions & 44 deletions

File tree

maproulette/api/errors.py

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,65 @@
33

44
class MapRouletteBaseException(Exception):
55
"""MapRoulette Base Exception"""
6-
def __init__(self, message, status=None, payload=None):
6+
def __init__(self, message, status, payload):
77
self.message = message
88
self.status = status
99
self.payload = payload
1010

1111
def __str__(self):
12-
return repr({
12+
error = {
1313
"status": self.status,
1414
"message": self.message,
1515
"payload": self.payload
16-
})
16+
}
17+
return repr({k: v for (k, v) in error.items() if v is not None})
1718

1819

1920
class NotFoundError(MapRouletteBaseException):
2021
"""Resource cannot be found"""
22+
def __init__(self, message=None, status=None, payload=None):
23+
if message:
24+
self.message = message
25+
else:
26+
self.message = "Resource cannot be found."
27+
super().__init__(message=self.message, status=status, payload=payload)
2128

2229

2330
class ConnectionUnavailableError(MapRouletteBaseException):
2431
"""A connection error occurred"""
32+
def __init__(self, message=None, status=None, payload=None):
33+
if message:
34+
self.message = message
35+
else:
36+
self.message = "A connection error occurred."
37+
super().__init__(message=self.message, status=status, payload=payload)
2538

2639

2740
class UnauthorizedError(MapRouletteBaseException):
2841
"""The user is not authorized to make this request"""
42+
def __init__(self, message=None, status=None, payload=None):
43+
if message:
44+
self.message = message
45+
else:
46+
self.message = "The user is not authorized to make this request."
47+
super().__init__(message=self.message, status=status, payload=payload)
2948

3049

3150
class HttpError(MapRouletteBaseException):
3251
"""An HTTP error occurred"""
52+
def __init__(self, message=None, status=None, payload=None):
53+
if message:
54+
self.message = message
55+
else:
56+
self.message = "An HTTP error occurred."
57+
super().__init__(message=self.message, status=status, payload=payload)
3358

3459

3560
class InvalidJsonError(MapRouletteBaseException):
3661
"""Errors produced from an invalid JSON object"""
62+
def __init__(self, message=None, status=None, payload=None):
63+
if message:
64+
self.message = message
65+
else:
66+
self.message = "Invalid JSON payload."
67+
super().__init__(message=self.message, status=status, payload=payload)

maproulette/api/maproulette_server.py

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -65,28 +65,25 @@ def get(self, endpoint, params=None):
6565
except requests.exceptions.HTTPError as e:
6666
if e.response.status_code == 404:
6767
raise NotFoundError(
68-
message='Resource not found',
69-
status=e.response.status_code,
70-
payload=e.response
68+
message=self.parse_response_message(e.response),
69+
status=e.response.status_code
7170
) from None
7271
else:
7372
raise HttpError(
74-
message='An HTTP error occurred',
75-
status=e.response.status_code,
76-
payload=e.response
73+
message=self.parse_response_message(e.response),
74+
status=e.response.status_code
7775
) from None
7876
except (requests.ConnectionError, requests.Timeout) as e:
7977
raise ConnectionUnavailableError(
80-
message="Connection Unavailable",
81-
status=e.response.status_code,
82-
payload=response
78+
message=self.parse_response_message(e.response),
79+
status=e.response.status_code
8380
) from None
8481
try:
8582
return {
8683
"data": response.json(),
8784
"status": response.status_code
8885
}
89-
except json.decoder.JSONDecodeError:
86+
except ValueError:
9087
return {
9188
"status": response.status_code
9289
}
@@ -109,21 +106,18 @@ def post(self, endpoint, body=None, params=None):
109106
except requests.exceptions.HTTPError as e:
110107
if e.response.status_code == 400:
111108
raise InvalidJsonError(
112-
message='Invalid JSON payload',
113-
status=e.response.status_code,
114-
payload=e.response
109+
message=self.parse_response_message(e.response),
110+
status=e.response.status_code
115111
) from None
116112
elif e.response.status_code == 401:
117113
raise UnauthorizedError(
118-
message='The user is not authorized to make this request',
119-
status=e.response.status_code,
120-
payload=e.response
114+
message=self.parse_response_message(e.response),
115+
status=e.response.status_code
121116
) from None
122117
else:
123118
raise HttpError(
124-
message='An HTTP error occurred',
125-
status=e.response.status_code,
126-
payload=e.response
119+
message=self.parse_response_message(e.response),
120+
status=e.response.status_code
127121
) from None
128122
except (requests.ConnectionError, requests.Timeout) as e:
129123
raise ConnectionUnavailableError(e) from None
@@ -132,7 +126,7 @@ def post(self, endpoint, body=None, params=None):
132126
"data": response.json(),
133127
"status": response.status_code
134128
}
135-
except json.decoder.JSONDecodeError:
129+
except ValueError:
136130
return {
137131
"status": response.status_code
138132
}
@@ -155,21 +149,18 @@ def put(self, endpoint, body=None, params=None):
155149
except requests.exceptions.HTTPError as e:
156150
if e.response.status_code == 400:
157151
raise InvalidJsonError(
158-
message='Invalid JSON payload',
159-
status=e.response.status_code,
160-
payload=e.response
152+
message=self.parse_response_message(e.response),
153+
status=e.response.status_code
161154
) from None
162155
elif e.response.status_code == 401:
163156
raise UnauthorizedError(
164-
message='The user is not authorized to make this request',
165-
status=e.response.status_code,
166-
payload=e.response
157+
message=self.parse_response_message(e.response),
158+
status=e.response.status_code
167159
) from None
168160
else:
169161
raise HttpError(
170-
message='An HTTP error occurred',
171-
status=e.response.status_code,
172-
payload=e.response
162+
message=self.parse_response_message(e.response),
163+
status=e.response.status_code
173164
) from None
174165
except (requests.ConnectionError, requests.Timeout) as e:
175166
raise ConnectionUnavailableError(e) from None
@@ -178,7 +169,7 @@ def put(self, endpoint, body=None, params=None):
178169
"data": response.json(),
179170
"status": response.status_code
180171
}
181-
except json.decoder.JSONDecodeError:
172+
except ValueError:
182173
return {
183174
"status": response.status_code
184175
}
@@ -199,21 +190,18 @@ def delete(self, endpoint, params=None):
199190
except requests.exceptions.HTTPError as e:
200191
if e.response.status_code == 401:
201192
raise UnauthorizedError(
202-
message='The user is not authorized to make this request',
203-
status=e.response.status_code,
204-
payload=e.response
193+
message=self.parse_response_message(e.response),
194+
status=e.response.status_code
205195
) from None
206196
elif e.response.status_code == 404:
207197
raise NotFoundError(
208-
message='Resource not found',
209-
status=e.response.status_code,
210-
payload=e.response
198+
message=self.parse_response_message(e.response),
199+
status=e.response.status_code
211200
) from None
212201
else:
213202
raise HttpError(
214-
message='An HTTP error occurred',
215-
status=e.response.status_code,
216-
payload=e.response
203+
message=self.parse_response_message(e.response),
204+
status=e.response.status_code
217205
) from None
218206
except (requests.ConnectionError, requests.Timeout) as e:
219207
raise ConnectionUnavailableError(e) from None
@@ -222,7 +210,7 @@ def delete(self, endpoint, params=None):
222210
"data": response.json(),
223211
"status": response.status_code
224212
}
225-
except json.decoder.JSONDecodeError:
213+
except ValueError:
226214
return {
227215
"status": response.status_code
228216
}
@@ -240,3 +228,15 @@ def is_json(input_object):
240228
return True
241229
except ValueError:
242230
return False
231+
232+
@staticmethod
233+
def parse_response_message(response):
234+
"""Method to determine the message body from a response object. Will return None if message cannot be parsed.
235+
236+
:param response: the Requests response object
237+
:returns: the response message if parsable, otherwise None
238+
"""
239+
try:
240+
return json.loads(response.text)['message']
241+
except (ValueError, KeyError):
242+
return None

tests/test_server.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ def test_get_not_found_error(self, mock_get, mock_server_get, server_instance=se
2626
server_instance.get(endpoint='')
2727
assert context.exception.message == 'Resource not found'
2828
assert context.exception.status == 404
29-
assert context.exception.payload == 'error payload'
3029

3130
@patch('maproulette.api.maproulette_server.MapRouletteServer.get')
3231
@patch('requests.Session.get')
@@ -265,3 +264,20 @@ def test_delete_connection_error(self, mock_delete, mock_server_delete, server_i
265264
assert context.exception.message == 'Connection Unavailable'
266265
assert context.exception.status == 500
267266
assert context.exception.payload == 'error payload'
267+
268+
@patch('json.loads')
269+
def test_parse_response_message(self, mock_loads, server_instance=server):
270+
mock_loads.return_value = {
271+
'message': 'some message'
272+
}
273+
self.assertTrue(server_instance.parse_response_message(mock_loads))
274+
275+
@patch('json.loads')
276+
def test_parse_response_message_value_error(self, mock_loads, server_instance=server):
277+
mock_loads.side_effect = ValueError()
278+
self.assertIsNone(server_instance.parse_response_message(mock_loads))
279+
280+
@patch('json.loads')
281+
def test_parse_response_message_key_error(self, mock_loads, server_instance=server):
282+
mock_loads.side_effect = KeyError()
283+
self.assertIsNone(server_instance.parse_response_message(mock_loads))

0 commit comments

Comments
 (0)