From b1d66c848de646afa3c61a14c6b2ed88c056fa98 Mon Sep 17 00:00:00 2001 From: Confidence Yobo Date: Tue, 14 Sep 2021 05:19:47 -0500 Subject: [PATCH 1/3] Prepare for packaging --- LICENSE | 21 ++++ Pipfile.lock | 107 ------------------ README.md | 0 coinpayments/__init__.py | 3 + apiConfig.py => coinpayments/apiConfig.py | 59 +++++----- .../coinpayments.py | 41 ++++++- errors.py => coinpayments/errors.py | 0 coinpayments/sample.py | 30 +++++ coinpayments/version.py | 5 + setup.cfg | 2 + setup.py | 24 ++++ test.py | 0 12 files changed, 151 insertions(+), 141 deletions(-) create mode 100644 LICENSE delete mode 100644 Pipfile.lock create mode 100644 README.md create mode 100644 coinpayments/__init__.py rename apiConfig.py => coinpayments/apiConfig.py (68%) rename coinpayments.py => coinpayments/coinpayments.py (80%) rename errors.py => coinpayments/errors.py (100%) create mode 100644 coinpayments/sample.py create mode 100644 coinpayments/version.py create mode 100644 setup.cfg create mode 100644 setup.py create mode 100644 test.py diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d63bf7d --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Klynox + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index 5eef911..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,107 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "c61cd70a5cf16f33b702bfb3b43fec40bc70e0cb9c349209aca8502349cf0aac" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.9" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "autopep8": { - "hashes": [ - "sha256:276ced7e9e3cb22e5d7c14748384a5cf5d9002257c0ed50c0e075b68011bb6d0", - "sha256:aa213493c30dcdac99537249ee65b24af0b2c29f2e83cd8b3f68760441ed0db9" - ], - "index": "pypi", - "version": "==1.5.7" - }, - "certifi": { - "hashes": [ - "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee", - "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8" - ], - "version": "==2021.5.30" - }, - "charset-normalizer": { - "hashes": [ - "sha256:0c8911edd15d19223366a194a513099a302055a962bca2cec0f54b8b63175d8b", - "sha256:f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3" - ], - "markers": "python_version >= '3'", - "version": "==2.0.4" - }, - "flake8": { - "hashes": [ - "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b", - "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907" - ], - "index": "pypi", - "version": "==3.9.2" - }, - "idna": { - "hashes": [ - "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a", - "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3" - ], - "markers": "python_version >= '3'", - "version": "==3.2" - }, - "mccabe": { - "hashes": [ - "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", - "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" - ], - "version": "==0.6.1" - }, - "pycodestyle": { - "hashes": [ - "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068", - "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.7.0" - }, - "pyflakes": { - "hashes": [ - "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3", - "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.3.1" - }, - "requests": { - "hashes": [ - "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24", - "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7" - ], - "index": "pypi", - "version": "==2.26.0" - }, - "toml": { - "hashes": [ - "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", - "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" - ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.10.2" - }, - "urllib3": { - "hashes": [ - "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4", - "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", - "version": "==1.26.6" - } - }, - "develop": {} -} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/coinpayments/__init__.py b/coinpayments/__init__.py new file mode 100644 index 0000000..7195fce --- /dev/null +++ b/coinpayments/__init__.py @@ -0,0 +1,3 @@ +from coinpayments.coinpayments import CoinPayments + +name = "coinpayments" diff --git a/apiConfig.py b/coinpayments/apiConfig.py similarity index 68% rename from apiConfig.py rename to coinpayments/apiConfig.py index fb1b8e8..2ee351b 100644 --- a/apiConfig.py +++ b/coinpayments/apiConfig.py @@ -1,20 +1,22 @@ import os +import urllib.request +import urllib.parse +import urllib.error +import urllib.request +import urllib.error +import urllib.parse import hmac import hashlib -import urllib.parse import json -import requests - -from .errors import (MissingAuthKeyError, - InvalidMethodError, ImproperlyConfigured) +from errors import (MissingAuthKeyError, ImproperlyConfigured) class ApiConfig: """ API configuration for the coinpayments SDK """ - _CONTENT_TYPE = "application/json" + _CONTENT_TYPE = "application/x-www-form-urlencoded" _API_END_POINT = "https://www.coinpayments.net/api.php" def __init__(self, private_key=None, public_key=None, ipn_url=None): @@ -65,38 +67,29 @@ def create_hmac(self, **params): encoded, hashlib.sha512).hexdigest() def _parse_json(self, response_obj): - parsed_response = response_obj.json() - print(parsed_response) - return response_obj.status_code, parsed_response + response_body = response_obj.read() + response_body_decoded = json.loads( + response_body) + response_body_decoded.update(response_body_decoded['result']) + response_body_decoded.pop('result', None) + return response_body_decoded def _handle_request(self, method, url, data=None): """ Generic function to handle all API url calls Returns a python tuple of status code, status(bool), message, data """ - method_map = { - 'GET': requests.get, - 'POST': requests.post, - 'PUT': requests.put, - 'DELETE': requests.delete - } - - payload = json.dumps(data) if data else data encoded, sig = self.create_hmac(**data) self.request_headers['hmac'] = sig - request = method_map.get(method) - - if not request: - raise InvalidMethodError( - "Request method not recognised or implemented") - - response = request(url, headers=self.request_headers, - data=payload, verify=True) - if response.status_code == 404: - return response.status_code, "The object request cannot be found" - - if response.status_code in [200, 201]: - return self._parse_json(response) - else: - # body = response.json() - return response.status_code, "Real error" + req = urllib.request.Request( + url, data=encoded, headers=self.request_headers) + + try: + response = urllib.request.urlopen(req) + response_body_decoded = self._parse_json(response) + except urllib.error.HTTPError as e: + response_body = e.read() + response_body_decoded = json.loads( + response_body) + return response_body_decoded + return response_body_decoded diff --git a/coinpayments.py b/coinpayments/coinpayments.py similarity index 80% rename from coinpayments.py rename to coinpayments/coinpayments.py index 4461a56..92990e1 100644 --- a/coinpayments.py +++ b/coinpayments/coinpayments.py @@ -1,4 +1,4 @@ -from .apiConfig import ApiConfig +from apiConfig import ApiConfig class CoinPayments(ApiConfig): @@ -12,6 +12,8 @@ def create_transaction(self, params=None): if self.ipn_url: params.update({'ipn_url': self.ipn_url}) params.update({'cmd': 'create_transaction', + 'version': 1, + 'format': 'json', 'key': self.COINPAYMENTS_PUBLIC_KEY}) url = self._url('') return self._handle_request('POST', url, params) @@ -24,6 +26,8 @@ def get_basic_info(self, params=None): if params is None: params = {} params.update({'cmd': 'get_basic_info', + 'version': 1, + 'format': 'json', 'key': self.COINPAYMENTS_PUBLIC_KEY}) url = self._url('') return self._handle_request('POST', url, params) @@ -36,6 +40,8 @@ def rates(self, params=None): if params is None: params = {} params.update({'cmd': 'rates', + 'version': 1, + 'format': 'json', 'key': self.COINPAYMENTS_PUBLIC_KEY}) url = self._url('') return self._handle_request('POST', url, params) @@ -48,6 +54,8 @@ def balances(self, params=None): if params is None: params = {} params.update({'cmd': 'balances', + 'version': 1, + 'format': 'json', 'key': self.COINPAYMENTS_PUBLIC_KEY}) url = self._url('') return self._handle_request('POST', url, params) @@ -60,6 +68,8 @@ def get_deposit_address(self, params=None): if params is None: params = {} params.update({'cmd': 'get_deposit_address', + 'version': 1, + 'format': 'json', 'key': self.COINPAYMENTS_PUBLIC_KEY}) url = self._url('') return self._handle_request('POST', url, params) @@ -74,6 +84,8 @@ def get_callback_address(self, params=None): if self.ipn_url: params.update({'ipn_url': self.ipn_url}) params.update({'cmd': 'get_callback_address', + 'version': 1, + 'format': 'json', 'key': self.COINPAYMENTS_PUBLIC_KEY}) url = self._url('') return self._handle_request('POST', url, params) @@ -88,6 +100,8 @@ def create_transfer(self, params=None): if params is None: params = {} params.update({'cmd': 'create_transfer', + 'version': 1, + 'format': 'json', 'key': self.COINPAYMENTS_PUBLIC_KEY}) url = self._url('') return self._handle_request('POST', url, params) @@ -101,6 +115,8 @@ def create_withdrawal(self, params=None): if params is None: params = {} params.update({'cmd': 'create_withdrawal', + 'version': 1, + 'format': 'json', 'key': self.COINPAYMENTS_PUBLIC_KEY}) url = self._url('') return self._handle_request('POST', url, params) @@ -113,6 +129,7 @@ def convert_coins(self, params=None): if params is None: params = {} params.update({'cmd': 'convert', + 'version': 1, 'key': self.COINPAYMENTS_PUBLIC_KEY}) url = self._url('') return self._handle_request('POST', url, params) @@ -125,6 +142,8 @@ def get_withdrawal_history(self, params=None): if params is None: params = {} params.update({'cmd': 'get_withdrawal_history', + 'version': 1, + 'format': 'json', 'key': self.COINPAYMENTS_PUBLIC_KEY}) url = self._url('') return self._handle_request('POST', url, params) @@ -137,6 +156,8 @@ def get_withdrawal_info(self, params=None): if params is None: params = {} params.update({'cmd': 'get_withdrawal_info', + 'version': 1, + 'format': 'json', 'key': self.COINPAYMENTS_PUBLIC_KEY}) url = self._url('') return self._handle_request('POST', url, params) @@ -149,6 +170,22 @@ def get_conversion_info(self, params=None): if params is None: params = {} params.update({'cmd': 'get_conversion_info', + 'version': 1, + 'format': 'json', + 'key': self.COINPAYMENTS_PUBLIC_KEY}) + url = self._url('') + return self._handle_request('POST', url, params) + + def get_tx_info(self, params=None): + """ + Get single tx info + https://www.coinpayments.net/apidoc-get-tx-info + """ + if params is None: + params = {} + params.update({'cmd': 'get_tx_info', + 'version': 1, + 'format': 'json', 'key': self.COINPAYMENTS_PUBLIC_KEY}) url = self._url('') return self._handle_request('POST', url, params) @@ -161,6 +198,8 @@ def get_tx_info_multi(self, params=None): if params is None: params = {} params.update({'cmd': 'get_tx_info_multi', + 'version': 1, + 'format': 'json', 'key': self.COINPAYMENTS_PUBLIC_KEY}) url = self._url('') return self._handle_request('POST', url, params) diff --git a/errors.py b/coinpayments/errors.py similarity index 100% rename from errors.py rename to coinpayments/errors.py diff --git a/coinpayments/sample.py b/coinpayments/sample.py new file mode 100644 index 0000000..ff17b26 --- /dev/null +++ b/coinpayments/sample.py @@ -0,0 +1,30 @@ +from coinpayments import CoinPayments + +create_transaction_params = { + 'amount': 10, + 'currency1': 'USDT.BEP20', + 'currency2': 'USDT.BEP20', + 'buyer_email': 'confiyobo@gmail.com' +} +cp = CoinPayments( + 'PrivateKey', + 'PublicKey') + +transaction = cp.create_transaction(create_transaction_params) + +if transaction['error'] == 'ok': + print(transaction['amount']) + print(transaction['address']) +else: + print(transaction['error']) + +post_params1 = { + 'txid': transaction['txn_id'], +} +transactionInfo = cp.get_tx_info(post_params1) + +if transactionInfo['error'] == 'ok': + print(transactionInfo['amountf']) + print(transactionInfo['payment_address']) +else: + print(transactionInfo['error']) diff --git a/coinpayments/version.py b/coinpayments/version.py new file mode 100644 index 0000000..8245807 --- /dev/null +++ b/coinpayments/version.py @@ -0,0 +1,5 @@ +__title__ = 'python-coinpayments-sdk' +__version__ = '0.0.1' +__author__ = 'Klynox' +__license__ = 'MIT' +__copyright__ = 'Copyright 2016. Klynox' diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..224a779 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[metadata] +description-file = README.md \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..be1fa9c --- /dev/null +++ b/setup.py @@ -0,0 +1,24 @@ +import setuptools +from coinpayments import version + +with open("README.md", "r") as fh: + long_description = fh.read() + +setuptools.setup( + name="python-coinpayments-sdk", + version=version.__version__, + author=version.__author__, + author_email="confiyobo@gmail.com", + description="Coinpayments SDK for python", + long_description=long_description, + long_description_content_type="text/markdown", + url="https://github.com/Klynox/python-coinpayments-api-wrapper", + packages=setuptools.find_packages(), + download_url='https://github.com/Klynox/python-coinpayments-api-wrapper/archive/v0.0.1.tar.gz', + classifiers=[ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + ], + install_requires=["requests", "simplejson"], +) diff --git a/test.py b/test.py new file mode 100644 index 0000000..e69de29 From 0dca0a3b7de03f485a77645d26929b50ae5675b1 Mon Sep 17 00:00:00 2001 From: Confidence Yobo Date: Tue, 14 Sep 2021 05:24:49 -0500 Subject: [PATCH 2/3] Remove unused package --- Pipfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Pipfile b/Pipfile index 92ab828..1029368 100644 --- a/Pipfile +++ b/Pipfile @@ -4,7 +4,6 @@ verify_ssl = true name = "pypi" [packages] -requests = "==2.26.0" flake8 = "*" autopep8 = "*" From 3a0df89276f1a440b92b2bb4e4ae9bceda34ac25 Mon Sep 17 00:00:00 2001 From: Confidence Yobo Date: Tue, 14 Sep 2021 05:29:17 -0500 Subject: [PATCH 3/3] change importation path --- coinpayments/apiConfig.py | 2 +- coinpayments/coinpayments.py | 2 +- test.py | 0 3 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 test.py diff --git a/coinpayments/apiConfig.py b/coinpayments/apiConfig.py index 2ee351b..976cb75 100644 --- a/coinpayments/apiConfig.py +++ b/coinpayments/apiConfig.py @@ -9,7 +9,7 @@ import hashlib import json -from errors import (MissingAuthKeyError, ImproperlyConfigured) +from coinpayments.errors import (MissingAuthKeyError, ImproperlyConfigured) class ApiConfig: diff --git a/coinpayments/coinpayments.py b/coinpayments/coinpayments.py index 92990e1..7472797 100644 --- a/coinpayments/coinpayments.py +++ b/coinpayments/coinpayments.py @@ -1,4 +1,4 @@ -from apiConfig import ApiConfig +from coinpayments.apiConfig import ApiConfig class CoinPayments(ApiConfig): diff --git a/test.py b/test.py deleted file mode 100644 index e69de29..0000000