Skip to content

Commit c56cc84

Browse files
SP-524 Implement Python client classes
1 parent 0a54ddd commit c56cc84

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1932
-3808
lines changed

docs/ledger.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ Facades : **`MERCHANT`**
8282
```python
8383
today = date.today().strftime("%Y%m%d")
8484
date_start = (date.today() - timedelta(days=100)).strftime("%Y%m%d")
85-
ledger = bitpay.get_ledger(Currency.USD, date_start, today)
85+
ledger = bitpay.get_ledger_entries(Currency.USD, date_start, today)
8686
print(ledger)
8787
```
8888

src/bitpay/client.py

Lines changed: 249 additions & 1314 deletions
Large diffs are not rendered by default.

src/bitpay/client/bill_client.py

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
from typing import List
2+
3+
from bitpay.client.bitpay_client import BitPayClient
4+
from bitpay.exceptions.bill_creation_exception import BillCreationException
5+
from bitpay.exceptions.bill_delivery_exception import BillDeliveryException
6+
from bitpay.exceptions.bill_query_exception import BillQueryException
7+
from bitpay.exceptions.bill_update_exception import BillUpdateException
8+
from bitpay.exceptions.bitpay_exception import BitPayException
9+
from bitpay.models.bill.bill import Bill
10+
from bitpay.models.facade import Facade
11+
from bitpay.utils.token_container import TokenContainer
12+
13+
14+
class BillClient:
15+
__bitpay_client = BitPayClient
16+
__token_container = TokenContainer
17+
18+
def __init__(self, bitpay_client: BitPayClient, token_container: TokenContainer):
19+
self.__bitpay_client = bitpay_client
20+
self.__token_container = token_container
21+
22+
def create(
23+
self, bill: Bill, facade: str = Facade.MERCHANT, sign_request: bool = True
24+
) -> Bill:
25+
"""
26+
Create a BitPay Bill.
27+
28+
:param Bill bill: A Bill object with request parameters defined.
29+
:param str facade: The facade used to create it.
30+
:param bool sign_request: Signed request.
31+
:return: A BitPay generated Bill object.
32+
:rtype: Bill
33+
:raises BitPayException
34+
:raises BillCreationException
35+
"""
36+
try:
37+
bill.set_token(self.__token_container.get_access_token(facade))
38+
response_json = self.__bitpay_client.post(
39+
"bills", bill.to_json(), sign_request
40+
)
41+
except BitPayException as exe:
42+
raise BillCreationException(
43+
"failed to serialize bill object : %s" % str(exe), exe.get_api_code()
44+
)
45+
46+
try:
47+
return Bill(**response_json)
48+
except Exception as exe:
49+
raise BillCreationException(
50+
"failed to deserialize BitPay server response (Bill) : %s" % str(exe)
51+
)
52+
53+
def get(self, bill_id: str) -> Bill:
54+
"""
55+
Retrieve a BitPay bill by bill id using the specified facade.
56+
57+
:param str bill_id: The id of the bill to retrieve.
58+
:return: A BitPay Bill object.
59+
:rtype: Bill
60+
:raises BitPayException
61+
:raises BillQueryException
62+
"""
63+
try:
64+
params = {"token": self.__token_container.get_access_token(Facade.MERCHANT)}
65+
response_json = self.__bitpay_client.get("bills/%s" % bill_id, params)
66+
except BitPayException as exe:
67+
raise BillQueryException(
68+
"failed to serialize bill object : %s" % str(exe), exe.get_api_code()
69+
)
70+
71+
try:
72+
return Bill(**response_json)
73+
except Exception as exe:
74+
raise BillQueryException(
75+
"failed to deserialize BitPay server response" " (Bill) : %s" % str(exe)
76+
)
77+
78+
def get_bills(self, status: str = None) -> List[Bill]:
79+
"""
80+
Retrieve a collection of BitPay bills.
81+
82+
:param str status: The status to filter the bills.
83+
:return: A list of BitPay Bill objects.
84+
:rtype: [Bill]
85+
:raises BitPayException
86+
:raises BillQueryException
87+
"""
88+
try:
89+
params = {"token": self.__token_container.get_access_token(Facade.MERCHANT)}
90+
if status is not None:
91+
params["status"] = status
92+
response_json = self.__bitpay_client.get("bills", params, True)
93+
except BitPayException as exe:
94+
raise BillQueryException(
95+
"failed to serialize bill object : %s" % str(exe), exe.get_api_code()
96+
)
97+
98+
try:
99+
bills = []
100+
for bill_data in response_json:
101+
bills.append(Bill(**bill_data))
102+
except Exception as exe:
103+
raise BillQueryException(
104+
"failed to deserialize BitPay server response" " (Bill) : %s" % str(exe)
105+
)
106+
107+
return bills
108+
109+
def update(self, bill: Bill, bill_id: str) -> Bill:
110+
"""
111+
Update a BitPay Bill.
112+
113+
:param Bill bill: A Bill object with the parameters to update defined.
114+
:param str bill_id: The Id of the Bill to update.
115+
:return: An updated Bill object.
116+
:rtype: Bill
117+
:raises BitPayException
118+
:raises BillUpdateException
119+
"""
120+
try:
121+
response_json = self.__bitpay_client.update(
122+
"bills/%s" % bill_id, bill.to_json()
123+
)
124+
except BitPayException as exe:
125+
raise BillUpdateException(
126+
"failed to serialize bill object : %s" % str(exe), exe.get_api_code()
127+
)
128+
129+
try:
130+
return Bill(**response_json)
131+
except Exception as exe:
132+
raise BillUpdateException(
133+
"failed to deserialize BitPay server response" " (Bill) : %s" % str(exe)
134+
)
135+
136+
def deliver(self, bill_id: str, bill_token: str) -> bool:
137+
"""
138+
Deliver a BitPay Bill.
139+
140+
:param str bill_id: The id of the requested bill.
141+
:param str bill_token: The token of the requested bill.
142+
:return: A response status returned from the API.
143+
:rtype: bool
144+
:raises BitPayException
145+
:raises BillDeliveryException
146+
"""
147+
try:
148+
params = {"token": bill_token}
149+
response_json = self.__bitpay_client.post(
150+
"bills/%s" % bill_id + "/deliveries", params
151+
)
152+
except BitPayException as exe:
153+
raise BillDeliveryException(
154+
"failed to serialize bill object : %s" % str(exe), exe.get_api_code()
155+
)
156+
157+
try:
158+
return response_json.lower() == "success"
159+
except Exception as exe:
160+
raise BillDeliveryException(
161+
"failed to deserialize BitPay server response" " (Bill) : %s" % str(exe)
162+
)
Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,23 @@
1-
"""
2-
HTTP methods
3-
"""
41
import json
52
import urllib
3+
64
import requests
75

8-
from .. import env
9-
from ..exceptions.bitpay_exception import BitPayException
10-
from .key_utils import get_compressed_public_key_from_pem, sign
6+
from bitpay.exceptions.bitpay_exception import BitPayException
7+
from bitpay.utils.key_utils import sign, get_compressed_public_key_from_pem
8+
from build.lib.bitpay import env
119

1210

13-
class RESTcli:
11+
class BitPayClient:
1412
__headers = {}
15-
__baseurl = ""
16-
__eckey = ""
17-
__identity = ""
18-
__proxy = ""
19-
20-
def __init__(self, environment, eckey, proxy=None):
21-
self.__eckey = eckey
22-
self.__baseurl = env.TESTURL if environment == env.TEST else env.PRODURL
23-
self.__proxy = proxy
13+
__base_url = None
14+
__ec_key = None
15+
__proxy = None
16+
17+
def __init__(self, base_url, ec_key=None, proxy=None):
18+
self.base_url = base_url
19+
self.ec_key = ec_key
20+
self.proxy = proxy
2421
self.init()
2522

2623
def init(self):
@@ -47,12 +44,12 @@ def post(self, uri, form_data, signature_required=True):
4744
with the request body
4845
:return: json response
4946
"""
50-
full_url = self.__baseurl + uri
47+
full_url = self.__base_url + uri
5148
form_data = json.dumps(form_data)
5249
if signature_required:
53-
self.__headers["x-signature"] = sign(full_url + form_data, self.__eckey)
50+
self.__headers["x-signature"] = sign(full_url + form_data, self.__ec_key)
5451
self.__headers["x-identity"] = get_compressed_public_key_from_pem(
55-
self.__eckey
52+
self.__ec_key
5653
)
5754

5855
response = requests.post(full_url, data=form_data, headers=self.__headers)
@@ -67,14 +64,14 @@ def get(self, uri, parameters=None, signature_required=True):
6764
:param signature_required: Signature of the full request URL concatenated
6865
:return: json response
6966
"""
70-
full_url = self.__baseurl + uri
67+
full_url = self.__base_url + uri
7168
if parameters is not None:
7269
full_url = "%s?%s" % (full_url, urllib.parse.urlencode(parameters))
7370

7471
if signature_required:
75-
self.__headers["x-signature"] = sign(full_url, self.__eckey)
72+
self.__headers["x-signature"] = sign(full_url, self.__ec_key)
7673
self.__headers["x-identity"] = get_compressed_public_key_from_pem(
77-
self.__eckey
74+
self.__ec_key
7875
)
7976

8077
response = requests.get(full_url, headers=self.__headers)
@@ -88,13 +85,13 @@ def delete(self, uri, parameters=None):
8885
:param parameters: These are query parameters
8986
:return: json response
9087
"""
91-
full_url = self.__baseurl + uri
88+
full_url = self.__base_url + uri
9289

9390
if parameters is not None:
9491
full_url = "%s?%s" % (full_url, urllib.parse.urlencode(parameters))
9592

96-
self.__headers["x-signature"] = sign(full_url, self.__eckey)
97-
self.__headers["x-identity"] = get_compressed_public_key_from_pem(self.__eckey)
93+
self.__headers["x-signature"] = sign(full_url, self.__ec_key)
94+
self.__headers["x-identity"] = get_compressed_public_key_from_pem(self.__ec_key)
9895

9996
response = requests.delete(full_url, headers=self.__headers)
10097
json_response = self.response_to_json_string(response)
@@ -106,11 +103,11 @@ def update(self, uri, form_data):
106103
:param form_data: the data to be updated
107104
:return: json response
108105
"""
109-
full_url = self.__baseurl + uri
106+
full_url = self.__base_url + uri
110107
form_data = json.dumps(form_data)
111108

112-
self.__headers["x-signature"] = sign(full_url + form_data, self.__eckey)
113-
self.__headers["x-identity"] = get_compressed_public_key_from_pem(self.__eckey)
109+
self.__headers["x-signature"] = sign(full_url + form_data, self.__ec_key)
110+
self.__headers["x-identity"] = get_compressed_public_key_from_pem(self.__ec_key)
114111

115112
response = requests.put(full_url, data=form_data, headers=self.__headers)
116113
json_response = self.response_to_json_string(response)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from bitpay.client.bitpay_client import BitPayClient
2+
from bitpay.exceptions.bitpay_exception import BitPayException
3+
from bitpay.exceptions.currency_query_exception import CurrencyQueryException
4+
from bitpay.models.currency import Currency
5+
6+
7+
class CurrencyClient:
8+
__bitpay_client = BitPayClient
9+
10+
def __init__(self, bitpay_client: BitPayClient):
11+
self.__bitpay_client = bitpay_client
12+
13+
def get_currencies(self):
14+
"""
15+
Fetch the supported currencies.
16+
17+
:return: A list of BitPay Invoice objects.
18+
:rtype: [Currency]
19+
:raises BitPayException
20+
:raises CurrencyQueryException
21+
"""
22+
try:
23+
response_json = self.__bitpay_client.get("currencies", None, False)
24+
except BitPayException as exe:
25+
raise CurrencyQueryException(
26+
"failed to serialize Currency object : %s" % str(exe),
27+
exe.get_api_code(),
28+
)
29+
30+
try:
31+
currencies = []
32+
for currency in response_json:
33+
currencies.append(Currency(**currency))
34+
except Exception as exe:
35+
raise CurrencyQueryException(
36+
"failed to deserialize BitPay server response "
37+
" (Currency) : %s" % str(exe)
38+
)
39+
return currencies

0 commit comments

Comments
 (0)