Skip to content

Commit 8e6a7f6

Browse files
Merge branch 'release/v2.6.1'
2 parents bb8d4a3 + ad1e0bf commit 8e6a7f6

File tree

8 files changed

+118
-45
lines changed

8 files changed

+118
-45
lines changed

.test-env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Configs for testing repo download:
22
SDK_TESTING_URL="https://github.com/algorand/algorand-sdk-testing"
3-
SDK_TESTING_BRANCH="V2"
3+
SDK_TESTING_BRANCH="master"
44
SDK_TESTING_HARNESS="test-harness"
55

66
INSTALL_ONLY=0

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Changelog
22

3+
# v2.6.1
4+
5+
<!-- Release notes generated using configuration in .github/release.yml at release/v2.6.1 -->
6+
7+
## What's Changed
8+
### Bugfixes
9+
* algod: Even in the face of urllib.error.HTTPError, return the json by @jannotti in https://github.com/algorand/py-algorand-sdk/pull/529
10+
* Fix: Pass args to underlying `kmd_request` function, including timeout by @jasonpaulos in https://github.com/algorand/py-algorand-sdk/pull/545
11+
12+
13+
**Full Changelog**: https://github.com/algorand/py-algorand-sdk/compare/v2.6.0...v2.6.1
14+
315
# v2.6.0
416

517
<!-- Release notes generated using configuration in .github/release.yml at release/v2.6.0 -->

algosdk/error.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,10 @@ def __init__(self, msg):
178178

179179

180180
class AlgodHTTPError(Exception):
181-
def __init__(self, msg, code=None):
181+
def __init__(self, msg, code=None, data=None):
182182
super().__init__(msg)
183183
self.code = code
184+
self.data = data
184185

185186

186187
class AlgodResponseError(Exception):

algosdk/kmd.py

Lines changed: 60 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import base64
22
import json
3+
from typing import Any
34
import urllib.error
45
from urllib import parse
56
from urllib.request import Request, urlopen
@@ -66,32 +67,37 @@ def kmd_request(self, method, requrl, params=None, data=None, timeout=30):
6667
raise error.KMDHTTPError(e)
6768
return json.loads(resp.read().decode("utf-8"))
6869

69-
def versions(self):
70+
def versions(self, **kwargs: Any):
7071
"""
7172
Get kmd versions.
7273
7374
Returns:
7475
str[]: list of versions
7576
"""
7677
req = "/versions"
77-
return self.kmd_request("GET", req)["versions"]
78+
return self.kmd_request("GET", req, **kwargs)["versions"]
7879

79-
def list_wallets(self):
80+
def list_wallets(self, **kwargs: Any):
8081
"""
8182
List all wallets hosted on node.
8283
8384
Returns:
8485
dict[]: list of dictionaries containing wallet information
8586
"""
8687
req = "/wallets"
87-
res = self.kmd_request("GET", req)
88+
res = self.kmd_request("GET", req, **kwargs)
8889
if "wallets" in res:
8990
return res["wallets"]
9091
else:
9192
return []
9293

9394
def create_wallet(
94-
self, name, pswd, driver_name="sqlite", master_deriv_key=None
95+
self,
96+
name,
97+
pswd,
98+
driver_name="sqlite",
99+
master_deriv_key=None,
100+
**kwargs: Any
95101
):
96102
"""
97103
Create a new wallet.
@@ -113,9 +119,9 @@ def create_wallet(
113119
}
114120
if master_deriv_key:
115121
query["master_derivation_key"] = master_deriv_key
116-
return self.kmd_request("POST", req, data=query)["wallet"]
122+
return self.kmd_request("POST", req, data=query, **kwargs)["wallet"]
117123

118-
def get_wallet(self, handle):
124+
def get_wallet(self, handle, **kwargs: Any):
119125
"""
120126
Get wallet information.
121127
@@ -127,9 +133,11 @@ def get_wallet(self, handle):
127133
"""
128134
req = "/wallet/info"
129135
query = {"wallet_handle_token": handle}
130-
return self.kmd_request("POST", req, data=query)["wallet_handle"]
136+
return self.kmd_request("POST", req, data=query, **kwargs)[
137+
"wallet_handle"
138+
]
131139

132-
def init_wallet_handle(self, id, password):
140+
def init_wallet_handle(self, id, password, **kwargs: Any):
133141
"""
134142
Initialize a handle for the wallet.
135143
@@ -142,9 +150,11 @@ def init_wallet_handle(self, id, password):
142150
"""
143151
req = "/wallet/init"
144152
query = {"wallet_id": id, "wallet_password": password}
145-
return self.kmd_request("POST", req, data=query)["wallet_handle_token"]
153+
return self.kmd_request("POST", req, data=query, **kwargs)[
154+
"wallet_handle_token"
155+
]
146156

147-
def release_wallet_handle(self, handle):
157+
def release_wallet_handle(self, handle, **kwargs: Any):
148158
"""
149159
Deactivate the handle for the wallet.
150160
@@ -156,10 +166,10 @@ def release_wallet_handle(self, handle):
156166
"""
157167
req = "/wallet/release"
158168
query = {"wallet_handle_token": handle}
159-
result = self.kmd_request("POST", req, data=query)
169+
result = self.kmd_request("POST", req, data=query, **kwargs)
160170
return result == {}
161171

162-
def renew_wallet_handle(self, handle):
172+
def renew_wallet_handle(self, handle, **kwargs: Any):
163173
"""
164174
Renew the wallet handle.
165175
@@ -171,9 +181,11 @@ def renew_wallet_handle(self, handle):
171181
"""
172182
req = "/wallet/renew"
173183
query = {"wallet_handle_token": handle}
174-
return self.kmd_request("POST", req, data=query)["wallet_handle"]
184+
return self.kmd_request("POST", req, data=query, **kwargs)[
185+
"wallet_handle"
186+
]
175187

176-
def rename_wallet(self, id, password, new_name):
188+
def rename_wallet(self, id, password, new_name, **kwargs: Any):
177189
"""
178190
Rename the wallet.
179191
@@ -191,9 +203,9 @@ def rename_wallet(self, id, password, new_name):
191203
"wallet_password": password,
192204
"wallet_name": new_name,
193205
}
194-
return self.kmd_request("POST", req, data=query)["wallet"]
206+
return self.kmd_request("POST", req, data=query, **kwargs)["wallet"]
195207

196-
def export_master_derivation_key(self, handle, password):
208+
def export_master_derivation_key(self, handle, password, **kwargs: Any):
197209
"""
198210
Get the wallet's master derivation key.
199211
@@ -206,10 +218,10 @@ def export_master_derivation_key(self, handle, password):
206218
"""
207219
req = "/master-key/export"
208220
query = {"wallet_handle_token": handle, "wallet_password": password}
209-
result = self.kmd_request("POST", req, data=query)
221+
result = self.kmd_request("POST", req, data=query, **kwargs)
210222
return result["master_derivation_key"]
211223

212-
def import_key(self, handle, private_key):
224+
def import_key(self, handle, private_key, **kwargs: Any):
213225
"""
214226
Import an account into the wallet.
215227
@@ -222,9 +234,9 @@ def import_key(self, handle, private_key):
222234
"""
223235
req = "/key/import"
224236
query = {"wallet_handle_token": handle, "private_key": private_key}
225-
return self.kmd_request("POST", req, data=query)["address"]
237+
return self.kmd_request("POST", req, data=query, **kwargs)["address"]
226238

227-
def export_key(self, handle, password, address):
239+
def export_key(self, handle, password, address, **kwargs: Any):
228240
"""
229241
Return an account private key.
230242
@@ -242,9 +254,11 @@ def export_key(self, handle, password, address):
242254
"wallet_password": password,
243255
"address": address,
244256
}
245-
return self.kmd_request("POST", req, data=query)["private_key"]
257+
return self.kmd_request("POST", req, data=query, **kwargs)[
258+
"private_key"
259+
]
246260

247-
def generate_key(self, handle, display_mnemonic=True):
261+
def generate_key(self, handle, display_mnemonic=True, **kwargs: Any):
248262
"""
249263
Generate a key in the wallet.
250264
@@ -258,9 +272,9 @@ def generate_key(self, handle, display_mnemonic=True):
258272
"""
259273
req = "/key"
260274
query = {"wallet_handle_token": handle}
261-
return self.kmd_request("POST", req, data=query)["address"]
275+
return self.kmd_request("POST", req, data=query, **kwargs)["address"]
262276

263-
def delete_key(self, handle, password, address):
277+
def delete_key(self, handle, password, address, **kwargs: Any):
264278
"""
265279
Delete a key in the wallet.
266280
@@ -278,10 +292,10 @@ def delete_key(self, handle, password, address):
278292
"wallet_password": password,
279293
"address": address,
280294
}
281-
result = self.kmd_request("DELETE", req, data=query)
295+
result = self.kmd_request("DELETE", req, data=query, **kwargs)
282296
return result == {}
283297

284-
def list_keys(self, handle):
298+
def list_keys(self, handle, **kwargs: Any):
285299
"""
286300
List all keys in the wallet.
287301
@@ -294,12 +308,14 @@ def list_keys(self, handle):
294308
req = "/key/list"
295309
query = {"wallet_handle_token": handle}
296310

297-
result = self.kmd_request("POST", req, data=query)
311+
result = self.kmd_request("POST", req, data=query, **kwargs)
298312
if result:
299313
return result["addresses"]
300314
return []
301315

302-
def sign_transaction(self, handle, password, txn, signing_address=None):
316+
def sign_transaction(
317+
self, handle, password, txn, signing_address=None, **kwargs: Any
318+
):
303319
"""
304320
Sign a transaction.
305321
@@ -322,11 +338,11 @@ def sign_transaction(self, handle, password, txn, signing_address=None):
322338
}
323339
if signing_address:
324340
query["public_key"] = signing_address
325-
result = self.kmd_request("POST", req, data=query)
341+
result = self.kmd_request("POST", req, data=query, **kwargs)
326342
result = result["signed_transaction"]
327343
return encoding.msgpack_decode(result)
328344

329-
def list_multisig(self, handle):
345+
def list_multisig(self, handle, **kwargs: Any):
330346
"""
331347
List all multisig accounts in the wallet.
332348
@@ -338,12 +354,12 @@ def list_multisig(self, handle):
338354
"""
339355
req = "/multisig/list"
340356
query = {"wallet_handle_token": handle}
341-
result = self.kmd_request("POST", req, data=query)
357+
result = self.kmd_request("POST", req, data=query, **kwargs)
342358
if result == {}:
343359
return []
344360
return result["addresses"]
345361

346-
def import_multisig(self, handle, multisig):
362+
def import_multisig(self, handle, multisig, **kwargs: Any):
347363
"""
348364
Import a multisig account into the wallet.
349365
@@ -364,9 +380,9 @@ def import_multisig(self, handle, multisig):
364380
for s in multisig.subsigs
365381
],
366382
}
367-
return self.kmd_request("POST", req, data=query)["address"]
383+
return self.kmd_request("POST", req, data=query, **kwargs)["address"]
368384

369-
def export_multisig(self, handle, address):
385+
def export_multisig(self, handle, address, **kwargs: Any):
370386
"""
371387
Export a multisig account.
372388
@@ -379,15 +395,15 @@ def export_multisig(self, handle, address):
379395
"""
380396
req = "/multisig/export"
381397
query = {"wallet_handle_token": handle, "address": address}
382-
result = self.kmd_request("POST", req, data=query)
398+
result = self.kmd_request("POST", req, data=query, **kwargs)
383399
pks = result["pks"]
384400
pks = [encoding.encode_address(base64.b64decode(p)) for p in pks]
385401
msig = transaction.Multisig(
386402
result["multisig_version"], result["threshold"], pks
387403
)
388404
return msig
389405

390-
def delete_multisig(self, handle, password, address):
406+
def delete_multisig(self, handle, password, address, **kwargs: Any):
391407
"""
392408
Delete a multisig account.
393409
@@ -405,10 +421,12 @@ def delete_multisig(self, handle, password, address):
405421
"wallet_password": password,
406422
"address": address,
407423
}
408-
result = self.kmd_request("DELETE", req, data=query)
424+
result = self.kmd_request("DELETE", req, data=query, **kwargs)
409425
return result == {}
410426

411-
def sign_multisig_transaction(self, handle, password, public_key, mtx):
427+
def sign_multisig_transaction(
428+
self, handle, password, public_key, mtx, **kwargs: Any
429+
):
412430
"""
413431
Sign a multisig transaction for the given public key.
414432
@@ -439,7 +457,9 @@ def sign_multisig_transaction(self, handle, password, public_key, mtx):
439457
signer = base64.b64encode(encoding.decode_address(mtx.auth_addr))
440458
query["signer"] = signer.decode()
441459

442-
result = self.kmd_request("POST", req, data=query)["multisig"]
460+
result = self.kmd_request("POST", req, data=query, **kwargs)[
461+
"multisig"
462+
]
443463
msig = encoding.msgpack_decode(result)
444464
mtx.multisig = msig
445465
return mtx

algosdk/v2client/algod.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,13 @@ def algod_request(
107107
except urllib.error.HTTPError as e:
108108
code = e.code
109109
es = e.read().decode("utf-8")
110+
m = e # If json.loads() fails, we'll return e itself
111+
j = {}
110112
try:
111-
e = json.loads(es)["message"]
113+
j = json.loads(es)
114+
m = j["message"]
112115
finally:
113-
raise error.AlgodHTTPError(e, code)
116+
raise error.AlgodHTTPError(m, code, j.get("data"))
114117
if response_format == "json":
115118
try:
116119
return json.load(resp)

examples/inspect-error.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from algosdk import error, transaction
2+
3+
from utils import get_algod_client, algod_env
4+
5+
algod = get_algod_client(*algod_env())
6+
7+
# This program is "#pragma version 5, +". It will fail because no arguments are on the stack.
8+
lsig = transaction.LogicSigAccount(b"\x05\x08")
9+
sender = lsig.address()
10+
# Get suggested parameters
11+
params = algod.suggested_params()
12+
13+
amount = 10000
14+
txn = transaction.PaymentTxn(sender, params, sender, amount)
15+
lstx = transaction.LogicSigTransaction(txn, lsig)
16+
try:
17+
txid = algod.send_transaction(lstx)
18+
print("Impossible! Exception will have been thrown")
19+
except error.AlgodHTTPError as e:
20+
print(e.data)

examples/utils.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,23 @@ class SandboxAccount:
9393
signer: AccountTransactionSigner
9494

9595

96+
def algod_env():
97+
algodata = os.environ.get("ALGORAND_DATA")
98+
if not algodata:
99+
return ()
100+
try:
101+
token = (
102+
open(os.path.join(algodata, "algod.token"), "rt").read().strip()
103+
)
104+
net = (
105+
"http://"
106+
+ open(os.path.join(algodata, "algod.net"), "rt").read().strip()
107+
)
108+
return (net, token)
109+
except FileNotFoundError:
110+
return ()
111+
112+
96113
def get_accounts(
97114
kmd_address: str = KMD_URL,
98115
kmd_token: str = KMD_TOKEN,

0 commit comments

Comments
 (0)