Skip to content

Commit 9ccc955

Browse files
hughesbmlasley
authored andcommitted
[FIX] Handle null response body from delete methods (#37)
* [FIX] Handle null response body from delete methods * Set response_json to empty dict if no response body * Return None from RequestPaginator._call if no response body * Return None instead of API object if no response body * [ADD] Add test
1 parent 748f8a5 commit 9ccc955

File tree

4 files changed

+25
-13
lines changed

4 files changed

+25
-13
lines changed

helpscout/base_api.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,10 @@ def __new__(cls, endpoint, data=None,
7171
)
7272
if singleton:
7373
results = paginator.call(paginator.data)
74-
result_length = len(results)
75-
if result_length == 0:
74+
try:
75+
return out_type.from_api(**results[0])
76+
except (IndexError, TypeError):
7677
return None
77-
return out_type.from_api(**results[0])
7878
obj = super(BaseApi, cls).__new__(cls)
7979
obj.paginator = paginator
8080
return obj

helpscout/request_paginator/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ def _call(self, method, *args, **kwargs):
143143
kwargs['verify'] = self.SSL_VERIFY
144144

145145
response = method(*args, **kwargs)
146-
response_json = response.json()
146+
response_json = response.text and response.json() or {}
147147

148148
if response.status_code < 200 or response.status_code >= 300:
149149
message = response_json.get('error', response_json.get('message'))
@@ -162,4 +162,4 @@ def _call(self, method, *args, **kwargs):
162162
except KeyError:
163163
pass
164164

165-
return True
165+
return None

helpscout/tests/test_base_api.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,19 @@ def test_new_paginator_singleton(self, paginator):
6161
self.assertEqual(res.id, 9876)
6262

6363
@mock.patch(PAGINATOR)
64-
def test_new_paginator_singleton_none(self, paginator):
64+
def test_new_paginator_singleton_not_found(self, paginator):
6565
"""It should return None if singleton and not found."""
6666
paginator().call.return_value = []
6767
res = self.new_api(singleton=True)
6868
self.assertIs(res, None)
6969

70+
@mock.patch(PAGINATOR)
71+
def test_new_paginator_singleton_none(self, paginator):
72+
"""It should return None if singleton and return value is None."""
73+
paginator().call.return_value = None
74+
res = self.new_api(singleton=True)
75+
self.assertIs(res, None)
76+
7077
@mock.patch(PAGINATOR)
7178
def test_base_api_iterates_paginator(self, paginator):
7279
"""It should pass iteration to the paginator."""

helpscout/tests/test_request_paginator.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,6 @@ def setUp(self):
4949
@contextmanager
5050
def mock_session(self, response_code=200, responses=None,
5151
mock_attrs=None):
52-
if responses is None:
53-
responses = self.test_responses
5452
if mock_attrs is None:
5553
mock_attrs = ['get', 'delete', 'post', 'put']
5654
elif isinstance(mock_attrs, str):
@@ -59,14 +57,16 @@ def mock_session(self, response_code=200, responses=None,
5957
response = mock.MagicMock()
6058
response.status_code = response_code
6159
response.json.side_effect = responses
60+
response.json.return_value = responses
6261
for attr in mock_attrs:
6362
method = getattr(session, attr)
6463
method.return_value = response
6564
yield session
6665

67-
def do_call(self, request_type='get'):
66+
def do_call(self, request_type='get', responses=None):
6867
self.params = {'param_test': 23234}
69-
with self.mock_session(mock_attrs=request_type) as session:
68+
with self.mock_session(mock_attrs=request_type,
69+
responses=responses) as session:
7070
return session, getattr(self.paginator, request_type)(self.params)
7171

7272
def _test_result(self, res):
@@ -96,7 +96,7 @@ def test_init_session(self, requests):
9696

9797
def test_get_gets(self):
9898
""" It should call the session with proper args. """
99-
session, _ = self.do_call()
99+
session, _ = self.do_call(responses=self.test_responses)
100100
session.get.assert_called_once_with(
101101
url=self.vals['endpoint'],
102102
params=self.params,
@@ -106,14 +106,19 @@ def test_get_gets(self):
106106
def test_returns(self):
107107
"""The returns should all return properly."""
108108
for request_type in self.REQUEST_TYPES:
109-
_, res = self.do_call(request_type)
109+
_, res = self.do_call(request_type, self.test_responses)
110110
self._test_result(res)
111111

112+
def test_delete_return_null_response_body(self):
113+
"""The delete return should be None if response body is null."""
114+
_, res = self.do_call('delete', None)
115+
self.assertEqual(res, None)
116+
112117
def test_session_calls(self):
113118
"""The calls should all be handled properly (tests all but GET)."""
114119
self.REQUEST_TYPES.remove('get')
115120
for request_type in self.REQUEST_TYPES:
116-
session, _ = self.do_call(request_type)
121+
session, _ = self.do_call(request_type, self.test_responses)
117122
self._test_session_call_json(session, request_type)
118123

119124
def test_call_get(self):

0 commit comments

Comments
 (0)