From 92f203bf1ba342ede3ba8e07655012fb3fe101bd Mon Sep 17 00:00:00 2001 From: Oleg Belousov Date: Thu, 2 Feb 2017 18:18:34 +0200 Subject: [PATCH] PEP8, correct errors, sensible exit codes --- samples/generate_pat.py | 17 ++--- samples/test.py | 54 +++++++++++----- setup.py | 21 ++++--- tests.py | 22 +++++-- uphold/uphold.py | 133 ++++++++++++++++++++++++++-------------- 5 files changed, 164 insertions(+), 83 deletions(-) diff --git a/samples/generate_pat.py b/samples/generate_pat.py index 1c909e1..23b7633 100644 --- a/samples/generate_pat.py +++ b/samples/generate_pat.py @@ -1,20 +1,22 @@ from __future__ import print_function, unicode_literals -import urllib3 import getpass import sys -sys.path.append('.') +import urllib3 + from uphold import * +sys.path.append('.') + #input('You are about to generate a persistent Personal Access Token on Uphold. Press ENTER to continue. ') -un = input("Uphold username: ").rstrip() -pw = getpass.getpass("Uphold password: ").rstrip() +un = input("Uphold username: ").rstrip() +pw = getpass.getpass("Uphold password: ").rstrip() desc = input("Label/description for PAT (optional): ").rstrip() -api = Uphold(True) -api.auth_basic( un, pw ) +api = Uphold(True) +api.auth_basic(un, pw) pat = None @@ -30,7 +32,7 @@ print("Error again: " + repr(e2)) except Exception as e: print("An unexpected error occurred: " + repr(e)) - exit(0); + exit(0) if pat is not None: print("Your PAT is: " + pat) @@ -38,4 +40,3 @@ print("Failed to generate PAT") exit(0) - diff --git a/samples/test.py b/samples/test.py index ca9816c..a52aaf1 100644 --- a/samples/test.py +++ b/samples/test.py @@ -1,22 +1,25 @@ from __future__ import print_function, unicode_literals -import urllib3 import locale +import sys + +import urllib3 + +from uphold import * + try: from configparser import ConfigParser -except: +except ImportError: from ConfigParser import ConfigParser -import sys -sys.path.append('.') -from uphold import * +sys.path.append('.') locale.setlocale(locale.LC_ALL, 'en_US') Config = ConfigParser() Config.read('samples/config.ini') api = Uphold() -api.auth_pat( Config.get('Settings','pat') ) +api.auth_pat(Config.get('Settings', 'pat')) print("Getting user data...") me = api.get_me() @@ -31,13 +34,14 @@ card_id = cards[0]['id'] print("\nGetting card labeled '" + cards[0]['label'] + "'") -card = api.get_card( cards[0]['id'] ) +card = api.get_card(cards[0]['id']) print("Available balance: " + card['available']) print("\nGetting contacts...") contacts = api.get_contacts() for contact in contacts: - if contact and contact['firstName'] is not None and contact['lastName'] is not None: + if contact and contact['firstName'] is not None and contact[ + 'lastName'] is not None: print(contact['firstName'] + " " + contact['lastName']) print("\nGetting phones...") @@ -56,10 +60,24 @@ i += 1 if i > 20: break - if entry["in"]: - print(str(i) + ". " + entry['type'] + ": +" + entry["in"]["amount"] + " " + entry["in"]["currency"]) - if entry["out"]: - print(str(i) + ". " + entry['type'] + ": -" + entry["in"]["amount"] + " " + entry["in"]["currency"]) + if entry["in"]: + print( + str(i) + + ". " + + entry['type'] + + ": +" + + entry["in"]["amount"] + + " " + + entry["in"]["currency"]) + if entry["out"]: + print( + str(i) + + ". " + + entry['type'] + + ": -" + + entry["in"]["amount"] + + " " + + entry["in"]["currency"]) print("\nGetting transactions (first 20 entries)...") entries = api.get_reserve_chain() @@ -68,11 +86,19 @@ i += 1 if i > 20: break - print(str(i) + ". " + entry['origin']['amount'] + " " + entry["origin"]["currency"] + " => " + entry['destination']['amount'] + " " + entry["destination"]["currency"]) + print( + str(i) + + ". " + + entry['origin']['amount'] + + " " + + entry["origin"]["currency"] + + " => " + + entry['destination']['amount'] + + " " + + entry["destination"]["currency"]) print("\nGetting all tickers...") tic = api.get_ticker() print("ok.") exit(0) - diff --git a/setup.py b/setup.py index 8e5ed31..d25f1c0 100644 --- a/setup.py +++ b/setup.py @@ -1,14 +1,15 @@ # -*- coding: utf-8 -*- from distutils.core import setup + setup( - name = 'uphold', - packages = ['uphold'], - version = '0.1', - description = "Library for uphold.com's API", - author = 'Byrne Reese, João Miguel Neves', - author_email = 'byrne@uphold.com', - url = 'https://github.com/byrnereese/uphold-python-sdk', - download_url = 'https://github.com/byrnereese/uphold-python-sdk/tarball/0.1', - keywords = ['uphold', 'bitreserve', 'currency', 'trading', 'api'], - classifiers = [], + name='uphold', + packages=['uphold'], + version='0.1', + description="Library for uphold.com's API", + author='Byrne Reese, João Miguel Neves', + author_email='byrne@uphold.com', + url='https://github.com/byrnereese/uphold-python-sdk', + download_url='https://github.com/byrnereese/uphold-python-sdk/tarball/0.1', + keywords=['uphold', 'bitreserve', 'currency', 'trading', 'api'], + classifiers=[], ) diff --git a/tests.py b/tests.py index 3dfbb00..58e7ddd 100644 --- a/tests.py +++ b/tests.py @@ -1,8 +1,10 @@ # -*- coding: utf-8 -*- from __future__ import print_function, unicode_literals + +from decimal import Decimal from unittest import TestCase, main, skip + from mock import Mock, patch -from decimal import Decimal from uphold import Uphold @@ -13,6 +15,7 @@ class FakeResponse(object): class TestAuthentication(TestCase): + def setUp(self): pass @@ -21,6 +24,7 @@ def test_(self): class TestCurrencies(TestCase): + def setUp(self): pass @@ -29,6 +33,7 @@ def test_(self): class TestTicker(TestCase): + def setUp(self): pass @@ -37,6 +42,7 @@ def test_(self): class TestCard(TestCase): + def setUp(self): pass @@ -45,6 +51,7 @@ def test_(self): class TestContact(TestCase): + def setUp(self): pass @@ -53,6 +60,7 @@ def test_(self): class TestCurrencyPair(TestCase): + def setUp(self): pass @@ -106,13 +114,15 @@ def test_(self): } }''' - + class TestTransaction(TestCase): + def setUp(self): self.api = Bitreserve() #self.api.auth('user', 'password') - @patch('requests.Session.post', Mock(return_value=fake_transaction_response)) + @patch('requests.Session.post', Mock( + return_value=fake_transaction_response)) def test_prepare_txn(self): res = self.api.prepare_txn( '66cf2c86-8247-4094-bbec-ca29cea8220f', @@ -122,7 +132,8 @@ def test_prepare_txn(self): ) self.assertEqual(res, '7c377eba-cb1e-45a2-8c13-9807b4139bec') - @patch('requests.Session.post', Mock(return_value=fake_transaction_response)) + @patch('requests.Session.post', Mock( + return_value=fake_transaction_response)) def test_execute_txn(self): res = self.api.execute_txn( '66cf2c86-8247-4094-bbec-ca29cea8220f', @@ -130,8 +141,9 @@ def test_execute_txn(self): ) self.assertEqual(res['id'], '7c377eba-cb1e-45a2-8c13-9807b4139bec') - + class TestUser(TestCase): + def setUp(self): pass diff --git a/uphold/uphold.py b/uphold/uphold.py index 010b8e4..5f28472 100644 --- a/uphold/uphold.py +++ b/uphold/uphold.py @@ -19,55 +19,60 @@ from __future__ import print_function, unicode_literals -import urllib3 -import requests import json -import ssl + +import requests + from .version import __version__ -class VerificationRequired(Exception): - def __init__(self, value): - self.value = value - def __str__(self): - return repr(self.value) -class RateLimitError(Exception): - def __init__(self, value): - self.value = value - def __str__(self): - return repr(self.value) +class BaseUpholdException(Exception): + pass + + +class VerificationRequired(BaseUpholdException): + pass + + +class RateLimitError(BaseUpholdException): + pass + class NotSupportedInProduction(Exception): - def __init__(self, value): - self.value = value - def __str__(self): - return repr(self.value) + pass + + +class UpholdApiError(Exception): + pass + class Uphold(object): """ Use this SDK to simplify interaction with the Uphold API """ - + def __init__(self, sandbox=False): if sandbox: self.host = 'api-sandbox.uphold.com' else: self.host = 'api.uphold.com' self.in_sandbox = sandbox - self.debug = False + self.debug = False self.version = 0 self.session = requests.Session() + self.username = None + self.password = None self.headers = { 'Content-type': 'application/x-www-form-urlencoded', 'User-Agent': 'uphold-python-sdk/' + __version__ - } + } self.pat = None self.otp = None def _debug(self, s): if self.debug: print(s) - + def verification_code(self, code): self.otp = code @@ -75,20 +80,20 @@ def auth_basic(self, username, password): """ Authenticates against the Uphold backend using a username and password. Uphold return an User Auth Token, which is persisted for the life of the session. - + :param String username An Uphold username or email address. - + :param String password The password corresponding to the specified username. - + """ self.username = username self.password = password self.pat = None - + def auth_pat(self, pat): """ Sets the authentication method to PAT, or "Personal Access Token." Before calling this - method, a PAT needs to be created using the create_path() method. + method, a PAT needs to be created using the create_path() method. :param String pat The personal access token @@ -102,7 +107,7 @@ def create_pat(self, desc): Creates a personal access token. :param String desc A description for the token - + :rtype: A string representing the Personal Access Token """ @@ -152,7 +157,13 @@ def get_contact(self, contact): """ return self._get('/me/contacts/{}'.format(contact)) - def create_contact(self, first_name, last_name, company, emails=[], bitcoin_addresses=[]): + def create_contact( + self, + first_name, + last_name, + company, + emails=[], + bitcoin_addresses=[]): fields = { 'firstName': first_name, 'lastName': last_name, @@ -266,7 +277,13 @@ def prepare_txn(self, card, to, amount, denom): 'destination': to } data = self._post('/me/cards/' + card + '/transactions', fields) - return data['id'] + try: + return data['id'] + except KeyError: + msg = 'Transaction was not created, please check your input.' \ + ' API returned {}'.format(data) + self._debug(msg) + raise UpholdApiError(msg) def execute_txn(self, card, transaction, message=''): """ @@ -286,7 +303,13 @@ def execute_txn(self, card, transaction, message=''): fields = {} if message: fields['message'] = message - return self._post('/me/cards/' + card + '/transactions/' + transaction + '/commit', fields) + return self._post( + '/me/cards/' + + card + + '/transactions/' + + transaction + + '/commit', + fields) def cancel_txn(self, card, transaction): """ @@ -300,7 +323,13 @@ def cancel_txn(self, card, transaction): A transaction object """ fields = {} - return self._post('/me/cards/' + card + '/transactions/' + transaction + '/cancel', fields) + return self._post( + '/me/cards/' + + card + + '/transactions/' + + transaction + + '/cancel', + fields) def resend_txn(self, card, transaction): """ @@ -314,7 +343,13 @@ def resend_txn(self, card, transaction): A transaction object """ fields = {} - return self._post('/me/cards/' + card + '/transactions/' + transaction + '/resend', fields) + return self._post( + '/me/cards/' + + card + + '/transactions/' + + transaction + + '/resend', + fields) def get_ticker(self, t=''): """ @@ -380,6 +415,7 @@ def revert_voucher(self, id): """ HELPER FUNCTIONS """ + def _build_url(self, uri): if uri.startswith('/oauth2'): return uri @@ -387,12 +423,12 @@ def _build_url(self, uri): def _update_rate_limit(self, headers): if 'X-RateLimit-Limit' in headers: - self.limit = headers['X-RateLimit-Limit'] + self.limit = headers['X-RateLimit-Limit'] self.remaining = headers['X-RateLimit-Remaining'] - self.reset = headers['X-RateLimit-Reset'] + self.reset = headers['X-RateLimit-Reset'] else: self.limit = self.remaining = self.reset = "" - + def _post(self, uri, params): """ """ @@ -401,19 +437,23 @@ def _post(self, uri, params): try: if self.pat: self._debug("Using PAT") - response = self.session.post(url, data=params, headers=self.headers, auth=(self.pat, 'X-OAuth-Basic')) + response = self.session.post( + url, data=params, headers=self.headers, auth=( + self.pat, 'X-OAuth-Basic')) elif self.username: self._debug("Using Basic Auth") - self.session.auth = ( self.username, self.password ) + self.session.auth = (self.username, self.password) if self.otp: self._debug("Using verification code: " + self.otp) self.headers['X-Bitreserve-OTP'] = self.otp self._debug(self.headers) - response = self.session.post(url, data=params, headers=self.headers) + response = self.session.post( + url, data=params, headers=self.headers) else: - response = self.session.post(url, data=params, headers=self.headers) + response = self.session.post( + url, data=params, headers=self.headers) - self._update_rate_limit( response.headers ) + self._update_rate_limit(response.headers) if 'X-Bitreserve-OTP' in response.headers: self._debug("OTP Required!") @@ -425,7 +465,7 @@ def _post(self, uri, params): except requests.exceptions.SSLError as e: # Handle incorrect certificate error. self._debug("Failed certificate check: " + str(e)) - exit() + exit(1) data = json.loads(response.text) if 'X-Bitreserve-OTP' in self.headers: @@ -441,10 +481,12 @@ def _get(self, uri): try: if self.pat: self._debug("Using PAT") - response = self.session.get(url, headers=self.headers, auth=(self.pat, 'X-OAuth-Basic')) + response = self.session.get( + url, headers=self.headers, auth=( + self.pat, 'X-OAuth-Basic')) elif self.username: self._debug("Using Basic Auth") - self.session.auth = ( self.username, self.password ) + self.session.auth = (self.username, self.password) if self.otp: self._debug("Using verification code: " + self.otp) self.headers['X-Bitreserve-OTP'] = self.otp @@ -453,7 +495,7 @@ def _get(self, uri): else: response = self.session.get(url, headers=self.headers) - self._update_rate_limit( response.headers ) + self._update_rate_limit(response.headers) if 'X-Bitreserve-OTP' in response.headers: self._debug("OTP Required!") @@ -465,10 +507,9 @@ def _get(self, uri): except requests.exceptions.SSLError as e: # Handle incorrect certificate error. self._debug("Failed certificate check: " + str(e)) - exit() + exit(1) data = json.loads(response.text) if 'X-Bitreserve-OTP' in self.headers: del self.headers['X-Bitreserve-OTP'] return data -