Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions gocardless_pro/api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,18 @@ def _handle_errors(self, response):
response_body = response.json()
except ValueError:
msg = 'Malformed response received from server'
raise errors.MalformedResponseError(msg, response.text)
raise errors.MalformedResponseError(msg, response.text, response.status_code)

if response.status_code < 400:
return

if not isinstance(response_body, dict):
raise errors.MalformedResponseError(
'Malformed response received from server',
response.text,
response.status_code,
)

error = response_body.get('error', response_body)

if isinstance(error, str):
Expand All @@ -139,8 +146,14 @@ def _handle_errors(self, response):
'message': error,
}
exception_class = errors.ApiError
else:
elif isinstance(error, dict) and 'type' in error:
exception_class = errors.ApiError.exception_for(response.status_code, error['type'], error.get('errors'))
else:
raise errors.MalformedResponseError(
'Malformed response received from server',
response.text,
response.status_code,
)

raise exception_class(error)

Expand Down
21 changes: 19 additions & 2 deletions gocardless_pro/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,26 @@ class RateLimitError(ApiError):

class MalformedResponseError(GoCardlessProError):

def __init__(self, message, response):
super(MalformedResponseError, self).__init__(message)
BODY_PREVIEW_MAX_LENGTH = 500

def __init__(self, message, response, status_code=None):
self.status_code = status_code
self.response = response
super(MalformedResponseError, self).__init__(
self._build_message(message, status_code, response)
)

@classmethod
def _build_message(cls, message, status_code, response):
parts = [message]
if status_code is not None:
parts.append('(HTTP {})'.format(status_code))
full = ' '.join(parts)
if response:
preview = response if len(response) <= cls.BODY_PREVIEW_MAX_LENGTH \
else response[:cls.BODY_PREVIEW_MAX_LENGTH] + '...'
full = '{}: {}'.format(full, preview)
return full


class InvalidSignatureError(GoCardlessProError):
Expand Down
2 changes: 1 addition & 1 deletion gocardless_pro/services/billing_request_flows_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def initialise(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down
18 changes: 9 additions & 9 deletions gocardless_pro/services/billing_requests_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def collect_customer_details(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down Expand Up @@ -126,7 +126,7 @@ def collect_bank_account(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand All @@ -153,7 +153,7 @@ def confirm_payer_details(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand All @@ -179,7 +179,7 @@ def fulfil(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand All @@ -205,7 +205,7 @@ def cancel(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down Expand Up @@ -284,7 +284,7 @@ def notify(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand All @@ -309,7 +309,7 @@ def fallback(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down Expand Up @@ -339,7 +339,7 @@ def choose_currency(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand All @@ -363,7 +363,7 @@ def select_institution(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down
6 changes: 3 additions & 3 deletions gocardless_pro/services/blocks_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def disable(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand All @@ -138,7 +138,7 @@ def enable(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand All @@ -162,7 +162,7 @@ def block_by_ref(self,params=None, headers=None):
path = '/blocks/block_by_ref'

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down
2 changes: 1 addition & 1 deletion gocardless_pro/services/creditor_bank_accounts_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ def disable(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down
2 changes: 1 addition & 1 deletion gocardless_pro/services/customer_bank_accounts_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def disable(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down
2 changes: 1 addition & 1 deletion gocardless_pro/services/customer_notifications_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def handle(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down
2 changes: 1 addition & 1 deletion gocardless_pro/services/funds_availabilities_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class FundsAvailabilitiesService(base_service.BaseService):
"""

RESOURCE_CLASS = resources.FundsAvailability
RESOURCE_NAME = 'funds_availabilities'
RESOURCE_NAME = 'funds_availability'


def check(self,identity,params=None, headers=None):
Expand Down
2 changes: 1 addition & 1 deletion gocardless_pro/services/instalment_schedules_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ def cancel(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down
4 changes: 2 additions & 2 deletions gocardless_pro/services/mandate_imports_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def submit(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down Expand Up @@ -133,7 +133,7 @@ def cancel(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down
4 changes: 2 additions & 2 deletions gocardless_pro/services/mandates_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ def cancel(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down Expand Up @@ -178,7 +178,7 @@ def reinstate(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down
6 changes: 3 additions & 3 deletions gocardless_pro/services/outbound_payments_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def withdraw(self,params=None, headers=None):
path = '/outbound_payments/withdrawal'

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down Expand Up @@ -88,7 +88,7 @@ def cancel(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand All @@ -113,7 +113,7 @@ def approve(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down
4 changes: 2 additions & 2 deletions gocardless_pro/services/payer_authorisations_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ def submit(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down Expand Up @@ -164,7 +164,7 @@ def confirm(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down
4 changes: 2 additions & 2 deletions gocardless_pro/services/payments_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def cancel(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down Expand Up @@ -182,7 +182,7 @@ def retry(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down
2 changes: 1 addition & 1 deletion gocardless_pro/services/redirect_flows_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ def complete(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down
2 changes: 1 addition & 1 deletion gocardless_pro/services/scenario_simulators_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def run(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down
6 changes: 3 additions & 3 deletions gocardless_pro/services/subscriptions_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ def pause(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down Expand Up @@ -246,7 +246,7 @@ def resume(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down Expand Up @@ -275,7 +275,7 @@ def cancel(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down
2 changes: 1 addition & 1 deletion gocardless_pro/services/webhooks_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def retry(self,identity,params=None, headers=None):
})

if params is not None:
params = {'data': params}
params = {self._envelope_key(): params}
response = self._perform_request('POST', path, params, headers,
retry_failures=False)
return self._resource_for(response)
Expand Down
13 changes: 13 additions & 0 deletions tests/api_client_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,19 @@ def test_handles_malformed_response():
with pytest.raises(errors.MalformedResponseError):
client.post('/test', body={'name': 'Billy Jean'})

@responses.activate
def test_includes_status_code_and_body_for_non_json_error_response():
body = '<html>502 Bad Gateway</html>'
responses.add(responses.POST, 'http://example.com/test',
body=body, status=502)

with pytest.raises(errors.MalformedResponseError) as exception:
client.post('/test', body={'name': 'Billy Jean'})

assert exception.value.status_code == 502
assert exception.value.response == body
assert 'HTTP 502' in str(exception.value)

@responses.activate
def test_handles_valid_empty_response():
responses.add(responses.DELETE, 'http://example.com/test', body='', status=204)
Expand Down
Loading