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
5 changes: 3 additions & 2 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[run]
source = hyperwallet
omit = venv/*
omit = hyperwallet/tests/*
omit =
venv/*
hyperwallet/tests/*
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ htmlcov
# Other
.DS_Store
.coverage
.idea/
5 changes: 5 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
Changelog
=========

1.1.2 (current)
------------------

- Added bank card endpoint

1.1.1 (2017-10-11)
------------------

Expand Down
2 changes: 1 addition & 1 deletion hyperwallet/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
__email__ = 'devsupport@hyperwallet.com'
__copyright__ = 'Copyright (c) 2017 Hyperwallet'
__license__ = 'MIT'
__version__ = '1.1.1'
__version__ = '1.1.2'
__url__ = 'https://github.com/hyperwallet/python-sdk'
__download_url__ = 'https://pypi.python.org/pypi/hyperwallet-sdk'
__description__ = 'A Python wrapper around the Hyperwallet API'
Expand Down
106 changes: 72 additions & 34 deletions hyperwallet/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import os

from config import SERVER
from exceptions import HyperwalletException
from utils import ApiClient
from .config import SERVER
from .exceptions import HyperwalletException
from .utils import ApiClient

from hyperwallet import (
User,
Expand Down Expand Up @@ -155,37 +155,6 @@ def listUsers(self,

return [User(x) for x in response.get('data', [])]

def createUserStatusTransition(self,
userToken=None,
data=None):
'''
Create a User Status Transition.

:param userToken:
A token identifying the User. **REQUIRED**
:param data:
A dictionary containing User Status Transition information. **REQUIRED**
:returns:
A User Status Transition.
'''

if not userToken:
raise HyperwalletException('userToken is required')

if not data:
raise HyperwalletException('data is required')

response = self.apiClient.doPost(
os.path.join(
'users',
userToken,
'status-transitions'
),
data
)

return StatusTransition(response)

def getUserStatusTransition(self,
userToken=None,
statusTransitionToken=None):
Expand Down Expand Up @@ -821,6 +790,44 @@ def createPrepaidCard(self,

return PrepaidCard(response)

def updatePrepaidCard(self,
userToken=None,
prepaidCardToken=None,
data=None):
'''
Update a Prepaid Card.

:param userToken:
A token identifying the User. **REQUIRED**
:param prepaidCardToken:
A token identifying the Prepaid Card. **REQUIRED**
:param data:
A dictionary containing Prepaid Card information. **REQUIRED**
:returns:
A Prepaid Card.
'''

if not userToken:
raise HyperwalletException('userToken is required')

if not prepaidCardToken:
raise HyperwalletException('prepaidCardToken is required')

if not data:
raise HyperwalletException('data is required')

response = self.apiClient.doPut(
os.path.join(
'users',
userToken,
'prepaid-cards',
prepaidCardToken
),
data
)

return PrepaidCard(response)

def getPrepaidCard(self,
userToken=None,
prepaidCardToken=None):
Expand Down Expand Up @@ -1560,6 +1567,37 @@ def listPaymentStatusTransitions(self,

return [StatusTransition(x) for x in response.get('data', [])]

def createPaymentStatusTransition(self,
paymentToken=None,
data=None):
'''
Create Payment Status Transition.

:param paymentToken:
A token identifying the Payment. **REQUIRED**
:param data:
A dictionary containing User Status Transition information. **REQUIRED**
:returns:
A Payment Status Transition.
'''

if not paymentToken:
raise HyperwalletException('paymentToken is required')

if not data:
raise HyperwalletException('data is required')

response = self.apiClient.doPost(
os.path.join(
'payments',
paymentToken,
'status-transitions'
),
data
)

return StatusTransition(response)

'''

Balances
Expand Down
8 changes: 8 additions & 0 deletions hyperwallet/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,16 @@ class HyperwalletException(Exception):
An Exception raised when the SDK is used incorrectly.
'''

@property
def message(self):
return self.__dict__.get('message', None) or getattr(self, 'args')[0]


class HyperwalletAPIException(Exception):
'''
An Exception raised when the API response is an error.
'''

@property
def message(self):
return self.__dict__.get('message', None) or getattr(self, 'args')[0]
73 changes: 51 additions & 22 deletions hyperwallet/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,28 +131,6 @@ def test_list_users_success(self, mock_get):

self.assertEqual(response[0].token, self.data.get('token'))

def test_create_user_status_transition_fail_need_user_token(self):

with self.assertRaises(HyperwalletException) as exc:
self.api.createUserStatusTransition()

self.assertEqual(exc.exception.message, 'userToken is required')

def test_create_user_status_transition_fail_need_data(self):

with self.assertRaises(HyperwalletException) as exc:
self.api.createUserStatusTransition('token')

self.assertEqual(exc.exception.message, 'data is required')

@mock.patch('hyperwallet.utils.ApiClient._makeRequest')
def test_create_user_status_transition_success(self, mock_post):

mock_post.return_value = self.data
response = self.api.createUserStatusTransition('token', self.data)

self.assertTrue(response.token, self.data.get('token'))

def test_get_user_status_transition_fail_need_user_token(self):

with self.assertRaises(HyperwalletException) as exc:
Expand Down Expand Up @@ -632,6 +610,35 @@ def test_create_prepaid_card_success(self, mock_post):

self.assertTrue(response.token, self.data.get('token'))

def test_update_prepaid_card_fail_need_user_token(self):

with self.assertRaises(HyperwalletException) as exc:
self.api.updatePrepaidCard()

self.assertEqual(exc.exception.message, 'userToken is required')

def test_update_prepaid_card_fail_need_card_token(self):

with self.assertRaises(HyperwalletException) as exc:
self.api.updatePrepaidCard('token')

self.assertEqual(exc.exception.message, 'prepaidCardToken is required')

def test_update_prepaid_card_fail_need_data(self):

with self.assertRaises(HyperwalletException) as exc:
self.api.updatePrepaidCard('token', 'token')

self.assertEqual(exc.exception.message, 'data is required')

@mock.patch('hyperwallet.utils.ApiClient._makeRequest')
def test_update_prepaid_card_success(self, mock_put):

mock_put.return_value = self.data
response = self.api.updatePrepaidCard('token', 'token', self.data)

self.assertTrue(response.token, self.data.get('token'))

def test_get_prepaid_card_fail_need_user_token(self):

with self.assertRaises(HyperwalletException) as exc:
Expand Down Expand Up @@ -1235,6 +1242,28 @@ def test_list_payment_status_transitions_success(self, mock_get):

self.assertTrue(response[0].token, self.data.get('token'))

def test_create_payment_status_transition_fail_need_payment_token(self):

with self.assertRaises(HyperwalletException) as exc:
self.api.createPaymentStatusTransition()

self.assertEqual(exc.exception.message, 'paymentToken is required')

def test_create_payment_status_transition_fail_need_data(self):

with self.assertRaises(HyperwalletException) as exc:
self.api.createPaymentStatusTransition('token')

self.assertEqual(exc.exception.message, 'data is required')

@mock.patch('hyperwallet.utils.ApiClient._makeRequest')
def test_create_payment_status_transition_success(self, mock_post):

mock_post.return_value = self.data
response = self.api.createPaymentStatusTransition('token', self.data)

self.assertTrue(response.token, self.data.get('token'))

'''

Balances
Expand Down
6 changes: 5 additions & 1 deletion hyperwallet/tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,13 @@ def test_receive_valid_json_response(self, session_mock):
content=json.dumps(data)
)

encoded = json.dumps(data)
if hasattr(encoded, 'decode'): # Python 2
encoded = encoded.decode('utf-8')

self.assertEqual(
self.client._makeRequest(),
json.loads(json.dumps(data).decode('utf-8'))
json.loads(encoded)
)


Expand Down
5 changes: 1 addition & 4 deletions hyperwallet/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@

import json
import unittest
import hyperwallet

from hyperwallet.exceptions import HyperwalletException

from hyperwallet import (
HyperwalletModel,
Expand Down Expand Up @@ -374,7 +371,7 @@ def test_transfer_method_configuration_model(self):
transfer_method_configuration_data
)

print transfer_method_configuration_data.get('countries')
print(transfer_method_configuration_data.get('countries'))
self.assertEqual(
test_transfer_method_configuration.__repr__(),
'TransferMethodConfiguration({country}, {type})'.format(
Expand Down
18 changes: 11 additions & 7 deletions hyperwallet/utils/apiclient.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
#!/usr/bin/env python

import sys
import ssl
import json
import urlparse
import requests

from hyperwallet.exceptions import HyperwalletAPIException
from requests_toolbelt.adapters.ssl import SSLAdapter
from hyperwallet import __version__
try:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd consider using six or future library.
Six:
http://six.readthedocs.io/
from six.moves import urllib or alternatively conditional using six.PY2 or six.PY3 variables.

Future:
http://python-future.org/compatible_idioms.html#urllib-module

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the feedback, we will consider it for the next update

from urllib.parse import urljoin
except ImportError:
from urlparse import urljoin # Python 2


class ApiClient(object):
Expand Down Expand Up @@ -42,7 +44,7 @@ def __init__(self, username, password, server):
self.server = server

# The complete base URL of the API.
self.baseUrl = urlparse.urljoin(self.server, '/rest/v3/')
self.baseUrl = urljoin(self.server, '/rest/v3/')

# The default connection to persist authentication and SSL settings.
defaultSession = requests.Session()
Expand Down Expand Up @@ -81,7 +83,7 @@ def _makeRequest(self,
try:
response = self.session.request(
method=method,
url=urlparse.urljoin(self.baseUrl, url),
url=urljoin(self.baseUrl, url),
data=data,
headers=headers,
params=params
Expand All @@ -93,15 +95,17 @@ def _makeRequest(self,
'code': 'COMMUNICATION_ERROR',
'message': 'Connection to {} failed: {}'.format(
self.server,
e.message
e.args[0]
)
}]
})

if response.status_code is 204:
return {}

content = response.content.decode('utf-8')
content = response.content
if hasattr(content, 'decode'): # Python 2
content = content.decode('utf-8')

try:
json_body = json.loads(content)
Expand All @@ -110,7 +114,7 @@ def _makeRequest(self,
raise HyperwalletAPIException({
'errors': [{
'code': 'GARBAGE_RESPONSE',
'message': 'Invalid response: {}'.format(e.message)
'message': 'Invalid response: {}'.format(e.args[0])
}]
})

Expand Down