diff --git a/monero/account.py b/monero/account.py index 4f1c9ca..47f3fcd 100644 --- a/monero/account.py +++ b/monero/account.py @@ -13,12 +13,15 @@ class Account(object): :param backend: a wallet backend :param index: the account's index within the wallet + :param label: optional account label as `str` """ index = None wallet = None + label = None - def __init__(self, backend, index): + def __init__(self, backend, index, label=None): self.index = index + self.label = label self._backend = backend self.incoming = PaymentManager(index, backend, 'in') self.outgoing = PaymentManager(index, backend, 'out') @@ -60,6 +63,7 @@ class Account(object): """ Creates a new address. + :param label: address label as `str` :rtype: :class:`SubAddress ` """ return self._backend.new_address(account=self.index, label=label) diff --git a/monero/backends/jsonrpc.py b/monero/backends/jsonrpc.py index b64bf6a..01ae60b 100644 --- a/monero/backends/jsonrpc.py +++ b/monero/backends/jsonrpc.py @@ -2,7 +2,6 @@ from datetime import datetime import operator import json import logging -import pprint import requests from .. import exceptions @@ -61,14 +60,14 @@ class JSONRPCDaemon(object): hdr = {'Content-Type': 'application/json'} _log.debug(u"Request: {path}\nData: {data}".format( path=path, - data=pprint.pformat(data))) + data=json.dumps(data, indent=2, sort_keys=True))) rsp = requests.post(self.url + path, headers=hdr, data=json.dumps(data)) if rsp.status_code != 200: raise RPCError("Invalid HTTP status {code} for path {path}.".format( code=rsp.status_code, path=path)) result = rsp.json() - _ppresult = pprint.pformat(result) + _ppresult = json.dumps(result, indent=2, sort_keys=True) _log.debug(u"Result:\n{result}".format(result=_ppresult)) return result @@ -78,7 +77,7 @@ class JSONRPCDaemon(object): data = {'jsonrpc': '2.0', 'id': 0, 'method': method, 'params': params or {}} _log.debug(u"Method: {method}\nParams:\n{params}".format( method=method, - params=pprint.pformat(params))) + params=json.dumps(params, indent=2, sort_keys=True))) auth = requests.auth.HTTPDigestAuth(self.user, self.password) rsp = requests.post(self.url + '/json_rpc', headers=hdr, data=json.dumps(data), auth=auth) if rsp.status_code == 401: @@ -88,7 +87,7 @@ class JSONRPCDaemon(object): code=rsp.status_code, method=method)) result = rsp.json() - _ppresult = pprint.pformat(result) + _ppresult = json.dumps(result, indent=2, sort_keys=True) _log.debug(u"Result:\n{result}".format(result=_ppresult)) if 'error' in result: @@ -142,24 +141,20 @@ class JSONRPCWallet(object): def accounts(self): accounts = [] - try: - _accounts = self.raw_request('get_accounts', squelch_error_logging=True) - except MethodNotFound: - # monero <= 0.11 : there's only one account and one address - _log.debug('Monero <= 0.11 found, no accounts') - self._master_address = self.addresses()[0] - return [Account(self, 0)] + _accounts = self.raw_request('get_accounts') idx = 0 self._master_address = Address(_accounts['subaddress_accounts'][0]['base_address']) for _acc in _accounts['subaddress_accounts']: assert idx == _acc['account_index'] - accounts.append(Account(self, _acc['account_index'])) + accounts.append(Account(self, _acc['account_index'], label=_acc.get('label'))) idx += 1 return accounts def new_account(self, label=None): _account = self.raw_request('create_account', {'label': label}) - return Account(self, _account['account_index']), SubAddress(_account['address']) + # NOTE: the following should re-read label by _account.get('label') but the RPC + # doesn't return that detail here + return Account(self, _account['account_index'], label=label), SubAddress(_account['address']) def addresses(self, account=0): _addresses = self.raw_request('getaddress', {'account_index': account}) @@ -318,7 +313,7 @@ class JSONRPCWallet(object): data = {'jsonrpc': '2.0', 'id': 0, 'method': method, 'params': params or {}} _log.debug(u"Method: {method}\nParams:\n{params}".format( method=method, - params=pprint.pformat(params))) + params=json.dumps(params, indent=2, sort_keys=True))) auth = requests.auth.HTTPDigestAuth(self.user, self.password) rsp = requests.post(self.url, headers=hdr, data=json.dumps(data), auth=auth) if rsp.status_code == 401: @@ -328,13 +323,12 @@ class JSONRPCWallet(object): code=rsp.status_code, method=method)) result = rsp.json() - _ppresult = pprint.pformat(result) + _ppresult = json.dumps(result, indent=2, sort_keys=True) _log.debug(u"Result:\n{result}".format(result=_ppresult)) if 'error' in result: err = result['error'] - if not squelch_error_logging: - _log.error(u"JSON RPC error:\n{result}".format(result=_ppresult)) + _log.error(u"JSON RPC error:\n{result}".format(result=_ppresult)) # XXX: workaround for 0.11 bug throwing a wrong error code if err['code'] == -4 and 'not enough money' in err['message']: raise exceptions.NotEnoughMoney(err['message']) diff --git a/monero/wallet.py b/monero/wallet.py index 94ec0f7..5f24d02 100644 --- a/monero/wallet.py +++ b/monero/wallet.py @@ -91,6 +91,7 @@ class Wallet(object): """ Creates new account, appends it to the :class:`Wallet`'s account list and returns it. + :param label: account label as `str` :rtype: :class:`Account` """ acc, addr = self._backend.new_account(label=label) diff --git a/tests/data/test_jsonrpcwallet/test_account_creation-00-get_accounts.json b/tests/data/test_jsonrpcwallet/test_account_creation-00-get_accounts.json new file mode 100644 index 0000000..58daa1f --- /dev/null +++ b/tests/data/test_jsonrpcwallet/test_account_creation-00-get_accounts.json @@ -0,0 +1,18 @@ +{ + "id": 0, + "jsonrpc": "2.0", + "result": { + "subaddress_accounts": [ + { + "account_index": 0, + "balance": 0, + "base_address": "53NTw2x2eJH3KCrcgWAMErZb7mqN57wkVTEjRkkUUXoWCrAd513JErRFT1AC9RvEddgpxoZTVXYJG9Jez4w9x6qd5s76wdu", + "label": "Primary account", + "tag": "", + "unlocked_balance": 0 + } + ], + "total_balance": 0, + "total_unlocked_balance": 0 + } +} diff --git a/tests/data/test_jsonrpcwallet/test_account_creation-10-create_account.json b/tests/data/test_jsonrpcwallet/test_account_creation-10-create_account.json new file mode 100644 index 0000000..937a301 --- /dev/null +++ b/tests/data/test_jsonrpcwallet/test_account_creation-10-create_account.json @@ -0,0 +1,8 @@ +{ + "id": 0, + "jsonrpc": "2.0", + "result": { + "account_index": 1, + "address": "75oMNpEDZNZhe9zBuKP4i6RpknDzAzM7t64Kq6nToUsJZms13tUucewKfZpdaQ9sNVYiMhiDyZbZR7MxbTCjq7D8N9CCo5k" + } +} diff --git a/tests/data/test_jsonrpcwallet/test_account_creation-20-getbalance.json b/tests/data/test_jsonrpcwallet/test_account_creation-20-getbalance.json new file mode 100644 index 0000000..345e668 --- /dev/null +++ b/tests/data/test_jsonrpcwallet/test_account_creation-20-getbalance.json @@ -0,0 +1,9 @@ +{ + "id": 0, + "jsonrpc": "2.0", + "result": { + "balance": 0, + "multisig_import_needed": false, + "unlocked_balance": 0 + } +} diff --git a/tests/data/test_jsonrpcwallet/test_account_creation-30-get_accounts.json b/tests/data/test_jsonrpcwallet/test_account_creation-30-get_accounts.json new file mode 100644 index 0000000..1816ecb --- /dev/null +++ b/tests/data/test_jsonrpcwallet/test_account_creation-30-get_accounts.json @@ -0,0 +1,26 @@ +{ + "id": 0, + "jsonrpc": "2.0", + "result": { + "subaddress_accounts": [ + { + "account_index": 0, + "balance": 0, + "base_address": "53NTw2x2eJH3KCrcgWAMErZb7mqN57wkVTEjRkkUUXoWCrAd513JErRFT1AC9RvEddgpxoZTVXYJG9Jez4w9x6qd5s76wdu", + "label": "Primary account", + "tag": "", + "unlocked_balance": 0 + }, + { + "account_index": 1, + "balance": 0, + "base_address": "75oMNpEDZNZhe9zBuKP4i6RpknDzAzM7t64Kq6nToUsJZms13tUucewKfZpdaQ9sNVYiMhiDyZbZR7MxbTCjq7D8N9CCo5k", + "label": "account 1", + "tag": "", + "unlocked_balance": 0 + } + ], + "total_balance": 0, + "total_unlocked_balance": 0 + } +} diff --git a/tests/test_jsonrpcwallet.py b/tests/test_jsonrpcwallet.py index 96ff7f7..db9a54b 100644 --- a/tests/test_jsonrpcwallet.py +++ b/tests/test_jsonrpcwallet.py @@ -139,6 +139,32 @@ class JSONRPCWalletTestCase(JSONTestCase): self.assertEqual(a0addr.label, 'Primary account') self.assertEqual(len(self.wallet.accounts[0].addresses()), 8) + @responses.activate + def test_account_creation(self): + responses.add(responses.POST, self.jsonrpc_url, + json=self._read('test_account_creation-00-get_accounts.json'), + status=200) + responses.add(responses.POST, self.jsonrpc_url, + json=self._read('test_account_creation-10-create_account.json'), + status=200) + responses.add(responses.POST, self.jsonrpc_url, + json=self._read('test_account_creation-20-getbalance.json'), + status=200) + responses.add(responses.POST, self.jsonrpc_url, + json=self._read('test_account_creation-30-get_accounts.json'), + status=200) + w = Wallet(JSONRPCWallet()) + self.assertEqual(1, len(w.accounts)) + w.new_account('account 1') + self.assertEqual(2, len(w.accounts)) + self.assertEqual('account 1', w.accounts[1].label) + self.assertEqual(0, w.accounts[1].balance()) + acc0, acc1 = w.accounts + w.refresh() + self.assertEqual(2, len(w.accounts)) + self.assertEqual('account 1', w.accounts[1].label) + self.assertEqual([acc0, acc1], w.accounts) + @patch('monero.backends.jsonrpc.requests.post') def test_incoming_confirmed(self, mock_post): mock_post.return_value.status_code = 200