Skip to content

Commit

Permalink
Merge pull request #3 from maxmind/greg/clean-request
Browse files Browse the repository at this point in the history
Copy request dict and remove keys with None values
  • Loading branch information
2shortplanks committed Aug 10, 2015
2 parents 576480f + b433a4a commit a9e7057
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 9 deletions.
5 changes: 3 additions & 2 deletions minfraud/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,9 @@ def _uri(s):
'last_4_digits': _credit_card_last_4,
},
Required('device'): {
'accept_language': _unicode_or_printable_ascii, Required('ip_address'):
_ip_address, 'user_agent': _unicode_or_printable_ascii
'accept_language': _unicode_or_printable_ascii,
Required('ip_address'): _ip_address,
'user_agent': _unicode_or_printable_ascii
},
'email': {'address': _email_or_md5,
'domain': _hostname, },
Expand Down
21 changes: 16 additions & 5 deletions minfraud/webservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,16 +93,17 @@ def score(self, transaction, validate=True):

def _response_for(self, path, model_class, request, validate):
"""Send request and create response object"""
cleaned_request = self._copy_and_clean(request)
if validate:
try:
validate_transaction(request)
validate_transaction(cleaned_request)
except MultipleInvalid as ex:
raise InvalidRequestError(
"Invalid transaction data: {0}".format(ex))
uri = '/'.join([self._base_uri, path])
response = requests.post(
uri,
json=request,
json=cleaned_request,
auth=(self._user_id, self._license_key),
headers=
{'Accept': 'application/json',
Expand All @@ -113,6 +114,16 @@ def _response_for(self, path, model_class, request, validate):
else:
self._handle_error(response, uri)

def _copy_and_clean(self, data):
"""This returns a copy of the data structure with Nones removed"""
if isinstance(data, dict):
return dict((k, self._copy_and_clean(v)) for (k, v) in data.items()
if v is not None)
elif isinstance(data, (list, set, tuple)):
return [self._copy_and_clean(x) for x in data if x is not None]
else:
return data

def _user_agent(self):
"""Create User-Agent header"""
return 'minFraud-API/%s %s' % (__version__, default_user_agent())
Expand Down Expand Up @@ -154,9 +165,9 @@ def _handle_4xx_status(self, response, status, uri):
except ValueError:
raise HTTPError(
'Received a {status:d} error but it did not include'
' the expected JSON body: {content}'
.format(status=status,
content=response.content), status, uri)
' the expected JSON body: {content}'.format(
status=status,
content=response.content), status, uri)
else:
if 'code' in body and 'error' in body:
self._handle_web_service_error(body.get('error'),
Expand Down
28 changes: 26 additions & 2 deletions tests/test_webservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,24 @@ def test_200(self):
if self.type == 'insights':
self.assertEqual('United Kingdom', model.ip_address.country.name)

def test_200_on_request_with_nones(self):
model = self.create_success(
request={
'device': {
'ip_address': '81.2.69.160',
'accept_language': None
},
'event': {
'shop_id': None
},
'shopping_cart': [{
'category': None,
'quantity': 2,
}, None],
})
response = self.response
self.assertEqual(0.01, model.risk_score)

def test_200_with_locales(self):
locales = ('fr', )
client = Client(42, 'abcdef123456', locales=locales)
Expand Down Expand Up @@ -142,7 +160,11 @@ def create_error(self, mock, status_code=400, text='', headers=None):
return getattr(self.client, self.type)(self.full_request)

@requests_mock.mock()
def create_success(self, mock, text=None, headers=None, client=None):
def create_success(self, mock,
text=None,
headers=None,
client=None,
request=None):
if headers is None:
headers = {
'Content-Type':
Expand All @@ -158,7 +180,9 @@ def create_success(self, mock, text=None, headers=None, client=None):
headers=headers)
if client is None:
client = self.client
return getattr(client, self.type)(self.full_request)
if request is None:
request = self.full_request
return getattr(client, self.type)(request)


class TestInsights(BaseTest, unittest.TestCase):
Expand Down

0 comments on commit a9e7057

Please sign in to comment.